From 73cdb347bc7ea8ed714bc4c01006935fefe72c41 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Wed, 24 Mar 2021 13:53:11 +0100 Subject: [PATCH 01/15] =?UTF-8?q?=F0=9F=9B=A0=20Fix=20the=20username=20use?= =?UTF-8?q?d=20error=20when=20creating=20from=20console?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Users/Controller/Adapters/Console/ApplyUpdates.php | 6 ++++++ twake/backend/core/src/Twake/Users/Services/User.php | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php index c08e1cc055..98fad748fb 100755 --- a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console/ApplyUpdates.php @@ -132,11 +132,15 @@ function updateUser($userDTO){ $ok = true; } }else{ + $usernameUsedError = false; $ok = true; } $counter++; } while (!$ok && $counter < 1000); if($mailUsedError || $usernameUsedError){ + error_log("Console user not created because mail exists or username exists:"); + error_log("Username used " . $username . ": " . ( $usernameUsedError ? "true" : "false" ) ); + error_log("Email used " . $email . ": " . ( $mailUsedError ? "true" : "false" ) ); return false; } @@ -196,6 +200,8 @@ function updateUser($userDTO){ } } + error_log("Created console user in Twake with success, id: " . $user->getId()); + return $user; } diff --git a/twake/backend/core/src/Twake/Users/Services/User.php b/twake/backend/core/src/Twake/Users/Services/User.php index 1315c228c5..3840c80b2d 100755 --- a/twake/backend/core/src/Twake/Users/Services/User.php +++ b/twake/backend/core/src/Twake/Users/Services/User.php @@ -122,6 +122,7 @@ public function loginFromServiceWithToken($service_id, $external_id, $email, $us $original_username = $username; $ok = false; $mailUsedError = false; + $usernameUsedError = false; do { $res = $this->getAvaibleMailPseudo($email, $username); if ($res !== true) { @@ -133,15 +134,18 @@ public function loginFromServiceWithToken($service_id, $external_id, $email, $us if (in_array(-2, $res)) { //Username used $username = $original_username . $counter; + $usernameUsedError = false; }else{ + $usernameUsedError = true; $ok = true; } }else{ + $usernameUsedError = false; $ok = true; } $counter++; } while (!$ok && $counter < 1000); - if($mailUsedError){ + if($mailUsedError || $usernameUsedError){ return false; } From 1d5b58b8773a817b8d37968530692ade30b639d4 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Tue, 23 Mar 2021 21:59:22 +0100 Subject: [PATCH 02/15] =?UTF-8?q?=F0=9F=9B=A0=20Fix=20direct=20channel=20c?= =?UTF-8?q?reation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/services/channels/web/controllers/channel.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/twake/backend/node/src/services/channels/web/controllers/channel.ts b/twake/backend/node/src/services/channels/web/controllers/channel.ts index f6b4e10f79..0d519c1f90 100644 --- a/twake/backend/node/src/services/channels/web/controllers/channel.ts +++ b/twake/backend/node/src/services/channels/web/controllers/channel.ts @@ -2,7 +2,7 @@ import { plainToClass } from "class-transformer"; import { FastifyReply, FastifyRequest } from "fastify"; import { Pagination } from "../../../../core/platform/framework/api/crud-service"; import { CrudController } from "../../../../core/platform/services/webserver/types"; -import { Channel, UserChannel } from "../../entities"; +import { Channel, ChannelMember, UserChannel } from "../../entities"; import { ChannelService, ChannelPrimaryKey, MemberService } from "../../provider"; import { getWebsocketInformation, getWorkspaceRooms } from "../../services/channel/realtime"; import { @@ -24,6 +24,7 @@ import { ResourceUpdateResponse, } from "../../../../services/types"; import { getLogger } from "../../../../core/platform/framework/logger"; +import _ from "lodash"; const logger = getLogger("channel.controller"); @@ -112,13 +113,14 @@ export class ChannelCrudController logger.debug("reqId: %s - save - Channel %s created", request.id, channelResult.entity.id); - const member = await this.membersService.get( - { + const member = await this.membersService.save( + _.assign(new ChannelMember(), { channel_id: channelResult.entity.id, workspace_id: channelResult.entity.workspace_id, company_id: channelResult.entity.company_id, user_id: context.user.id, - }, + }), + {}, getChannelExecutionContext(request, channelResult.entity), ); From 9b9be120f49ccce5cd00c172ae4d77473fa9e20a Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Tue, 23 Mar 2021 20:01:26 +0100 Subject: [PATCH 03/15] =?UTF-8?q?=F0=9F=90=B3=20Fix=20nginx=20docker-files?= =?UTF-8?q?=20(#1052)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- twake/docker/twake-nginx-php-only/Dockerfile | 3 +- .../docker/twake-nginx-php-only/entrypoint.sh | 9 +++ twake/docker/twake-nginx/Dockerfile | 1 + twake/docker/twake-nginx/entrypoint.sh | 2 +- twake/docker/twake-nginx/nginx.conf | 65 +++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 twake/docker/twake-nginx/nginx.conf diff --git a/twake/docker/twake-nginx-php-only/Dockerfile b/twake/docker/twake-nginx-php-only/Dockerfile index 8b639a1afb..ec856bcca4 100644 --- a/twake/docker/twake-nginx-php-only/Dockerfile +++ b/twake/docker/twake-nginx-php-only/Dockerfile @@ -3,8 +3,9 @@ FROM twaketech/nginx-static-yarn MAINTAINER Romaric Mourgues -ADD docker/twake-nginx-php-only/site.conf /etc/nginx/sites-enabled/site +ADD docker/twake-nginx/site.conf /etc/nginx/sites-available/site.template ADD docker/twake-nginx-php-only/nginx.conf /etc/nginx/nginx.conf +RUN apt-get update && apt-get install gettext-base RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf diff --git a/twake/docker/twake-nginx-php-only/entrypoint.sh b/twake/docker/twake-nginx-php-only/entrypoint.sh index 692f2fb750..08c8c49f12 100644 --- a/twake/docker/twake-nginx-php-only/entrypoint.sh +++ b/twake/docker/twake-nginx-php-only/entrypoint.sh @@ -1,4 +1,13 @@ #!/bin/bash +MOBILE_HOST="${MOBILE_HOST:-http://node:3000}" +NODE_HOST="${NODE_HOST:-http://node:3000}" +PHP_UPSTREAM="${PHP_UPSTREAM:-php:9000}" +export MOBILE_HOST +export NODE_HOST +export PHP_UPSTREAM +envsubst '$${MOBILE_HOST} $${NODE_HOST}' < /etc/nginx/sites-available/site.template > /etc/nginx/sites-enabled/site +echo "upstream php-upstream { server ${PHP_UPSTREAM}; }" > /etc/nginx/conf.d/upstream.conf + cron -f & nginx -g "daemon off;" diff --git a/twake/docker/twake-nginx/Dockerfile b/twake/docker/twake-nginx/Dockerfile index 5159ab41ca..8ef7ccc197 100644 --- a/twake/docker/twake-nginx/Dockerfile +++ b/twake/docker/twake-nginx/Dockerfile @@ -3,6 +3,7 @@ FROM twaketech/nginx-static-yarn MAINTAINER Romaric Mourgues ADD docker/twake-nginx/site.conf /etc/nginx/sites-available/site.template +ADD docker/twake-nginx-php-only/nginx.conf /etc/nginx/nginx.conf RUN apt-get update && apt-get install gettext-base RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf diff --git a/twake/docker/twake-nginx/entrypoint.sh b/twake/docker/twake-nginx/entrypoint.sh index 3e96378b64..b3ca4b0031 100644 --- a/twake/docker/twake-nginx/entrypoint.sh +++ b/twake/docker/twake-nginx/entrypoint.sh @@ -17,7 +17,7 @@ fi MOBILE_HOST="${MOBILE_HOST:-http://node:3000}" NODE_HOST="${NODE_HOST:-http://node:3000}" -PHP_UPSTREAM="${PHP_UPSTREAM:-php-upstream}" +PHP_UPSTREAM="${PHP_UPSTREAM:-php:9000}" export MOBILE_HOST export NODE_HOST export PHP_UPSTREAM diff --git a/twake/docker/twake-nginx/nginx.conf b/twake/docker/twake-nginx/nginx.conf new file mode 100644 index 0000000000..4e8010685a --- /dev/null +++ b/twake/docker/twake-nginx/nginx.conf @@ -0,0 +1,65 @@ +user www-data; +worker_processes 4; +pid /run/nginx.pid; + +events { + worker_connections 768; + # multi_accept on; +} + +http { + + client_max_body_size 200M; + + ## + # Basic Settings + ## + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + gzip_disable "msie6"; + + # gzip_vary on; + # gzip_proxied any; + # gzip_comp_level 6; + # gzip_buffers 16 8k; + # gzip_http_version 1.1; + # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + ## + # Virtual Host Configs + ## + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; +} From 7d1d268d39e4dd70a4ac9291bb61ccaa8153c57a Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Wed, 24 Mar 2021 18:39:46 +0100 Subject: [PATCH 04/15] =?UTF-8?q?=F0=9F=90=B3=20Fix=20max=20header=20size?= =?UTF-8?q?=20in=20node=20server?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- twake/backend/node/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/twake/backend/node/package.json b/twake/backend/node/package.json index 66913ff9b7..172260ca58 100644 --- a/twake/backend/node/package.json +++ b/twake/backend/node/package.json @@ -15,7 +15,7 @@ "lint": "eslint . --ext .ts --quiet --fix", "lint:no-fix": "eslint . --ext .ts", "lint:prettier": "prettier --config .prettierrc 'src/**/*.ts'", - "serve": "node dist/server.js", + "serve": "node --max-http-header-size=30000 dist/server.js", "serve:watch": "nodemon dist/server.js | pino-pretty", "serve:debug": "nodemon --inspect dist/server.js | pino-pretty", "start": "npm run serve", From db08d85f34ae95b239de05cbb16fce8e566a88d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Vieira?= <36481167+stephanevieira75@users.noreply.github.com> Date: Mon, 29 Mar 2021 17:33:57 +0200 Subject: [PATCH 05/15] =?UTF-8?q?=E2=AC=85=EF=B8=8F=20#360=20Fix=20Back=20?= =?UTF-8?q?/=20Next=20in=20browser=20(#1034)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #360 Create pushTo and replace functions and using them instead of history * #360 Fix Back / Next in Browser * #360 push instead of pushTo --- twake/frontend/src/app/app.tsx | 8 ++++---- twake/frontend/src/app/scenes/Apps/Drive/Drive.js | 2 +- .../ChannelsBar/Modals/WorkspaceChannelList.tsx | 2 +- .../WorkspaceChannelList/WorkspaceChannelRow.tsx | 2 +- .../ChannelsBar/Parts/Channel/ChannelMenu.tsx | 2 +- .../MainHeader/ChannelHeader/ChannelHeader.tsx | 2 +- .../Client/MainView/Tabs/DefaultChannelTab.tsx | 2 +- .../src/app/scenes/Client/MainView/Tabs/Tab.tsx | 2 +- .../src/app/scenes/Client/MainView/Tabs/Tabs.tsx | 2 +- twake/frontend/src/app/scenes/Error/Error.tsx | 2 +- .../src/app/scenes/Error/ErrorBoundary.tsx | 2 +- twake/frontend/src/app/scenes/Setup/Setup.tsx | 2 +- .../src/app/services/AppView/MainViewService.ts | 6 ++---- twake/frontend/src/app/services/InitService.ts | 9 +++------ twake/frontend/src/app/services/RouterService.ts | 8 ++++++++ .../app/services/channels/ChannelsBarService.ts | 2 +- .../frontend/src/app/services/channels/channels.js | 4 ++-- twake/frontend/src/app/services/login/login.js | 14 ++++++-------- .../src/app/services/user/notifications.tsx | 2 +- .../src/app/services/workspaces/workspaces.js | 4 ++-- 20 files changed, 40 insertions(+), 39 deletions(-) diff --git a/twake/frontend/src/app/app.tsx b/twake/frontend/src/app/app.tsx index 482803e270..2b3e6c402e 100755 --- a/twake/frontend/src/app/app.tsx +++ b/twake/frontend/src/app/app.tsx @@ -39,10 +39,10 @@ export default () => { { - RouterServices.history.replace( - RouterServices.pathnames.LOGIN + - '?auto&' + - RouterServices.history.location.search.substr(1), + RouterServices.replace( + `${ + RouterServices.pathnames.LOGIN + }?auto&${RouterServices.history.location.search.substr(1)}`, ); return
; }} diff --git a/twake/frontend/src/app/scenes/Apps/Drive/Drive.js b/twake/frontend/src/app/scenes/Apps/Drive/Drive.js index 3b2071c3a1..636b4cca26 100755 --- a/twake/frontend/src/app/scenes/Apps/Drive/Drive.js +++ b/twake/frontend/src/app/scenes/Apps/Drive/Drive.js @@ -314,7 +314,7 @@ export default class Drive extends Component { channelId: this.props.channel.id, directoryId: directory_id, }); - RouterServices.history.replace(url); + RouterServices.replace(url); */ } diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList.tsx index a037689109..4671d64e0e 100644 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList.tsx +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList.tsx @@ -76,7 +76,7 @@ export default () => { } ModalManager.closeAll(); - return RouterServices.history.push(`/client/${channel.data.workspace_id}/c/${channel.data.id}`); + return RouterServices.push(`/client/${channel.data.workspace_id}/c/${channel.data.id}`); }; const loadMore = () => { diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList/WorkspaceChannelRow.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList/WorkspaceChannelRow.tsx index 229ab840dd..42f57813c4 100644 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList/WorkspaceChannelRow.tsx +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/WorkspaceChannelList/WorkspaceChannelRow.tsx @@ -47,7 +47,7 @@ export default ({ channel, joined, active }: PropsType) => { } ModalManager.closeAll(); - return RouterServices.history.push(`/client/${workspaceId}/c/${channel.data.id}`); + return RouterServices.push(`/client/${workspaceId}/c/${channel.data.id}`); }; return ( diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/Channel/ChannelMenu.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/Channel/ChannelMenu.tsx index 5eb45d4563..7d8513985b 100644 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/Channel/ChannelMenu.tsx +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/Channel/ChannelMenu.tsx @@ -91,7 +91,7 @@ export default (props: Props): JSX.Element => { const redirectToWorkspace = () => { const url = RouterServices.generateRouteFromState({ workspaceId: workspaceId, channelId: '' }); - return RouterServices.history.push(url); + return RouterServices.push(url); }; const editChannel = () => { diff --git a/twake/frontend/src/app/scenes/Client/MainView/MainHeader/ChannelHeader/ChannelHeader.tsx b/twake/frontend/src/app/scenes/Client/MainView/MainHeader/ChannelHeader/ChannelHeader.tsx index 89c0d295a1..cef5e50451 100644 --- a/twake/frontend/src/app/scenes/Client/MainView/MainHeader/ChannelHeader/ChannelHeader.tsx +++ b/twake/frontend/src/app/scenes/Client/MainView/MainHeader/ChannelHeader/ChannelHeader.tsx @@ -26,7 +26,7 @@ export default (): JSX.Element => { workspaceId: workspaceId, channelId: '', }); - return RouterServices.history.push(url); + return RouterServices.push(url); }; const collectionPath: string = `/channels/v1/companies/${companyId}/workspaces/${workspaceId}/channels/${ diff --git a/twake/frontend/src/app/scenes/Client/MainView/Tabs/DefaultChannelTab.tsx b/twake/frontend/src/app/scenes/Client/MainView/Tabs/DefaultChannelTab.tsx index cb2b8b0830..7f7db6e706 100644 --- a/twake/frontend/src/app/scenes/Client/MainView/Tabs/DefaultChannelTab.tsx +++ b/twake/frontend/src/app/scenes/Client/MainView/Tabs/DefaultChannelTab.tsx @@ -61,7 +61,7 @@ export default ({ selected }: { selected: boolean }): JSX.Element => { const route: string = RouterServices.generateRouteFromState({ tabId: '', }); - return RouterServices.history.push(route); + return RouterServices.push(route); }} > diff --git a/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tab.tsx b/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tab.tsx index 64e205bc67..1f1a333095 100644 --- a/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tab.tsx +++ b/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tab.tsx @@ -54,7 +54,7 @@ export default ({ const route: string = RouterServices.generateRouteFromState({ tabId: tabResource.data.id, }); - return RouterServices.history.push(route); + return RouterServices.push(route); }} > {WorkspacesApps.getAppIconComponent(tabResource.data, { size: 14 })} diff --git a/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tabs.tsx b/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tabs.tsx index a751e933fb..5f0b1aa118 100644 --- a/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tabs.tsx +++ b/twake/frontend/src/app/scenes/Client/MainView/Tabs/Tabs.tsx @@ -31,7 +31,7 @@ export default (): JSX.Element => { const route: string = RouterServices.generateRouteFromState({ tabId: '', }); - RouterServices.history.push(route); + RouterServices.push(route); } return ( diff --git a/twake/frontend/src/app/scenes/Error/Error.tsx b/twake/frontend/src/app/scenes/Error/Error.tsx index 83c6eb8215..b4c5a4a773 100644 --- a/twake/frontend/src/app/scenes/Error/Error.tsx +++ b/twake/frontend/src/app/scenes/Error/Error.tsx @@ -16,7 +16,7 @@ export default () => { }, }; if (!RouterServices.useRedirection()) { - RouterServices.history.push('/'); + RouterServices.push('/'); } } return ( diff --git a/twake/frontend/src/app/scenes/Error/ErrorBoundary.tsx b/twake/frontend/src/app/scenes/Error/ErrorBoundary.tsx index 5c7b11f5f7..7c909e4a56 100755 --- a/twake/frontend/src/app/scenes/Error/ErrorBoundary.tsx +++ b/twake/frontend/src/app/scenes/Error/ErrorBoundary.tsx @@ -25,7 +25,7 @@ export default class ErrorBoundary extends React.Component<{}, { hasError: boole info: errorInfo.componentStack, }, }; - RouterServices.history.replace(RouterServices.addRedirection(RouterServices.pathnames.ERROR)); + RouterServices.replace(RouterServices.addRedirection(RouterServices.pathnames.ERROR)); } render() { diff --git a/twake/frontend/src/app/scenes/Setup/Setup.tsx b/twake/frontend/src/app/scenes/Setup/Setup.tsx index 5979873d42..1bf924fac8 100644 --- a/twake/frontend/src/app/scenes/Setup/Setup.tsx +++ b/twake/frontend/src/app/scenes/Setup/Setup.tsx @@ -16,7 +16,7 @@ export default function Setup() { if (ready === true) { if (!RouterServices.useRedirection()) { - RouterServices.history.push('/'); + RouterServices.push('/'); } return
; } diff --git a/twake/frontend/src/app/services/AppView/MainViewService.ts b/twake/frontend/src/app/services/AppView/MainViewService.ts index 135fefa15f..331c925624 100755 --- a/twake/frontend/src/app/services/AppView/MainViewService.ts +++ b/twake/frontend/src/app/services/AppView/MainViewService.ts @@ -14,10 +14,8 @@ class _MainViewService extends AppViewService { } public select(id: string, configuration?: ViewConfiguration) { - if (id != this.getId()) { - RouterService.history.push( - RouterService.generateRouteFromState({ channelId: id, tabId: '' }), - ); + if (RouterService.history.action !== 'POP' && id != this.getId()) { + RouterService.push(RouterService.generateRouteFromState({ channelId: id, tabId: '' })); } super.select(id, configuration); } diff --git a/twake/frontend/src/app/services/InitService.ts b/twake/frontend/src/app/services/InitService.ts index ff0fd82bcc..f8ff66687c 100644 --- a/twake/frontend/src/app/services/InitService.ts +++ b/twake/frontend/src/app/services/InitService.ts @@ -37,12 +37,9 @@ class InitService extends Observable { if (this.server_infos.ready !== true && this.server_infos.ready !== undefined) { //Server is not ready - RouterServices.history.replace( - RouterServices.addRedirection(RouterServices.pathnames.SETUP), - { - ...this.server_infos.ready, - }, - ); + RouterServices.replace(RouterServices.addRedirection(RouterServices.pathnames.SETUP), { + ...this.server_infos.ready, + }); this.app_ready = false; this.notify(); setTimeout(() => { diff --git a/twake/frontend/src/app/services/RouterService.ts b/twake/frontend/src/app/services/RouterService.ts index e1e5d81619..5bf3bd9554 100644 --- a/twake/frontend/src/app/services/RouterService.ts +++ b/twake/frontend/src/app/services/RouterService.ts @@ -257,6 +257,14 @@ class RouterServices extends Observable { } return false; } + + push(path: string, state?: unknown): void { + return this.history.push(path, state); + } + + replace(path: string, state?: unknown): void { + return this.history.replace(path, state); + } } export default new RouterServices(); diff --git a/twake/frontend/src/app/services/channels/ChannelsBarService.ts b/twake/frontend/src/app/services/channels/ChannelsBarService.ts index b6e513d3aa..6fc18bd613 100755 --- a/twake/frontend/src/app/services/channels/ChannelsBarService.ts +++ b/twake/frontend/src/app/services/channels/ChannelsBarService.ts @@ -39,7 +39,7 @@ class ChannelsBarService extends Observable { const channelId = localStorage.getItem(companyId + ':' + workspaceId + ':channel'); if (channelId) { this.updateCurrentChannelId(companyId, workspaceId, ''); - RouterService.history.push(RouterService.generateRouteFromState({ channelId: channelId })); + RouterService.push(RouterService.generateRouteFromState({ channelId: channelId })); } } } diff --git a/twake/frontend/src/app/services/channels/channels.js b/twake/frontend/src/app/services/channels/channels.js index 4021718284..f2a848c48a 100755 --- a/twake/frontend/src/app/services/channels/channels.js +++ b/twake/frontend/src/app/services/channels/channels.js @@ -79,7 +79,7 @@ class Channels extends Observable { } if (res) { - RouterService.history.push( + RouterService.push( RouterService.generateRouteFromState({ channelId: res.id, companyId: res.data.company_id, @@ -147,7 +147,7 @@ class Channels extends Observable { this.currentChannelFrontId = channel.front_id; this.currentChannelFrontIdByWorkspace[Workspaces.currentWorkspaceId] = channel.front_id; - RouterService.history.push(RouterService.generateRouteFromState({ channelId: channel.id })); + RouterService.push(RouterService.generateRouteFromState({ channelId: channel.id })); this.current_tab_id = this.current_tab_id_by_channel_id[channel.id] || null; diff --git a/twake/frontend/src/app/services/login/login.js b/twake/frontend/src/app/services/login/login.js index cd6beb6c27..bdcacbf888 100755 --- a/twake/frontend/src/app/services/login/login.js +++ b/twake/frontend/src/app/services/login/login.js @@ -210,11 +210,9 @@ class Login extends Observable { that.notify(); WindowState.setTitle(); - RouterServices.history.push( + RouterServices.push( RouterServices.addRedirection( - RouterServices.pathnames.LOGIN + - '?' + - RouterServices.history.location.search.substr(1), + `${RouterServices.pathnames.LOGIN}${RouterServices.history.location.search}`, ), ); } else { @@ -278,7 +276,7 @@ class Login extends Observable { } that.login_loading = false; that.init(); - return RouterServices.history.replace(RouterServices.pathnames.LOGIN); + return RouterServices.replace(RouterServices.pathnames.LOGIN); } else { that.login_error = true; that.login_loading = false; @@ -321,8 +319,8 @@ class Login extends Observable { if (!no_reload) { Globals.window.location.reload(); } else { - RouterServices.history.push( - RouterServices.pathnames.LOGIN + '?' + RouterServices.history.location.search.substr(1), + RouterServices.push( + `${RouterServices.pathnames.LOGIN}${RouterServices.history.location.search}`, ); } } @@ -355,7 +353,7 @@ class Login extends Observable { this.state = 'app'; this.notify(); - RouterServices.history.push(RouterServices.generateRouteFromState({})); + RouterServices.push(RouterServices.generateRouteFromState({})); Notifications.start(); CurrentUser.start(); diff --git a/twake/frontend/src/app/services/user/notifications.tsx b/twake/frontend/src/app/services/user/notifications.tsx index 97d74a567d..9c3c39e3e6 100755 --- a/twake/frontend/src/app/services/user/notifications.tsx +++ b/twake/frontend/src/app/services/user/notifications.tsx @@ -219,7 +219,7 @@ class Notifications extends Observable { )[0]?.id; } if (workspaceId) { - RouterService.history.push( + RouterService.push( RouterService.generateRouteFromState({ companyId: notificationObject.company_id, workspaceId: workspaceId, diff --git a/twake/frontend/src/app/services/workspaces/workspaces.js b/twake/frontend/src/app/services/workspaces/workspaces.js index e19a5913f8..d358e6ed1d 100755 --- a/twake/frontend/src/app/services/workspaces/workspaces.js +++ b/twake/frontend/src/app/services/workspaces/workspaces.js @@ -165,9 +165,9 @@ class Workspaces extends Observable { channelId: '', }); if (replace) { - RouterServices.history.replace(route); + RouterServices.replace(route); } else { - RouterServices.history.push(route); + RouterServices.push(route); } LocalStorage.setItem('autoload_workspaces', { id: workspace.id }); From ae112df2a0930b4b33997ef0cb44e55ba5bff6e5 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Wed, 31 Mar 2021 09:47:02 +0200 Subject: [PATCH 06/15] =?UTF-8?q?=F0=9F=9B=A4=20Tracker=20update=20&=20Mai?= =?UTF-8?q?n=20patch=20(#1067)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use console_id for tracker * Main patch 1 * Rename provider sub in jwt * Fix missing token orm save * Fix non mandatory type * Fix channel context user in it --- .../Twake/Calendar/Controller/Calendar.php | 4 +- .../src/Twake/Calendar/Controller/Event.php | 4 +- .../Discussion/Controller/Discussion.php | 2 +- .../src/Twake/Drive/Controller/Download.php | 2 +- .../src/Twake/Drive/Controller/DriveFile.php | 2 +- .../src/Twake/Drive/Controller/Upload.php | 4 +- .../core/src/Twake/Tasks/Controller/Board.php | 4 +- .../core/src/Twake/Tasks/Controller/Task.php | 6 +-- .../core/src/Twake/Users/Services/User.php | 8 ++- .../src/Twake/Workspaces/Entity/Group.php | 2 +- .../src/Twake/Workspaces/Entity/Workspace.php | 2 +- .../core/platform/services/auth/web/jwt.ts | 7 ++- .../core/platform/services/tracker/index.ts | 2 +- .../src/core/platform/services/types/index.ts | 1 + .../services/websocket/services/index.ts | 1 + .../channels/services/channel/service.ts | 25 ++++++++- .../channels/web/controllers/channel.ts | 3 +- .../backend/node/src/services/types/index.ts | 2 + .../Popup/AddUser/AddUserFromTwakeConsole.tsx | 7 +++ .../src/app/services/workspaces/workspaces.js | 53 ++++++++++++------- 20 files changed, 96 insertions(+), 45 deletions(-) diff --git a/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php b/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php index ac1217927e..0e1f969b0b 100755 --- a/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php +++ b/twake/backend/core/src/Twake/Calendar/Controller/Calendar.php @@ -31,7 +31,7 @@ public function save(Request $request) }else{ if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "calendar:".($object["id"] ? "edit" : "create"), - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } return new Response(Array("data" => Array("object" => $res))); @@ -46,7 +46,7 @@ public function getAction(Request $request) }else{ if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "calendar:open", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } diff --git a/twake/backend/core/src/Twake/Calendar/Controller/Event.php b/twake/backend/core/src/Twake/Calendar/Controller/Event.php index 269df60dfa..ab207fcc9f 100755 --- a/twake/backend/core/src/Twake/Calendar/Controller/Event.php +++ b/twake/backend/core/src/Twake/Calendar/Controller/Event.php @@ -20,7 +20,7 @@ public function remove(Request $request) } if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "calendar:event:remove", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); return new Response(Array("data" => Array("object" => $res))); } @@ -38,7 +38,7 @@ public function save(Request $request) } if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "calendar:event:".($object["id"] ? "edit" : "create"), - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } return new Response(Array("data" => Array("object" => $res))); diff --git a/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php b/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php index ec75b93323..bb0bd16a2e 100755 --- a/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php +++ b/twake/backend/core/src/Twake/Discussion/Controller/Discussion.php @@ -39,7 +39,7 @@ public function save(Request $request) $this->get("administration.counter")->incrementCounter("total_messages", 1); if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "message:send", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } } diff --git a/twake/backend/core/src/Twake/Drive/Controller/Download.php b/twake/backend/core/src/Twake/Drive/Controller/Download.php index 62ae59db95..53e73b3e28 100755 --- a/twake/backend/core/src/Twake/Drive/Controller/Download.php +++ b/twake/backend/core/src/Twake/Drive/Controller/Download.php @@ -39,7 +39,7 @@ public function downloadfile(Request $request) if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "drive:download", - "userId" => $this->isConnected() ? $this->getUser()->getId() : "anonymous" + "userId" => $this->isConnected() ? ($this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId()) : "anonymous" ]); @$response = $this->get('driveupload.download')->download($workspace_id, $files_ids, $download, $versionId); diff --git a/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php b/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php index cefdd57078..cfcba1903d 100755 --- a/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php +++ b/twake/backend/core/src/Twake/Drive/Controller/DriveFile.php @@ -48,7 +48,7 @@ public function save(Request $request) if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "drive:".($object["is_directory"] ? "directory" : "file") . ":" . ($object["id"] ? "edit" : "create"), - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); if (!empty($object["_once_set_access"]) && !empty($object["id"])) { diff --git a/twake/backend/core/src/Twake/Drive/Controller/Upload.php b/twake/backend/core/src/Twake/Drive/Controller/Upload.php index cd0d3dd78e..15c3028956 100755 --- a/twake/backend/core/src/Twake/Drive/Controller/Upload.php +++ b/twake/backend/core/src/Twake/Drive/Controller/Upload.php @@ -17,7 +17,7 @@ public function Preprocess(Request $request) if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "drive:file:create", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); return new Response(Array("identifier" => $identifier)); @@ -41,7 +41,7 @@ public function Preview(Request $request) if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "drive:preview", - "userId" => $this->isConnected() ? $this->getUser()->getId() : "anonymous" + "userId" => $this->isConnected() ? ($this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId()) : "anonymous" ]); $this->get('driveupload.previewmanager')->generatePreviewFromFolder($request); diff --git a/twake/backend/core/src/Twake/Tasks/Controller/Board.php b/twake/backend/core/src/Twake/Tasks/Controller/Board.php index 30dffe5c87..58fe102711 100755 --- a/twake/backend/core/src/Twake/Tasks/Controller/Board.php +++ b/twake/backend/core/src/Twake/Tasks/Controller/Board.php @@ -20,7 +20,7 @@ public function remove(Request $request) } if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "tasks:board:remove", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); return new Response(Array("data" => Array("object" => $res))); } @@ -35,7 +35,7 @@ public function save(Request $request) } if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "tasks:board:".($object["id"] ? "edit" : "create"), - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); return new Response(Array("data" => Array("object" => $res))); } diff --git a/twake/backend/core/src/Twake/Tasks/Controller/Task.php b/twake/backend/core/src/Twake/Tasks/Controller/Task.php index cb14484bd0..fa5f505fa5 100755 --- a/twake/backend/core/src/Twake/Tasks/Controller/Task.php +++ b/twake/backend/core/src/Twake/Tasks/Controller/Task.php @@ -20,7 +20,7 @@ public function remove(Request $request) }else{ if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "tasks:task:remove", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } return new Response(Array("data" => Array("object" => $res))); @@ -37,7 +37,7 @@ public function save(Request $request) } if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "tasks:task:".($object["id"] ? "edit" : "create"), - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); if (!$res) { @@ -55,7 +55,7 @@ public function getAction(Request $request) }else{ if($GLOBALS["segment_enabled"]) \Segment::track([ "event" => "tasks:task:get", - "userId" => $this->getUser()->getId() + "userId" => $this->getuser()->getIdentityProviderId() ?: $this->getUser()->getId() ]); } return new Response(Array("data" => $objects)); diff --git a/twake/backend/core/src/Twake/Users/Services/User.php b/twake/backend/core/src/Twake/Users/Services/User.php index 3840c80b2d..f77674c200 100755 --- a/twake/backend/core/src/Twake/Users/Services/User.php +++ b/twake/backend/core/src/Twake/Users/Services/User.php @@ -122,7 +122,6 @@ public function loginFromServiceWithToken($service_id, $external_id, $email, $us $original_username = $username; $ok = false; $mailUsedError = false; - $usernameUsedError = false; do { $res = $this->getAvaibleMailPseudo($email, $username); if ($res !== true) { @@ -134,18 +133,15 @@ public function loginFromServiceWithToken($service_id, $external_id, $email, $us if (in_array(-2, $res)) { //Username used $username = $original_username . $counter; - $usernameUsedError = false; }else{ - $usernameUsedError = true; $ok = true; } }else{ - $usernameUsedError = false; $ok = true; } $counter++; } while (!$ok && $counter < 1000); - if($mailUsedError || $usernameUsedError){ + if($mailUsedError){ return false; } @@ -784,6 +780,8 @@ public function addDevice($userId, $type, $value, $version = "?") } $newDevice = new Device($userId, $type, $value, $version); + $this->em->persist($newDevice); + $this->em->flush(); return true; diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Group.php b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php index e4241b3c8e..9789dd324e 100755 --- a/twake/backend/core/src/Twake/Workspaces/Entity/Group.php +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php @@ -62,7 +62,7 @@ class Group extends SearchableObject /** * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") - * @ORM\JoinColumn(name="logo") + * @ORM\JoinColumn(name="logo_id") */ protected $logoFile; diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php index d410034223..438a0f7957 100755 --- a/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php @@ -62,7 +62,7 @@ class Workspace extends SearchableObject /** * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") - * @ORM\JoinColumn(name="logo") + * @ORM\JoinColumn(name="logo_id") */ private $logoFile; diff --git a/twake/backend/node/src/core/platform/services/auth/web/jwt.ts b/twake/backend/node/src/core/platform/services/auth/web/jwt.ts index 98a71382e4..f4f42978ae 100644 --- a/twake/backend/node/src/core/platform/services/auth/web/jwt.ts +++ b/twake/backend/node/src/core/platform/services/auth/web/jwt.ts @@ -12,7 +12,12 @@ const jwtPlugin: FastifyPluginCallback = (fastify, _opts, next) => { fastify.decorate("authenticate", async (request: FastifyRequest) => { try { const jwt: JwtType = await request.jwtVerify(); - request.currentUser = { ...{ org: jwt.org }, ...{ email: jwt.email }, ...{ id: jwt.sub } }; + request.currentUser = { + ...{ org: jwt.org }, + ...{ email: jwt.email }, + ...{ id: jwt.sub }, + ...{ identity_provider_id: jwt.provider_id }, + }; request.log.debug(`Authenticated as user ${request.currentUser.id}`); } catch (err) { throw fastify.httpErrors.unauthorized("Bad credentials"); diff --git a/twake/backend/node/src/core/platform/services/tracker/index.ts b/twake/backend/node/src/core/platform/services/tracker/index.ts index 007275f7a6..f9a3c278c3 100644 --- a/twake/backend/node/src/core/platform/services/tracker/index.ts +++ b/twake/backend/node/src/core/platform/services/tracker/index.ts @@ -16,7 +16,7 @@ export default class Tracker extends TwakeService implements Tracker localEventBus.subscribe(channelListEvent, data => { logger.debug(`Tracker - New ${channelListEvent} event`); this.identify({ - userId: data.user.id, + userId: data.user.identity_provider_id || data.user.id, traits: { email: data.user.email || "", company: { diff --git a/twake/backend/node/src/core/platform/services/types/index.ts b/twake/backend/node/src/core/platform/services/types/index.ts index c44775d76f..47a25ff6af 100644 --- a/twake/backend/node/src/core/platform/services/types/index.ts +++ b/twake/backend/node/src/core/platform/services/types/index.ts @@ -1,5 +1,6 @@ export type JwtType = { sub: string; + provider_id: string; //Console sub email: string; nbf: number; refresh_nbf: number; diff --git a/twake/backend/node/src/core/platform/services/websocket/services/index.ts b/twake/backend/node/src/core/platform/services/websocket/services/index.ts index 5544961401..48d7b43afd 100644 --- a/twake/backend/node/src/core/platform/services/websocket/services/index.ts +++ b/twake/backend/node/src/core/platform/services/websocket/services/index.ts @@ -61,6 +61,7 @@ export class WebSocketService extends EventEmitter implements WebSocketAPI { getUser(socket: WebSocket): WebSocketUser { return { id: socket.decoded_token.sub, + identity_provider_id: socket.decoded_token.provider_id, email: socket.decoded_token.email, org: socket.decoded_token.org, token: socket.decoded_token, diff --git a/twake/backend/node/src/services/channels/services/channel/service.ts b/twake/backend/node/src/services/channels/services/channel/service.ts index 045122ebab..a98c6cb735 100644 --- a/twake/backend/node/src/services/channels/services/channel/service.ts +++ b/twake/backend/node/src/services/channels/services/channel/service.ts @@ -195,11 +195,14 @@ export class Service implements ChannelService { if (existingChannel) { const last_activity = await this.getChannelActivity(existingChannel); - return new SaveResult( + const saveResult = new SaveResult( "channels", ChannelObject.mapTo(existingChannel, { last_activity }), OperationType.EXISTS, ); + await this.addContextUserToChannel(context, saveResult); + + return saveResult; } else { //Fixme: remove directChannel instance throw CrudExeption.badRequest("table inconsistency"); @@ -223,6 +226,7 @@ export class Service implements ChannelService { mode, ); + await this.addContextUserToChannel(context, saveResult); await this.onSaved(channelToSave, options, context, saveResult, mode); return saveResult; @@ -549,6 +553,24 @@ export class Service implements ChannelService { return channel.owner && String(channel.owner) === user.id; } + async addContextUserToChannel( + context: WorkspaceExecutionContext, + result: SaveResult, + ): Promise { + const savedChannel = result.entity; + + //Add requester as member + if (context.user.id) { + try { + await this.channelService.members.addUserToChannels({ id: context.user.id }, [ + savedChannel, + ]); + } catch (err) { + logger.warn({ err }, "Can not add requester as channel member"); + } + } + } + /** * Called when channel update has been successfully called * @@ -584,6 +606,7 @@ export class Service implements ChannelService { } } } + localEventBus.publish("channel:created", { channel }); } } diff --git a/twake/backend/node/src/services/channels/web/controllers/channel.ts b/twake/backend/node/src/services/channels/web/controllers/channel.ts index 0d519c1f90..c50ece8478 100644 --- a/twake/backend/node/src/services/channels/web/controllers/channel.ts +++ b/twake/backend/node/src/services/channels/web/controllers/channel.ts @@ -113,14 +113,13 @@ export class ChannelCrudController logger.debug("reqId: %s - save - Channel %s created", request.id, channelResult.entity.id); - const member = await this.membersService.save( + const member = await this.membersService.get( _.assign(new ChannelMember(), { channel_id: channelResult.entity.id, workspace_id: channelResult.entity.workspace_id, company_id: channelResult.entity.company_id, user_id: context.user.id, }), - {}, getChannelExecutionContext(request, channelResult.entity), ); diff --git a/twake/backend/node/src/services/types/index.ts b/twake/backend/node/src/services/types/index.ts index bd4e386946..18d719eb17 100644 --- a/twake/backend/node/src/services/types/index.ts +++ b/twake/backend/node/src/services/types/index.ts @@ -40,6 +40,8 @@ export const webSocketSchema = { export interface User { // unique user id id: uuid; + // unique console user id + identity_provider_id?: uuid; // user email email?: string; // Organisation properties diff --git a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx index 4e6943dce2..de16adffe0 100644 --- a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx +++ b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx @@ -24,6 +24,13 @@ const AddUserFromTwakeConsole = (props: PropsType) => { const onChange = (e: React.ChangeEvent) => setEmails(e.target.value); const onClickBtn = async () => { + if (props.onChange) props.onChange(emails); + + if (props.finish) { + props.finish(); + return; + } + setLoading(true); setDisabled(true); diff --git a/twake/frontend/src/app/services/workspaces/workspaces.js b/twake/frontend/src/app/services/workspaces/workspaces.js index d358e6ed1d..d5e45cedc8 100755 --- a/twake/frontend/src/app/services/workspaces/workspaces.js +++ b/twake/frontend/src/app/services/workspaces/workspaces.js @@ -6,13 +6,10 @@ import User from 'services/user/user.js'; import Api from 'services/Api'; import ws from 'services/websocket.js'; import DepreciatedCollections from 'app/services/Depreciated/Collections/Collections.js'; -import Collections from 'app/services/CollectionsReact/Collections'; -import { ChannelResource } from 'app/models/Channel'; import Groups from 'services/workspaces/groups.js'; import LocalStorage from 'services/localStorage.js'; import workspacesUsers from './workspaces_users.js'; import WindowService from 'services/utils/window.js'; -import Languages from 'services/languages/languages.js'; import workspacesApps from 'services/workspaces/workspaces_apps.js'; import RouterServices from 'app/services/RouterService'; import WelcomePage from 'scenes/Client/Popup/WelcomePage/WelcomePage'; @@ -20,9 +17,10 @@ import Notifications from 'services/user/notifications'; import $ from 'jquery'; import AccessRightsService from 'services/AccessRightsService'; import loginService from 'services/login/login.js'; - +import InitService from 'app/services/InitService'; import Globals from 'services/Globals.js'; import JWTStorage from 'services/JWTStorage'; +import ConsoleService from 'services/ConsoleService'; class Workspaces extends Observable { constructor() { @@ -254,21 +252,38 @@ class Workspaces extends Observable { workspace = res.data.workspace; if (wsMembers.length > 0) { - var data = { - workspaceId: res.data.workspace.id, - list: wsMembers.join(','), - asExterne: false, - }; - - Api.post('workspace/members/addlist', data, () => { - that.loading = false; - popupManager.close(); - if (workspace) { - that.select(workspace); - } else { - that.notify(); - } - }); + if (InitService.server_infos?.auth?.console?.use) { + //Invite using console + ConsoleService.addMailsInWorkspace({ + workspace_id: res.data.workspace.id || '', + company_id: res.data.workspace.group.id || '', + wsMembers, + }).finally(() => { + that.loading = false; + popupManager.close(); + if (workspace) { + that.select(workspace); + } else { + that.notify(); + } + }); + } else { + var data = { + workspaceId: res.data.workspace.id, + list: wsMembers.join(','), + asExterne: false, + }; + + Api.post('workspace/members/addlist', data, () => { + that.loading = false; + popupManager.close(); + if (workspace) { + that.select(workspace); + } else { + that.notify(); + } + }); + } } else { that.loading = false; popupManager.close(); From 4611392ead82fb384178a992b154bb3f77ae0d69 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Fri, 2 Apr 2021 17:19:03 +0200 Subject: [PATCH 07/15] =?UTF-8?q?=F0=9F=9B=A0=20Multiple=20fixes=20(#1095)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix email verification links in templates * Fix #1086 * Fix #1088 * Fix #1091 * Disable user search on whole Twake user base Fix #1070 --- .../Mail/de/inviteToWorkspaceMail.html.twig | 4 ++-- .../Mail/de/messages_notifications.html.twig | 2 +- .../views/Mail/de/subscribeMail.html.twig | 2 +- .../Mail/de/unread_notifications.html.twig | 2 +- .../Mail/en/inviteToWorkspaceMail.html.twig | 4 ++-- .../Mail/en/messages_notifications.html.twig | 2 +- .../views/Mail/en/subscribeMail.html.twig | 2 +- .../Mail/en/unread_notifications.html.twig | 2 +- .../Mail/fr/inviteToWorkspaceMail.html.twig | 4 ++-- .../Mail/fr/messages_notifications.html.twig | 2 +- .../views/Mail/fr/subscribeMail.html.twig | 2 +- .../Mail/fr/unread_notifications.html.twig | 2 +- .../Mail/ru/inviteToWorkspaceMail.html.twig | 4 ++-- .../Mail/ru/messages_notifications.html.twig | 2 +- .../views/Mail/ru/subscribeMail.html.twig | 2 +- .../Mail/ru/unread_notifications.html.twig | 2 +- .../src/Twake/Core/Services/TwakeMailer.php | 2 ++ .../Users/Controller/UsersConnections.php | 2 +- .../core/src/Twake/Users/Services/User.php | 2 +- .../core/src/Twake/Users/Services/Users.php | 23 +++++++++++++++---- .../PopupComponent/PopupComponent.scss | 15 ++++++++++++ .../Calendar/FullCalendar/FullCalendar.js | 2 ++ .../src/app/scenes/Apps/Drive/Drive.js | 2 ++ .../ChannelsBar/Modals/SearchListManager.ts | 1 + .../app/services/Apps/Calendar/Calendar.js | 2 -- 25 files changed, 62 insertions(+), 29 deletions(-) diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig index a69f289e02..b43fd46dba 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/inviteToWorkspaceMail.html.twig @@ -14,12 +14,12 @@
- Dem Arbeitsbereich beitreten
-
{{ twakeurl|trim('/') }}/login?subscribe=1&mail={{ mail }} +
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }}

diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig index 0aab8d799d..ff38131a33 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/messages_notifications.html.twig @@ -24,7 +24,7 @@ {% endfor %}
- Öffne Twake + Öffne Twake
{% endblock %} \ No newline at end of file diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig index f070f96941..e760069721 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/de/subscribeMail.html.twig @@ -11,7 +11,7 @@ Um Ihr Konto einzurichten, sie können auf diesen Link klicken :
{{ twakeurl|trim('/') }}{{ magic_link }} + href="{{ twakeappurl|trim('/') }}{{ magic_link }}">{{ twakeappurl|trim('/') }}{{ magic_link }}

Durch Klicken auf diesen Link erklären Sie sich mit den
-
Öffne Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig index 58cbc73b96..6c4e9a6398 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/inviteToWorkspaceMail.html.twig @@ -14,12 +14,12 @@
- Join workspace now !
-
{{ twakeurl|trim('/') }}/login?subscribe=1&mail={{ mail }} +
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }}

diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig index 93cc48368b..97dc3c96f1 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/messages_notifications.html.twig @@ -24,7 +24,7 @@

- Ouvrir Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig index 3731e30c8a..0e95860733 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/subscribeMail.html.twig @@ -11,7 +11,7 @@ In order to create your account, you can click on this link :
{{ twakeurl|trim('/') }}{{ magic_link }} + href="{{ twakeappurl|trim('/') }}{{ magic_link }}">{{ twakeappurl|trim('/') }}{{ magic_link }}

By clicking on this link you agree to the terms diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig index df397dc258..2c4924dafb 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/en/unread_notifications.html.twig @@ -23,7 +23,7 @@

-
Open Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig index 9ce3787bc8..84b776f69a 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/inviteToWorkspaceMail.html.twig @@ -14,12 +14,12 @@
- Rejoindre l'espace de travail
-
{{ twakeurl|trim('/') }}/login?subscribe=1&mail={{ mail }} +
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }}

diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig index 86430f6eb6..60ca99ff02 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/messages_notifications.html.twig @@ -25,7 +25,7 @@

- Ouvrir Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig index dacafea9dd..81cedb3fd9 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/subscribeMail.html.twig @@ -11,7 +11,7 @@ Pour terminer votre inscription, cliquez sur ce lien :
{{ twakeurl|trim('/') }}{{ magic_link }} + href="{{ twakeappurl|trim('/') }}{{ magic_link }}">{{ twakeappurl|trim('/') }}{{ magic_link }}

En cliquant sur ce lien, vous acceptez les condition d'utilisation de Twake. diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig index cddd1f1963..86f89db060 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/fr/unread_notifications.html.twig @@ -24,7 +24,7 @@

- Ouvrir Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig index 57a434b289..ca169e1e29 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/inviteToWorkspaceMail.html.twig @@ -14,12 +14,12 @@
- Присоединиться к рабочему пространству сейчас !
-
{{ twakeurl|trim('/') }}/login?subscribe=1&mail={{ mail }} +
{{ twakeappurl|trim('/') }}/login?subscribe&mail={{ mail }}

diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig index 50b43a496a..6379e99882 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/messages_notifications.html.twig @@ -24,7 +24,7 @@

- Открыть Twake diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig index eca35710f7..7a1792b941 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/subscribeMail.html.twig @@ -11,7 +11,7 @@ Для того, чтобы создать свой аккаунт, вы можете нажать на эту ссылку:
{{ twakeurl|trim('/') }}{{ magic_link }} + href="{{ twakeappurl|trim('/') }}{{ magic_link }}">{{ twakeappurl|trim('/') }}{{ magic_link }}

Перейдя по этой ссылке, вы соглашаетесь с условиями diff --git a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig index 95d5db7e29..acb7cc3466 100755 --- a/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig +++ b/twake/backend/core/src/Twake/Core/Resources/views/Mail/ru/unread_notifications.html.twig @@ -23,7 +23,7 @@

-
Открыть Twake diff --git a/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php index 55ce61805b..a2352141ee 100755 --- a/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php +++ b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php @@ -78,6 +78,8 @@ public function sendInternal($mail, $template, $data = Array(), $attachments = A $data["twakeaddress"] = $this->mail_parameters["twake_address"]; $data["twakeurl"] = $this->mail_parameters["twake_domain_url"]; + $data["twakeappurl"] = $this->app->getContainer()->getParameter("frontend_server_name", $this->app->getContainer()->getParameter("server_name", $data["twakeurl"])); + $language = "en"; if (isset($data["_language"])) { $language = $data["_language"]; diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php index 20134879b6..d7c463c774 100755 --- a/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php +++ b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php @@ -106,7 +106,7 @@ public function isLogged(Request $request) $forename = $request->query->get("forename", ""); $mail = $request->query->get("mail", ""); $username = $request->query->get("username", ""); - $url = "https://app.twakeapp.com/login?subscribe=1&origin=" . $origin; + $url = "https://app.twakeapp.com/login?subscribe&origin=" . $origin; if ($username && $username != "") { $url = $url . "&username=" . $username; } diff --git a/twake/backend/core/src/Twake/Users/Services/User.php b/twake/backend/core/src/Twake/Users/Services/User.php index f77674c200..baa4cfc426 100755 --- a/twake/backend/core/src/Twake/Users/Services/User.php +++ b/twake/backend/core/src/Twake/Users/Services/User.php @@ -538,7 +538,7 @@ public function subscribeMail($mail, $pseudo, $password, $name, $firstname, $pho if(!$auto_validate_mail){ - $magic_link = "/login?verifyMail=1&m=" . $mail . "&c=" . $code . "&token=" . $verificationNumberMail->getToken(); + $magic_link = "/login?verifyMail&m=" . $mail . "&c=" . $code . "&token=" . $verificationNumberMail->getToken(); if (!defined("TESTENV")) { error_log("sign in code: " . $magic_link); diff --git a/twake/backend/core/src/Twake/Users/Services/Users.php b/twake/backend/core/src/Twake/Users/Services/Users.php index 570bbc8172..0259b944db 100755 --- a/twake/backend/core/src/Twake/Users/Services/Users.php +++ b/twake/backend/core/src/Twake/Users/Services/Users.php @@ -33,7 +33,8 @@ public function searchWithDB($options = Array(), $entity = false) $name = $options["name"]; $scope = $options["scope"] ?: "all"; - + if($scope !== "group" || $scope !== "workspace") $scope = "group"; + $usersArray = []; $usersEntities = []; @@ -72,10 +73,21 @@ public function searchWithDB($options = Array(), $entity = false) foreach($users as $user){ if($user){ - //TODO execute search filter - - $usersArray[] = [$user->getAsArray(), 0]; - $usersEntities[] = [$user, 0]; + $match = false; + foreach($user->getAsArray() as $key => $value){ + if(in_array($key, ["username", "firstname", "lastname", "email"])){ + foreach(explode(" ", $name) as $word){ + if(strpos(strtolower($value), strtolower($word)) !== false){ + $match = true; + } + } + } + } + + if($match){ + $usersArray[] = [$user->getAsArray(), 0]; + $usersEntities[] = [$user, 0]; + } } } @@ -95,6 +107,7 @@ public function searchWithES($options = Array(), $entity = false) $name = $options["name"]; $scope = $options["scope"] ?: "all"; + if($scope !== "group" || $scope !== "workspace") $scope = "group"; $workspace_id = $options["workspace_id"]; $group_id = $options["group_id"]; diff --git a/twake/frontend/src/app/components/PopupComponent/PopupComponent.scss b/twake/frontend/src/app/components/PopupComponent/PopupComponent.scss index cc666f7808..cf9241bdd7 100755 --- a/twake/frontend/src/app/components/PopupComponent/PopupComponent.scss +++ b/twake/frontend/src/app/components/PopupComponent/PopupComponent.scss @@ -44,4 +44,19 @@ transform: translateX(-50%) translateY(-50%); } } + + @media only screen and (max-width: 600px) { + .header { + .close { + right: auto; + left: 16px; + } + } + .main .content { + margin-left: 0px !important; + } + .main .sideBar { + display: none; + } + } } diff --git a/twake/frontend/src/app/scenes/Apps/Calendar/FullCalendar/FullCalendar.js b/twake/frontend/src/app/scenes/Apps/Calendar/FullCalendar/FullCalendar.js index 97f2d25472..512569df3a 100755 --- a/twake/frontend/src/app/scenes/Apps/Calendar/FullCalendar/FullCalendar.js +++ b/twake/frontend/src/app/scenes/Apps/Calendar/FullCalendar/FullCalendar.js @@ -73,6 +73,8 @@ export default class FullCalendar extends Component { return true; }, select: function (event) { + that.cancelClickOut = true; + //Create event if (moment(event.end).diff(event.start) == 15 * 60 * 1000) { that.api.unselect(); diff --git a/twake/frontend/src/app/scenes/Apps/Drive/Drive.js b/twake/frontend/src/app/scenes/Apps/Drive/Drive.js index 636b4cca26..6605fff145 100755 --- a/twake/frontend/src/app/scenes/Apps/Drive/Drive.js +++ b/twake/frontend/src/app/scenes/Apps/Drive/Drive.js @@ -828,6 +828,8 @@ export default class Drive extends Component { data={files} view_mode={DriveService.view_mode} /> + +
)} diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/SearchListManager.ts b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/SearchListManager.ts index b89384343c..13a83cb199 100644 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/SearchListManager.ts +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Modals/SearchListManager.ts @@ -94,6 +94,7 @@ class SearchListManager { UsersService.search( Strings.removeAccents(text), { + scope: 'group', group_id: Workspaces.currentGroupId, }, (res: UserType[]) => users.push(...res.filter((el: UserType) => !!el)), diff --git a/twake/frontend/src/app/services/Apps/Calendar/Calendar.js b/twake/frontend/src/app/services/Apps/Calendar/Calendar.js index c2f76d1e53..3d6ad88130 100755 --- a/twake/frontend/src/app/services/Apps/Calendar/Calendar.js +++ b/twake/frontend/src/app/services/Apps/Calendar/Calendar.js @@ -127,8 +127,6 @@ class Calendar extends Observable { } closePopups() { - console.log('close'); - //console.trace(); this.preview = null; if (this.edited) { Collections.get('events').cancelEdit(this.edited); From 46f9117fb115d627659e85b2734c16af79ebfb45 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Tue, 6 Apr 2021 16:00:13 +0200 Subject: [PATCH 08/15] =?UTF-8?q?=F0=9F=8E=AE=20Console=20login=20issues?= =?UTF-8?q?=20update=20(#1106)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix Console state not working with php sessions * Display login error if exists * Fix docker-compose for on-premise quick installations * Add ability to remove a document in connectors --- .../Common/Services/MainConnectorService.php | 13 ++- .../src/Twake/Core/Services/TwakeMailer.php | 2 +- .../Users/Controller/Adapters/Console.php | 24 ++++-- .../Users/Controller/Adapters/OpenID.php | 1 + .../Adapters/OpenID/OpenIDConnectClient.php | 85 +++++++++---------- twake/docker-compose.yml.onpremise | 63 ++++++++++++++ .../src/app/scenes/Login/Error/Error.scss | 33 +++++++ .../src/app/scenes/Login/Error/Error.tsx | 35 ++++++++ twake/frontend/src/app/scenes/Login/login.tsx | 2 + .../frontend/src/app/services/login/login.js | 14 +++ twake/start.sh | 2 +- 11 files changed, 219 insertions(+), 55 deletions(-) create mode 100644 twake/docker-compose.yml.onpremise create mode 100644 twake/frontend/src/app/scenes/Login/Error/Error.scss create mode 100755 twake/frontend/src/app/scenes/Login/Error/Error.tsx diff --git a/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php b/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php index a9d4e99e39..b854ea0523 100755 --- a/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php +++ b/twake/backend/core/src/BuiltInConnectors/Common/Services/MainConnectorService.php @@ -139,12 +139,21 @@ public function saveDocument($id, $content){ return false; } $document = new BuiltInConnectorsEntity($cred["api_id"], $id); - $document->setValue($content); - $this->doctrine->persist($document); + if($content === null){ + $this->doctrine->remove($document); + }else{ + $document->setValue($content); + $this->doctrine->persist($document); + } $this->doctrine->flush(); return true; } + /** Remove connector document from db */ + public function removeDocument($id){ + return $this->saveDocument($id, null); + } + /** Get connector document from db */ public function getDocument($id){ $cred = $this->getConnectorKeys(); diff --git a/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php index a2352141ee..7886247e57 100755 --- a/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php +++ b/twake/backend/core/src/Twake/Core/Services/TwakeMailer.php @@ -78,7 +78,7 @@ public function sendInternal($mail, $template, $data = Array(), $attachments = A $data["twakeaddress"] = $this->mail_parameters["twake_address"]; $data["twakeurl"] = $this->mail_parameters["twake_domain_url"]; - $data["twakeappurl"] = $this->app->getContainer()->getParameter("frontend_server_name", $this->app->getContainer()->getParameter("server_name", $data["twakeurl"])); + $data["twakeappurl"] = $this->app->getContainer()->getParameter("env.frontend_server_name", $this->app->getContainer()->getParameter("env.server_name", $data["twakeurl"])); $language = "en"; if (isset($data["_language"])) { diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php index b4aca8d5a6..bc5e10782f 100755 --- a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php @@ -37,7 +37,7 @@ function logoutSuccess(Request $request) $message = "success"; } - return $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "/login"); + return $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "/login" . "?error_code=".str_replace('+', '%20', urlencode(json_encode($message)))); } function logout(Request $request, $message = null) @@ -98,6 +98,7 @@ function index(Request $request) $this->getParameter("defaults.auth.console.openid.client_id"), $this->getParameter("defaults.auth.console.openid.client_secret") ); + $oidc->setServerKey($this->app->getContainer()->getParameter("jwt.secret")); $oidc->setCodeChallengeMethod($this->getParameter("defaults.auth.console.openid.provider_config.code_challenge_methods_supported", [""])[0]); $oidc->providerConfigParam($this->getParameter("defaults.auth.console.openid.provider_config", [])); @@ -121,19 +122,26 @@ function index(Request $request) $response = $this->app->getServices()->get("app.restclient")->get($url, array(CURLOPT_HTTPHEADER => [$header])); $response = json_decode($response->getContent(), 1); - /** @var User $user */ - $user = (new ApplyUpdates($this->app))->updateUser($response); + try { - $userTokens = null; - if($user){ - $userTokens = $this->get("app.user")->loginWithIdOnlyWithToken($user->getId()); + /** @var User $user */ + $user = (new ApplyUpdates($this->app))->updateUser($response); + + $userTokens = null; + if($user){ + $userTokens = $this->get("app.user")->loginWithIdOnlyWithToken($user->getId()); + } + + } catch (\Exception $e) { + error_log($e); + $this->logout($request, ["error" => "Unknown error while creating/getting account"]); } if ($userTokens) { return $this->redirect(rtrim($this->getParameter("env.server_name"), "/") . "/ajax/users/console/redirect_to_app?token=" . urlencode($userTokens["token"]) . "&username=" . urlencode($userTokens["username"]) ); }else{ - return $this->logout($request, ["error" => "No user profile created"]); + return $this->logout($request, ["error" => "No user profile created: is your email already used in Twake?"]); } }else{ @@ -142,7 +150,7 @@ function index(Request $request) } catch (\Exception $e) { error_log($e); - $this->logout($request); + $this->logout($request, ["error" => "Unknown error while processing OIDC login"]); } return $this->logout($request, ["error" => "An unknown error occurred"]); diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php index 52706c3551..fd1ee589ff 100755 --- a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID.php @@ -61,6 +61,7 @@ function index(Request $request) $this->getParameter("defaults.auth.openid.client_id"), $this->getParameter("defaults.auth.openid.client_secret") ); + $oidc->setServerKey($this->app->getContainer()->getParameter("jwt.secret")); $oidc->providerConfigParam($this->getParameter("defaults.auth.openid.provider_config", [])); diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php index 3d1111aa4e..2bc877e9d5 100755 --- a/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/OpenID/OpenIDConnectClient.php @@ -1,30 +1,12 @@ - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. You may obtain - * a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - */ - namespace Twake\Users\Controller\Adapters\OpenID; +use \Firebase\JWT\JWT; + /** * * JWT signature verification support by Jonathan Reed + * Edited by Romaric Mourgues to make it stateless and compatible with LemonLDAP * Licensed under the same license as the rest of this file. * * phpseclib is required to validate the signatures of some tokens. @@ -237,6 +219,19 @@ class OpenIDConnectClient */ private $pkceAlgs = array('S256' => 'sha256', 'plain' => false); + /** + * Server key, used to generate stateless OIDC state + */ + private $serverKey = ""; + + public function setServerKey($key){ + $this->serverKey = $key; + } + + private function getServerKey(){ + return $this->serverKey; + } + /** * @param $provider_url string optional * @@ -308,13 +303,10 @@ public function authenticate($options = []) { } // Do an OpenID Connect session check - if ($_REQUEST['state'] !== $this->getState($_REQUEST['state']) && !$options["ignore_state"]) { + if (!$this->checkState($_REQUEST['state']) && !$options["ignore_state"]) { throw new OpenIDConnectClientException('Unable to determine state'); } - // Cleanup state - $this->unsetState($_REQUEST['state']); - if (!property_exists($token_json, 'id_token')) { throw new OpenIDConnectClientException('User did not authorize openid scope.'); } @@ -374,13 +366,10 @@ public function authenticate($options = []) { } // Do an OpenID Connect session check - if ($_REQUEST['state'] !== $this->getState($_REQUEST['state'])) { + if ($_REQUEST['state'] !== $this->checkState($_REQUEST['state'])) { throw new OpenIDConnectClientException('Unable to determine state'); } - // Cleanup state - $this->unsetState($_REQUEST['state']); - $claims = $this->decodeJWT($id_token, 1); // Verify the signature @@ -643,7 +632,7 @@ private function requestAuthorization() { $nonce = $this->setNonce($this->generateRandString()); // State essentially acts as a session key for OIDC - $state = $this->setState($this->generateRandString()); + $state = $this->genState(); $auth_params = array_merge($this->authParams, array( 'response_type' => $response_type, @@ -1607,9 +1596,17 @@ protected function unsetNonce() { * @param string $state * @return string */ - protected function setState($state) { - $this->setSessionKey('openid_connect_state_' . $state, $state); - return $state; + protected function genState() { + //Generate a state using jwt + $payload = [ + "token" => $this->generateRandString(), + "exp" => date("U") + 5 * 60 + ]; + + $key = $this->getServerKey(); + $jwt = JWT::encode($payload, $key); + + return $jwt; } /** @@ -1617,17 +1614,19 @@ protected function setState($state) { * * @return string */ - protected function getState($stateId = "") { - return $this->getSessionKey('openid_connect_state_' . $stateId); - } + protected function checkState($state = "") { + $key = $this->getServerKey(); - /** - * Cleanup state - * - * @return void - */ - protected function unsetState($stateId = "") { - $this->unsetSessionKey('openid_connect_state_' . $stateId); + try{ + //Check state is valid and non expired + $jwt = JWT::decode($state, $key, array('HS256')); + + if($jwt->exp > date("U")){ + return true; + } + }catch(\Exception $e){} + + return false; } /** diff --git a/twake/docker-compose.yml.onpremise b/twake/docker-compose.yml.onpremise new file mode 100644 index 0000000000..af4abc49a9 --- /dev/null +++ b/twake/docker-compose.yml.onpremise @@ -0,0 +1,63 @@ +version: "3.4" + +services: + scylladb: + image: scylladb/scylla:4.1.0 + command: --smp 1 --memory 1G + ports: + - 9042:9042 + volumes: + - ./docker-data/scylladb:/var/lib/scylla + + rabbitmq: + image: library/rabbitmq:3.8.9-management-alpine + ports: + - 15672:15672 + environment: + RABBITMQ_DEFAULT_USER: admin + RABBITMQ_DEFAULT_PASS: admin + + node: + image: twaketech/twake-node:latest + environment: + - NODE_ENV=production + volumes: + - ./configuration/backend-node/production.json:/usr/src/app/config/production.json + depends_on: + - scylladb + - rabbitmq + links: + - scylladb + + php: + image: twaketech/twake-php:latest + environment: + - DEV=production + volumes: + - ./docker-data/drive/:/twake-core/drive/ + - ./docker-data/fpm/:/etc/docker-data/fpm/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ + depends_on: + - scylladb + - rabbitmq + links: + - scylladb + + nginx: + image: twaketech/twake-nginx:latest + environment: + - DEV=production + ports: + - 8000:80 + depends_on: + - php + - node + volumes_from: + - php + - node + volumes: + - ./docker-data/logs/nginx/:/var/log/nginx + - ./docker-data/letsencrypt/:/etc/letsencrypt/ + - ./docker-data/drive-preview/:/twake-core/web/medias/ + - ./docker-data/uploads/:/twake-core/web/upload/ diff --git a/twake/frontend/src/app/scenes/Login/Error/Error.scss b/twake/frontend/src/app/scenes/Login/Error/Error.scss new file mode 100644 index 0000000000..301bbb98fe --- /dev/null +++ b/twake/frontend/src/app/scenes/Login/Error/Error.scss @@ -0,0 +1,33 @@ +.full_page_error_login { + display: inline-flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100vh; + + .error_message { + z-index: 100; + text-align: center; + width: 600px; + padding: 40px; + margin: auto; + + .title { + font-size: 40px; + .emojione { + margin-right: 5px; + width: 64px; + height: 64px; + bottom: 8px; + } + } + .subtitle { + text-align: center; + line-height: 25px; + margin: auto; + margin-top: 30px; + margin-bottom: 16px; + max-width: 500px; + } + } +} diff --git a/twake/frontend/src/app/scenes/Login/Error/Error.tsx b/twake/frontend/src/app/scenes/Login/Error/Error.tsx new file mode 100755 index 0000000000..229958b78e --- /dev/null +++ b/twake/frontend/src/app/scenes/Login/Error/Error.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import Languages from 'services/languages/languages'; +import Emojione from 'components/Emojione/Emojione'; +import './Error.scss'; +import { Button } from 'antd'; +import LoginService from 'services/login/login.js'; + +export default () => { + return ( +
+
+
+ {' '} + {Languages.t('scenes.login_error', [], 'There was an error while logging you into Twake')} +
+
{LoginService.parsed_error_code}
+ + {LoginService.error_code} + +
+
+
+ + +
+
+ ); +}; diff --git a/twake/frontend/src/app/scenes/Login/login.tsx b/twake/frontend/src/app/scenes/Login/login.tsx index 17f06adbc1..a6b861de97 100755 --- a/twake/frontend/src/app/scenes/Login/login.tsx +++ b/twake/frontend/src/app/scenes/Login/login.tsx @@ -12,6 +12,7 @@ import LoginView from './LoginView/LoginView.js'; import Signin from './Signin/Signin.js'; import VerifyMail from './VerifyMail/VerifyMail.js'; import ForgotPassword from './ForgotPassword/ForgotPassword.js'; +import Error from './Error/Error'; export default () => { LoginService.useListener(useState); @@ -37,6 +38,7 @@ export default () => { )} + {LoginService.state == 'error' && } {LoginService.state == 'logged_out' && } {LoginService.state == 'signin' && } {LoginService.state == 'verify_mail' && } diff --git a/twake/frontend/src/app/services/login/login.js b/twake/frontend/src/app/services/login/login.js index bdcacbf888..8e993a0cfb 100755 --- a/twake/frontend/src/app/services/login/login.js +++ b/twake/frontend/src/app/services/login/login.js @@ -74,6 +74,20 @@ class Login extends Observable { } }); + var error_code = WindowState.findGetParameter('error_code') ? true : false; + if (error_code) { + this.firstInit = true; + this.setPage('error'); + this.error_code = WindowState.findGetParameter('error_code') || ''; + try { + this.parsed_error_code = JSON.parse(WindowState.findGetParameter('error_code')).error; + } catch (e) { + this.parsed_error_code = 'Unable to parse error.'; + } + this.notify(); + return; + } + var subscribe = WindowState.findGetParameter('subscribe') !== undefined ? WindowState.findGetParameter('subscribe') === true diff --git a/twake/start.sh b/twake/start.sh index bae98aa1fd..b377c195a2 100755 --- a/twake/start.sh +++ b/twake/start.sh @@ -1,4 +1,4 @@ -cp -n docker-compose.yml.dist docker-compose.yml +cp -n docker-compose.yml.onpremise docker-compose.yml cp -nR default-configuration/ configuration/ docker-compose pull From fd3e9edf067b397df09ec9241857006226e1f679 Mon Sep 17 00:00:00 2001 From: RkAiman <64081690+RkAiman@users.noreply.github.com> Date: Mon, 12 Apr 2021 15:48:02 +0200 Subject: [PATCH 09/15] =?UTF-8?q?=F0=9F=9B=8E=20Refacto=20the=20notificati?= =?UTF-8?q?ons=20form=20(#938)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refacto the notifications form * Add the feedback message manager --- .../src/app/models/NotificationPreferences.ts | 26 ++ .../CompanyHeader/CompanyHeader.js | 76 +--- .../CompanyHeader/CompanyHeader.scss | 5 + .../Parts/CurrentUser/CurrentUser.js | 147 -------- .../Notifications/NotificationBell.tsx | 76 ++++ .../Notifications/NotificationDelay.tsx | 24 ++ .../UserParameter/Pages/Notifications.js | 325 ------------------ .../UserParameter/Pages/Notifications.tsx | 285 +++++++++++++++ .../Popup/UserParameter/UserParameter.js | 2 +- .../FeedbackMessageManager.ts | 23 ++ .../src/app/services/languages/locale/de.js | 2 +- .../src/app/services/languages/locale/en.js | 7 +- .../src/app/services/languages/locale/fr.js | 7 +- .../src/app/services/languages/locale/ru.js | 2 +- .../services/user/notificationParameters.ts | 148 ++++++++ .../src/app/services/user/notifications.tsx | 2 + 16 files changed, 608 insertions(+), 549 deletions(-) create mode 100644 twake/frontend/src/app/models/NotificationPreferences.ts create mode 100644 twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationBell.tsx create mode 100644 twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationDelay.tsx delete mode 100755 twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.js create mode 100755 twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.tsx create mode 100644 twake/frontend/src/app/services/FeedbackMessageManager/FeedbackMessageManager.ts create mode 100644 twake/frontend/src/app/services/user/notificationParameters.ts diff --git a/twake/frontend/src/app/models/NotificationPreferences.ts b/twake/frontend/src/app/models/NotificationPreferences.ts new file mode 100644 index 0000000000..21d30f7f33 --- /dev/null +++ b/twake/frontend/src/app/models/NotificationPreferences.ts @@ -0,0 +1,26 @@ +import { Resource } from 'services/CollectionsReact/Collections'; + +export type preferencesType = { + highlight_words: string[], + night_break: { + enable: boolean, + from: number, + to: number, + }, + private_message_content: boolean, + mobile_notifications: string, + email_notifications_delay: number, + deactivate_notifications_until: number, + notification_sound: string, +} +export type NotificationPreferencesType = { + user_id: string, + company_id: string, + workspace_id: string, + preferences: preferencesType, +} + +export class NotificationPreferencesResource extends Resource { + _type = 'notification_preferences'; + _resourcePrimaryKey = ["user_id", "company_id", "workspace_id"]; +} diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.js b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.js index 7d5a4f5638..4a53cb78a7 100755 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.js +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.js @@ -1,20 +1,18 @@ -import React, { Component } from 'react'; +import React from 'react'; import './CompanyHeader.scss'; -import User from 'components/User/User.js'; import UserService from 'services/user/user.js'; import Icon from 'components/Icon/Icon.js'; import Emojione from 'components/Emojione/Emojione'; +import NotificationDelay from '../Notifications/NotificationDelay'; export default class CompanyHeader extends React.Component { - constructor(props) { + constructor() { super(); } render() { var user = this.props.user || {}; - var notifications_disabled = this.props.notificationsDisabled; - var status = this.props.status; return (
- {/*
*/} - {!!(user.status_icon || [])[0] && } @@ -45,68 +35,10 @@ export default class CompanyHeader extends React.Component {
-
-
{ - evt.stopPropagation(); - evt.preventDefault(); - this.props.onClickBell && this.props.onClickBell(evt); - }} - > - -
-
-
- ); - - /* - return ( -
this.props.onClickUser && this.props.onClickUser(evt)} - style={this.props.style || {}} - > -
- -
-
-
-
{UserService.getFullName(user)}
-
- -
-
-
-
- {user.status_icon && } -
-
{'@' + user.username}
-
{ - evt.stopPropagation(); - evt.preventDefault(); - this.props.onClickBell && this.props.onClickBell(evt); - }} - > - -
-
+
); - */ } } diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.scss b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.scss index 861128ba1e..c7f2759cb7 100755 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.scss +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CompanyHeader/CompanyHeader.scss @@ -28,6 +28,11 @@ color: var(--warning); } } + + .remaning-time { + color: grey; + font-style: italic; + } } .current-company { diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CurrentUser.js b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CurrentUser.js index e0217a3c92..7d5aebf64e 100755 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CurrentUser.js +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/CurrentUser.js @@ -308,151 +308,7 @@ export default class CurrentUser extends Component { 'bottom', ); } - onClickBell(evt) { - var current_user = this.state.users_repository.known_objects_by_id[this.user_id]; - - this.dont_disturb = NotificationParameters.transform_period( - UserService.getCurrentUser().notifications_preferences.dont_disturb_between, - UserService.getCurrentUser().notifications_preferences.dont_disturb_and, - -new Date().getTimezoneOffset() / 60, - ); - this.notifications_state = NotificationParameters.getNotificationsStatus(current_user); - this.notifications_menu = [ - { - type: 'menu', - hide: true, //Disabled until refactor - text: Languages.t( - 'scenes.app.channelsbar.currentuser.user_parameter', - [], - 'Paramètres de notification', - ), - onClick: () => { - popupManager.open(, true, true); - }, - }, - { - type: 'menu', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.disabling_notifications', - [], - 'Désactiver pendant 1h', - ), - onClick: () => { - NotificationParameters.saveElements( - { disable_until: parseInt(new Date().getTime() / 1000 + 60 * 60) }, - true, - ); - }, - }, - { - type: 'menu', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.disabling_notifications_until', - [], - "Désactiver jusqu'à demain 9h", - ), - onClick: () => { - var a = new Date(); - a.setDate(new Date().getDate() + 1); - a.setHours(9); - a.setMinutes(0); - a = parseInt(a.getTime() / 1000); - NotificationParameters.saveElements({ disable_until: a }, true); - }, - }, - ]; - - if (this.notifications_state != 'off') { - this.notifications_menu.push({ - type: 'menu', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.disable_notifications', - [], - 'Désactiver', - ), - onClick: () => { - NotificationParameters.saveElements( - { disable_until: parseInt(new Date().getTime() / 1000 + 60 * 60 * 24 * 10000) }, - true, - ); - }, - }); - } - - if (this.notifications_state != 'on') { - this.notifications_menu.push({ - type: 'menu', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.reactivate_notifications', - [], - 'Réactiver', - ), - onClick: () => { - NotificationParameters.saveElements({ disable_until: 0 }, true); - }, - }); - - var disabled_until = new Date( - UserService.getCurrentUser().notifications_preferences.disable_until * 1000, - ); - - if (this.notifications_state == 'off') { - this.notifications_menu.push({ - type: 'text', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.desactivated_notifications_message', - [], - 'Vos notifications sont désactivées.', - ), - }); - } else if (NotificationParameters.is_in_period(this.dont_disturb[0], this.dont_disturb[1])) { - var a = this.dont_disturb[0]; - var b = this.dont_disturb[1]; - a = Math.floor(a) + 'h' + ((a - Math.floor(a)) * 60 || '00'); - b = Math.floor(b) + 'h' + ((b - Math.floor(b)) * 60 || '00'); - this.notifications_menu.push({ - type: 'text', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.desactivated_notifiations_information', - [a, b], - "Vos notifications sont désactivées la nuit de $1 jusqu'à $2.", - ), - }); - } else if ( - UserService.getCurrentUser().notifications_preferences.disable_until < - new Date().getTime() / 1000 + 60 * 60 * 11 - ) { - this.notifications_menu.push({ - type: 'text', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.desactivated_notifiations_information_until', - [disabled_until.getHours(), disabled_until.getMinutes()], - "Vos notifications sont désactivées jusqu'à $1:$2.", - ), - }); - } else { - this.notifications_menu.push({ - type: 'text', - text: Languages.t( - 'scenes.app.channelsbar.currentuser.desactivated_notifiations_information_no_choice', - [], - "Vos notifications sont désactivées jusqu'à demain 9h.", - ), - }); - } - } - - var pos = window.getBoundingClientRect(this.bell_node); - pos.x = pos.x || pos.left; - pos.y = pos.y || pos.top; - - MenusManager.openMenu( - this.notifications_menu, - { x: pos.x + pos.width - 5, y: pos.y + pos.height + 10 }, - 'bottom', - ); - } render() { var current_user = this.state.users_repository.known_objects_by_id[this.user_id]; @@ -483,9 +339,6 @@ export default class CurrentUser extends Component { onClickUser={evt => { this.onClickUser(evt); }} - onClickBell={evt => { - this.onClickBell(evt); - }} style={{ marginBottom: 10 }} /> ); diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationBell.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationBell.tsx new file mode 100644 index 0000000000..b2fb4024ed --- /dev/null +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationBell.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import moment from 'moment'; + +import Menu from 'components/Menus/Menu'; +import Icon from 'components/Icon/Icon.js'; + +import Languages from 'services/languages/languages.js'; +import NotificationParametersService from 'services/user/notificationParameters'; + +type PropsType = { + preferences: any; +}; + +export default (props: PropsType) => { + const status = NotificationParametersService.areNotificationsAllowed(); + + const tomorrowMorning = moment().add(1, 'd').hour(9).minute(0).second(0); + const hoursUntilTomorrowMorning = moment + .duration(tomorrowMorning.diff(moment(new Date()))) + .asHours(); + + const notifications_menu = [ + { + type: 'menu', + hide: true, //Disabled until refactor + text: Languages.t('scenes.app.channelsbar.currentuser.user_parameter'), + onClick: () => {}, + }, + { + type: 'menu', + text: Languages.t('scenes.app.channelsbar.currentuser.disabling_notifications'), + onClick: () => NotificationParametersService.deactivateNotificationsUntil(1, 'h'), + }, + { + type: 'menu', + text: '2 hours', // Add translation + onClick: () => NotificationParametersService.deactivateNotificationsUntil(2, 'h'), + }, + { + type: 'menu', + text: Languages.t('scenes.app.channelsbar.currentuser.disabling_notifications_until'), + onClick: () => + NotificationParametersService.deactivateNotificationsUntil(hoursUntilTomorrowMorning, 'h'), + }, + { + type: 'menu', + text: Languages.t( + status + ? 'scenes.app.channelsbar.currentuser.disable_notifications' + : 'scenes.app.channelsbar.currentuser.reactivate_notifications', + ), + onClick: () => { + status + ? NotificationParametersService.deactivateNotificationsUntil(24, 'y') + : NotificationParametersService.deactivateNotificationsUntil(0, 's'); + }, + }, + { + // TODO: Calculate the real value + hide: true, + type: 'text', + text: '35 minutes remaning', // Vos notifications sont désactivées jusqu'à hh:mm + className: 'remaning-time', + }, + ]; + + return ( + +
+
+ +
+
+
+ ); +}; diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationDelay.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationDelay.tsx new file mode 100644 index 0000000000..4518080390 --- /dev/null +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/Parts/CurrentUser/Notifications/NotificationDelay.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import _ from 'lodash'; + +import NotificationParametersService from 'services/user/notificationParameters'; +import NotificationBell from './NotificationBell'; + +import { Collection } from 'services/CollectionsReact/Collections'; +import { NotificationPreferencesResource } from 'app/models/NotificationPreferences'; + +export default () => { + // const preferences = NotificationParametersService.useWatcher( + // () => NotificationParametersService.notificationPreferences, + // ); + + const url = '/notifications/v1/preferences/'; + const notificationPreferencesCollection = Collection.get(url, NotificationPreferencesResource); + const notificationPreferences = notificationPreferencesCollection.useWatcher({}); + + return _.isEmpty(notificationPreferences) ? ( + <> + ) : ( + + ); +}; diff --git a/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.js b/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.js deleted file mode 100755 index b51013ba96..0000000000 --- a/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.js +++ /dev/null @@ -1,325 +0,0 @@ -import React, { Component } from 'react'; - -import Languages from 'services/languages/languages.js'; -import currentUserService from 'services/user/current_user.js'; -import ButtonWithTimeout from 'components/Buttons/ButtonWithTimeout.js'; -import Attribute from 'components/Parameters/Attribute.js'; -import NotificationParameters from 'services/user/notification_parameters.js'; -import Switch from 'components/Inputs/Switch.js'; -import Radio from 'components/Inputs/Radio.js'; -import AutoHeight from 'components/AutoHeight/AutoHeight.js'; - -export default class Notifications extends Component { - constructor() { - super(); - this.state = { - i18n: Languages, - notifications_parameters: NotificationParameters, - }; - Languages.addListener(this); - NotificationParameters.addListener(this); - NotificationParameters.init(); - } - componentWillUnmount() { - Languages.removeListener(this); - NotificationParameters.removeListener(this); - } - render() { - return ( -
-
{this.state.i18n.t('scenes.apps.account.notifications.title')}
- -
-
- {Languages.t( - 'scenes.app.popup.userparameter.pages.frequency_notif_subtitle', - [], - 'Fréquence des notifications', - )} -
- - -
- { - NotificationParameters.preferences.dont_use_keywords = checked ? 1 : 0; - NotificationParameters.notify(); - }} - /> - - {!this.state.notifications_parameters.preferences.dont_use_keywords ? ( - -
- {this.state.i18n.t( - 'scenes.apps.account.notifications.keywords_activated_text', - currentUserService.get().username, - )} -
- { - NotificationParameters.preferences.keywords = evt.target.value; - NotificationParameters.notify(); - }} - > - {this.state.notifications_parameters.preferences.keywords} - -
- ) : ( - - )} - - NotificationParameters.save(['keywords', 'dont_use_keywords'])} - value={this.state.i18n.t('general.update')} - /> -
-
- - -
-
- {this.state.i18n.t('scenes.apps.account.notifications.disturb_option_a')} - - {this.state.i18n.t('scenes.apps.account.notifications.disturb_option_b')} - - {this.state.i18n.t('scenes.apps.account.notifications.disturb_option_c')} -
- - - NotificationParameters.save(['dont_disturb_and', 'dont_disturb_between']) - } - value={this.state.i18n.t('general.update')} - /> -
-
- - -
- { - NotificationParameters.preferences.devices = 0; - NotificationParameters.notify(); - }} - /> -
- - { - NotificationParameters.preferences.devices = 1; - NotificationParameters.notify(); - }} - /> -
- - { - NotificationParameters.preferences.devices = 3; - NotificationParameters.notify(); - }} - /> - - NotificationParameters.save(['devices'])} - value={this.state.i18n.t('general.update')} - /> -
-
- - -
- { - NotificationParameters.preferences.mail_notifications = 2; - NotificationParameters.notify(); - }} - /> -
- - { - NotificationParameters.preferences.mail_notifications = 1; - NotificationParameters.notify(); - }} - /> -
- - { - NotificationParameters.preferences.mail_notifications = 0; - NotificationParameters.notify(); - }} - /> - - NotificationParameters.save(['mail_notifications'])} - value={this.state.i18n.t('general.update')} - /> -
-
-
- -
-
- {this.state.i18n.t('scenes.apps.account.notifications.privacy_subtitle')} -
- - -
- { - NotificationParameters.preferences.privacy = checked ? 1 : 0; - NotificationParameters.notify(); - }} - /> - NotificationParameters.save(['privacy'])} - value={this.state.i18n.t('general.update')} - /> -
-
-
-
- ); - } -} diff --git a/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.tsx b/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.tsx new file mode 100755 index 0000000000..a6bfbb3f61 --- /dev/null +++ b/twake/frontend/src/app/scenes/Client/Popup/UserParameter/Pages/Notifications.tsx @@ -0,0 +1,285 @@ +import React, { useState, useRef } from 'react'; +import { Input } from 'antd'; +import _ from 'lodash'; + +import Languages from 'services/languages/languages.js'; +import NotificationParameters from 'services/user/notification_parameters.js'; +import { Collection } from 'services/CollectionsReact/Collections'; +import NotificationParametersService from 'services/user/notificationParameters'; + +import ButtonWithTimeout from 'components/Buttons/ButtonWithTimeout.js'; +import Attribute from 'components/Parameters/Attribute.js'; +import Switch from 'components/Inputs/Switch.js'; +import Radio from 'components/Inputs/Radio.js'; + +import { + preferencesType, + NotificationPreferencesResource, +} from 'app/models/NotificationPreferences'; + +export default () => { + const loading = useRef(true); + const url = '/notifications/v1/preferences/'; + const notificationPreferencesCollection = Collection.get(url, NotificationPreferencesResource); + const notificationPreferences = notificationPreferencesCollection.useWatcher({}); + + const [newPreferences, setNewPreferences] = useState(); + + if (loading.current && !!notificationPreferences && notificationPreferences.length) { + setNewPreferences(notificationPreferences[0].data.preferences); + loading.current = false; + } + + const saveNewPreferences = async (preferences: preferencesType) => { + const newPreferences: any = Object.entries(preferences).map(([key, value]) => ({ key, value })); + + NotificationParametersService.save(newPreferences); + }; + + const generateTimeOptions = () => { + const options = []; + for (let value = 0; value < 24; value += 0.5) { + const text = ~~value + ':' + ((value * 2) % 2 == 0 ? '00' : '30'); + options.push( + , + ); + } + return options; + }; + + if (!newPreferences) { + return
; + } + + return ( + <> +
{Languages.t('scenes.apps.account.notifications.title')}
+
+
+ {Languages.t('scenes.app.popup.userparameter.pages.frequency_notif_subtitle')} +
+ +
+ ) => { + setNewPreferences({ + ...newPreferences, + highlight_words: evt.target.value.split(', '), + }); + }} + > +
+
+ +
+ { + setNewPreferences({ + ...newPreferences, + night_break: { + ...newPreferences.night_break, + enable: checked, + }, + }); + }} + /> +
+
+ {Languages.t('scenes.apps.account.notifications.disturb_option_a')} + + {Languages.t('scenes.apps.account.notifications.disturb_option_b')} + + {Languages.t('scenes.apps.account.notifications.disturb_option_c')} +
+
+
+
+ +
+ { + setNewPreferences({ + ...newPreferences, + mobile_notifications: 'always', + }); + }} + /> +
+ + { + setNewPreferences({ + ...newPreferences, + mobile_notifications: 'when_inactive', + }); + }} + /> +
+ + { + setNewPreferences({ + ...newPreferences, + mobile_notifications: 'never', + }); + }} + /> +
+
+ +
+ {/* TODO: Add an explanatory message */} + { + setNewPreferences({ + ...newPreferences, + email_notifications_delay: evt.target.value, + }); + }} + /> +
+
+ {/* TODO: Add DE and RU traduction and implement the feature */} + +
+
+
+ {Languages.t('scenes.apps.account.notifications.privacy_subtitle')} +
+ + { + setNewPreferences({ + ...newPreferences, + private_message_content: checked, + }); + }} + /> + +
+
+ saveNewPreferences(newPreferences)} + value={Languages.t('general.update')} + /> +
+ + ); +}; diff --git a/twake/frontend/src/app/scenes/Client/Popup/UserParameter/UserParameter.js b/twake/frontend/src/app/scenes/Client/Popup/UserParameter/UserParameter.js index 8be4e6f593..1e285865dc 100755 --- a/twake/frontend/src/app/scenes/Client/Popup/UserParameter/UserParameter.js +++ b/twake/frontend/src/app/scenes/Client/Popup/UserParameter/UserParameter.js @@ -10,7 +10,7 @@ import currentUserService from 'services/user/current_user.js'; import uploadService from 'services/uploadManager/uploadManager.js'; import ButtonWithTimeout from 'components/Buttons/ButtonWithTimeout.js'; import Attribute from 'components/Parameters/Attribute.js'; -import Notifications from './Pages/Notifications.js'; +import Notifications from './Pages/Notifications'; import MenuList from 'components/Menus/MenuComponent.js'; import './UserParameter.scss'; import Input from 'components/Inputs/Input.js'; diff --git a/twake/frontend/src/app/services/FeedbackMessageManager/FeedbackMessageManager.ts b/twake/frontend/src/app/services/FeedbackMessageManager/FeedbackMessageManager.ts new file mode 100644 index 0000000000..cca8f08a31 --- /dev/null +++ b/twake/frontend/src/app/services/FeedbackMessageManager/FeedbackMessageManager.ts @@ -0,0 +1,23 @@ +import { message } from 'antd'; + +class FeedbackMessage { + success(content:string, duration:number, onClose?:any) { + message.success(content, duration, onClose) + } + error(content:string, duration:number, onClose?:any) { + message.error(content, duration, onClose) + } + info(content:string, duration:number, onClose?:any) { + message.info(content, duration, onClose) + } + warning(content:string, duration:number, onClose?:any) { + message.warning(content, duration, onClose) + } + loading(content:string, duration:number, onClose?:any) { + message.loading(content, duration, onClose) + } +} + +const feedbackMessage = new FeedbackMessage(); +export default feedbackMessage; + diff --git a/twake/frontend/src/app/services/languages/locale/de.js b/twake/frontend/src/app/services/languages/locale/de.js index 39f01835e6..d5c0f9896d 100755 --- a/twake/frontend/src/app/services/languages/locale/de.js +++ b/twake/frontend/src/app/services/languages/locale/de.js @@ -1396,7 +1396,7 @@ export default { 'scenes.app.popup.userparameter.pages.frequency_notif_subtitle': 'Häufigkeit der Benachrichtigungen', 'scenes.app.popup.userparameter.pages.keywords_notif_description': - 'Erhalten Sie nur Benachrichtigungen, die bestimmten Keywords entsprechen.', + 'Markieren Sie die folgenden Schlüsselwörter:', 'scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description': 'Legen Sie die Häufigkeit der E-Mail-Benachrichtigungen fest.', 'scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description': diff --git a/twake/frontend/src/app/services/languages/locale/en.js b/twake/frontend/src/app/services/languages/locale/en.js index a8eb59047b..13832bf5e4 100755 --- a/twake/frontend/src/app/services/languages/locale/en.js +++ b/twake/frontend/src/app/services/languages/locale/en.js @@ -662,6 +662,7 @@ export default { 'scenes.apps.account.notifications.mail_option_ever': 'Send me all the notification emails', 'scenes.apps.account.notifications.mail_option_daily': 'Just send me a daily report', 'scenes.apps.account.notifications.mail_option_never': 'Never send e-mail notifications', + 'scenes.apps.account.notifications.sound': 'Sound notification', 'scenes.apps.account.workspaces.workspace_name': 'Workspace name', 'scenes.apps.account.workspaces.members_number': 'Number of members', 'scenes.apps.account.workspaces.favorite_workspace': 'Favorite workspaces', @@ -1367,9 +1368,13 @@ export default { 'Set the frequency of mobile notifications.', 'scenes.app.popup.userparameter.pages.frequency_notif_subtitle': 'Frenquency of notifications', 'scenes.app.popup.userparameter.pages.keywords_notif_description': - 'Receive only notifications that match certain keywords.', + 'Highlight the following keywords:', 'scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description': 'Set the frequency of email notifications.', + 'scenes.app.popup.userparameter.pages.private_message_content.show': + 'Show private messages content', + 'scenes.app.popup.userparameter.pages.private_message_content.hide': + 'Hide private messages content', 'scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description': 'Choose a period during which you do not receive notifications.', 'scenes.app.popup.userparameter.pages.no_night_disturbing_label': 'Do not disturb at night', diff --git a/twake/frontend/src/app/services/languages/locale/fr.js b/twake/frontend/src/app/services/languages/locale/fr.js index d811becd5d..98a80e6545 100755 --- a/twake/frontend/src/app/services/languages/locale/fr.js +++ b/twake/frontend/src/app/services/languages/locale/fr.js @@ -681,6 +681,7 @@ export default { 'Envoyez-moi seulement un rapport journalier', 'scenes.apps.account.notifications.mail_option_never': 'Ne jamais envoyez de notifications par e-mail', + 'scenes.apps.account.notifications.sound': 'Notification sonore', 'scenes.apps.account.workspaces.workspace_name': 'Nom des espaces de travail', 'scenes.apps.account.workspaces.members_number': 'Nombre de membres', 'scenes.apps.account.workspaces.favorite_workspace': 'Espaces de travail favoris', @@ -1429,7 +1430,7 @@ export default { 'Configurez la fréquence des notifications mobile.', 'scenes.app.popup.userparameter.pages.frequency_notif_subtitle': 'Fréquence des notifications', 'scenes.app.popup.userparameter.pages.keywords_notif_description': - 'Ne recevez que des notifications correspondant à certains mots clés.', + 'Mettre en surbrillance les mots clés suivants:', 'scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description': 'Configurez la fréquence des notifications mail.', 'scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description': @@ -1441,6 +1442,10 @@ export default { 'scenes.aie': 'Aïe !', 'scenes.app.mainview.quick_search_placeholder': 'Recherche rapide', 'scenes.app.popup.userparameter.personnal_workspaces_title': 'Vos espaces de travail', + 'scenes.app.popup.userparameter.pages.private_message_content.show': + 'Afficher le contenu des messages privés', + 'scenes.app.popup.userparameter.pages.private_message_content.hide': + 'Masquer le contenu des messages privés', 'scenes.app.popup.workspaceparameter.admin_current_status': 'Vous êtes Administrateur.', 'scenes.app.popup.workspaceparameter.admin_manager_current_status': "Vous êtes Administrateur et Gérant de l'entreprise.", diff --git a/twake/frontend/src/app/services/languages/locale/ru.js b/twake/frontend/src/app/services/languages/locale/ru.js index 29eb8bd05f..69134ad6cb 100644 --- a/twake/frontend/src/app/services/languages/locale/ru.js +++ b/twake/frontend/src/app/services/languages/locale/ru.js @@ -1418,7 +1418,7 @@ export default { 'Установить частоту мобильных уведомлений.', 'scenes.app.popup.userparameter.pages.frequency_notif_subtitle': 'Частота уведомлений', 'scenes.app.popup.userparameter.pages.keywords_notif_description': - 'Получайте только те уведомления, которые соответствуют определенным ключевым словам.', + 'Выделите следующие ключевые слова:', 'scenes.app.popup.userparameter.pages.mail_frequency_notif_configuration_description': 'Установите частоту уведомлений по электронной почте.', 'scenes.app.popup.userparameter.pages.no_disturbing_notif_period_description': diff --git a/twake/frontend/src/app/services/user/notificationParameters.ts b/twake/frontend/src/app/services/user/notificationParameters.ts new file mode 100644 index 0000000000..607690abe2 --- /dev/null +++ b/twake/frontend/src/app/services/user/notificationParameters.ts @@ -0,0 +1,148 @@ +import moment from 'moment'; +import { message } from 'antd'; + +import Observable from 'services/Observable/Observable'; +import Languages from 'services/languages/languages.js'; +import FeedbackMessageManager from 'services/FeedbackMessageManager/FeedbackMessageManager'; +import Login from 'services/login/login.js'; + +import { Collection } from '../CollectionsReact/Collections'; +import { + preferencesType, + NotificationPreferencesResource, + } from 'app/models/NotificationPreferences'; + +type Keys = keyof preferencesType; +type Values = preferencesType[Keys]; + +class NotificationParametersService extends Observable { + constructor() { + super(); + } + + url = '/notifications/v1/preferences/'; + notificationPreferences!: NotificationPreferencesResource; + + async init() { + const collection = Collection.get(this.url, NotificationPreferencesResource); + + collection.addWatcher(()=>{ + //Will be called each time something happen on this collection + this.notificationPreferences = collection.findOne({}, {withoutBackend: true}); //Get preferences from collection store + this.notify(); //Tell all subscribed components to reload + }, {}, {}) + } + + /** + * + * @param preferences + */ + async save(preferences: {key:Keys, value:Values}[]) { + const newPreferences:any = {}, + user_id = Login.currentUserId, + workspace_id = "all", + company_id = "all"; + + preferences.map(({key, value})=> newPreferences[key] = value); + + const collection = Collection.get(this.url, NotificationPreferencesResource); + const currentPreferences = collection.findOne({user_id, workspace_id, company_id}); + + await collection.upsert( + new NotificationPreferencesResource({ + ...currentPreferences.data, + preferences: { + ...currentPreferences.data.preferences, + ...newPreferences + } + }) + ); + + FeedbackMessageManager.success(Languages.t('services.user.notification_parameters_update_alert'), 3); + } + + + areNotificationsAllowed() { + const _is_in_period = (a:number, b:number) => { + const currentDate = new Date().getHours() + Math.floor(new Date().getMinutes() / 30) / 2; + if (a != null && b != null) { + if (a < b && currentDate >= a && currentDate < b) { + return true; + } + if (a > b && (currentDate >= a || currentDate < b)) { + return true; + } + } + return false; + } + + const _transform_period = (a:any, b:any, offset:number) => { + a = parseFloat(a); + b = parseFloat(b); + + if (offset > 0) { + offset += -24; + } + + a += offset; + b += offset; + + if (a < 0 || b < 0) { + a += 24; + b += 24; + + if (b >= 24) { + if (a < b) { + b += -24; + } else { + b += -24; + const c = b; + b = a; + a = c; + } + } + + if (a >= 24) { + if (b < a) { + a += -24; + } else { + a += -24; + const c = a; + a = b; + b = c; + } + } + } + + return [a, b]; + } + + if (this.notificationPreferences) { + const nightBreakIntrv = _transform_period( + this.notificationPreferences.data.preferences.night_break.from, + this.notificationPreferences.data.preferences.night_break.to, + -new Date().getTimezoneOffset() / 60, + ); + + const isNightBreak = _is_in_period(nightBreakIntrv[0], nightBreakIntrv[1]); + const isDeactivate = moment.unix(this.notificationPreferences.data.preferences.deactivate_notifications_until).diff(moment()); + + return isNightBreak ? false : isDeactivate > 0 ? false : true; + } + + return false; + } + + /** + * + * @param timeToAdd Time to add + * @param format Unit of time + */ + deactivateNotificationsUntil(timeToAdd:number, format:'s'|'m'|'h'|'d'|'y') { + const unixtimestamp = moment().add(timeToAdd, format).unix(); + + this.save([{key:"deactivate_notifications_until", value:unixtimestamp}]) + } +} + +export default new NotificationParametersService(); \ No newline at end of file diff --git a/twake/frontend/src/app/services/user/notifications.tsx b/twake/frontend/src/app/services/user/notifications.tsx index 9c3c39e3e6..0dac7efb1f 100755 --- a/twake/frontend/src/app/services/user/notifications.tsx +++ b/twake/frontend/src/app/services/user/notifications.tsx @@ -15,6 +15,7 @@ import ChannelsService from 'services/channels/channels.js'; import emojione from 'emojione'; import NotificationParameters from 'services/user/notification_parameters.js'; import UserService from 'services/user/user.js'; +import NotificationPreferences from './notificationParameters'; type DesktopNotification = { channel_id: string; @@ -156,6 +157,7 @@ class Notifications extends Observable { } } this.updateAppBadge(badgeCount); + NotificationPreferences.init(); this.notify(); } From e1c8754d2df7e006dbf26cdb433a77239c281299 Mon Sep 17 00:00:00 2001 From: Romaric Mourgues Date: Mon, 12 Apr 2021 16:32:45 +0200 Subject: [PATCH 10/15] =?UTF-8?q?=E2=8F=AE=20=20Retrieve=20changes=20made?= =?UTF-8?q?=20to=20main=20branch=20into=202021.Q2.dev=20(#1141)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CODE_OF_CONDUCT.md | 106 ++++++------- CONTRIBUTING.md | 147 ++++++++++++++--- .../Commit & Pull Request Title Format.md | 24 +++ Contribute/HowtoApplyOurLicense.md | 19 +++ ...agora Developer's Certificate of Origin.md | 35 ++++ LICENSE.md | 149 ++++++++++++------ README.md | 14 +- pull_request_template.md | 35 ++++ .../Core/Command/TwakeSchemaUpdateCommand.php | 8 +- .../Notifications/Services/Notifications.php | 4 +- .../src/Twake/Workspaces/Entity/Group.php | 4 +- .../src/Twake/Workspaces/Entity/Workspace.php | 4 +- twake/docker-compose.yml.onpremise | 2 + 13 files changed, 412 insertions(+), 139 deletions(-) create mode 100644 Contribute/Commit & Pull Request Title Format.md create mode 100644 Contribute/HowtoApplyOurLicense.md create mode 100644 Contribute/Linagora Developer's Certificate of Origin.md create mode 100644 pull_request_template.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 3854628212..b940e0c7f7 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,76 @@ -# Contributor Covenant Code of Conduct +# LINAGORA OPEN-SOURCE CODE OF CONDUCT + + ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +In Linagora, we foster an open and welcoming environment to build Good Tech - ethical and open-source software. We build this Good Tech to have a maximum positive impact on people, society, and the planet. We call this #GoodTech4Good. This is made possible by the support, hard work and enthusiasm of thousands of people, including those who create and use Linagora products. + +We as contributors and maintainers pledge to making participation in our project and in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + + ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +This code of conduct outlines expectations for participants in Linagora managed open-source communities, as well as for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all. + +Examples of behavior that contributes to creating a positive environment include: + +- **Using welcoming and inclusive language**: Our communities welcome and support people of all backgrounds and identities. Remember you might not be communicating in someone else's primary spoken or programming language, and others may not have your level of understanding. + +- **Being respectful of differing viewpoints and experiences**: In order for the Linagora community to thrive, its members must feel comfortable and accepted. Treating one another with respect is absolutely necessary for this. In a disagreement, in the first instance assume that people mean well. Respecting other people, their work, their contributions and assuming well-meaning motivation will make community members feel comfortable and safe and will result in motivation and productivity. + +- **Gracefully accepting constructive criticism**: Disagreements, both political and technical, happen all the time. The goal is not to avoid disagreements or criticisms but to resolve them constructively. You should turn to the community to seek advice and to resolve disagreements and where possible consult the team most directly involved. Think deeply before taking a criticism personally and turning it into a public dispute. If you do feel that you or your work is being attacked, take your time to breathe through before writing heated replies. + +- **Focusing on what is best for the community**: The success and quality of open-source software depends on collaboration. As a contributor, you should aim to collaborate with other community members, as well as with other communities that are interested in or depend on the work you do. Your work should be transparent and be fed back into the community when available. Please ensure that you keep the other community members informed of your work, and publish it in a way that allows them to test, discuss and contribute to your efforts. + + As a user, your feedback is important, as is its form. Poorly thought out comments can cause pain and demotivation of other community members, but considerate discussion of problems can bring positive results. + +- **Showing empathy towards other community members**: Our community is made strong by mutual respect, collaboration and empathy. Sometimes there are situations where this has to be defended and other community members need help. If you witness others being attacked, think first about how you can offer them personal support. If you feel that the situation is beyond your ability to help individually, go privately to the victim and ask if some form of official intervention is needed. Similarly, you should support anyone who appears to be in danger of burning out, either through work-related stress or personal problems. -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +Examples of unacceptable behavior by participants include: + +- **The use of sexualized language or imagery and unwelcome sexual attention or advances.** +- **Trolling, insulting/derogatory comments, and personal or political attacks.** +- **Public or private harassments** +- **Publishing others' private information, such as physical or electronic address, without explicit permission.** +- **Other conduct which could reasonably be considered inappropriate in a professional setting.** + +This code is neither exhaustive nor complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter. -Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. -## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at contact@twakeapp.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +## Reporting Code of Conduct Issues -## Attribution +We encourage all community members to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting schauhan@linagora.com. Your report will be handled in accordance with the issue resolution process described in the Code of Conduct FAQ on our website(https://linagora.com). + +In your report please include: -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +- Your contact information. +- Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. +- Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment. +- Any additional information that may be helpful. -[homepage]: https://www.contributor-covenant.org +All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never a part of the review team. + +Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take an action they deem appropriate, including a permanent ban from the community. + + + +## Attribution -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +This Code of Conduct is adapted from both the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html and the template established by the [TODO Group](https://todogroup.org/). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f93065004a..b12feb37ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,39 +1,138 @@ # Contributing to Twake -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. +Hey! Thank you for your interest in contributing to Twake, we really appreciate it. -#### Run Twake in dev mode and get the documentation +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue, assessing changes, and helping you finalize your pull requests. -Everything you need is on the Twake documentation for internal developers: +We are an open-source project and we love to receive contributions from our community! There are many ways to contribute - writing tutorials or blog posts, improving the documentation, submitting bug reports and feature requests, fixing bugs, submitting pull requests for enhancements, or reviewing other's pull requests. -> https://doc.twake.app/internal-documentation/get_started -#### How to contribute -Any change must be done using **Pull Requests** incoming from a fork of original Twake repository. +## Ground Rules -#### Commit format +Please adhere to the following responsibilities: -Your pull request and commits must respect this format: +- Ensure cross-platform compatibility for every change that's accepted. For example, Windows, Mac, Debian & Ubuntu Linux. +- Any change must be done using **Pull Requests** incoming from a fork of original Twake repository. +- Create issues for any major changes and enhancements that you wish to make. Discuss things transparently and get community feedback. +- Don't add any classes to the codebase unless absolutely needed. Err on the side of using functions. +- Keep feature versions as small as possible, preferably one new feature per version. +- Be welcoming to newcomers and encourage diverse new contributions from all backgrounds. See the [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md) -`[Emoji] [Verb] [Details]` -The description of the commit must contain the issues fixed by your proposition. -Example: -`Fixes #43` -List of commit emojis: +#### What does the Code of Conduct mean for You? -- 🛠 Fixing broken code. -- ♻️ Refactoring code and making it work better. -- 🔍 Writing or fixing tests. -- 🌈 Making your code or your app beautiful with style -- 🐳 Deployment / docker -- 📚 Documentation -- 🌟 New feature +Our [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md) means that you are responsible for treating everyone on the project with respect and courtesy regardless of their identity. If you are the victim of any inappropriate behavior or comments as described in our [Code of Conduct](https://github.com/linagora/Twake/blob/main/CODE_OF_CONDUCT.md), we are here for you. Please follow the guidelines on our [website](https://linagora.com/en/) to report the issue and we will do the best to ensure that the abuser is reprimanded appropriately per our code. -Examples of commits: -`🛠 Fix broken login page` -`🌟 Implement SpaceX Crew Dragon plugin` + +## Your First Contribution? + +Unsure where to begin contributing to Twake? You can start by looking at these [good first issues](https://github.com/linagora/Twake/labels/good%20first%20issue) and [help wanted issues](https://github.com/linagora/Twake/labels/help%20wanted). Good first issues - issues which should require only a few lines of code, and a test or two. Help wanted issues - issues which should be a bit more involved than beginner issues. While not perfect, number of comments is a reasonable proxy for impact a given change will have. + +Working on your first Pull Request? You can learn how from these free resources: [Course - How to Contribute to an Open Source Project on GitHub from @kentcdodds on @eggheadio](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github) and [Make a Pull Request](https://makeapullrequest.com/). + +At this point, you are ready to make your changes! Feel free to ask for help; everyone is a beginner at first. 😃 + +If a maintainer asks you to "rebase" your PR, they are saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. + + + +## How to Contribute? + +When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. + +#### Pull Requests + +**It's important to break your feature down into small pieces first,** each piece should become it's own pull request. Once you know, what the first small piece of your feature will be, follow this general process while working: + +1. Create your own fork of the code and do changes in your own fork. + +2. Make your first commit: any will do even if empty or trivial, but we need something in order to create the initial pull request. Create the pull request and use the [pull request naming convention](https://github.com/linagora/Twake/blob/main/Contribute/Commit%20%26%20Pull%20Request%20Title%20Format.md). + + - Make sure that the titles of your pull requests and commits respect this format - [Commit & Pull Request Format](https://github.com/linagora/Twake/blob/main/Contribute/Commit%20%26%20Pull%20Request%20Title%20Format.md) + + - Write a detailed description of the problem you are solving, the part of Twake it affects, and how you plan on fixing it. + - If you have write access, add the **[Status] In Progress** label or wait until somebody adds it. This indicates that the pull request is not ready for a review and may still be incomplete. On the other hand, it welcomes early feedback and encourages collaboration during the development process. + +3. Start developing and pushing out commits to your new branch. + + - Push your changes out frequently and try to avoid getting stuck in a long-running branch or a merge nightmare. Smaller changes are much easier to review and to deal with potential conflicts. + - Note that you can automate some of these tasks by setting up githooks and they will run whenever you `git commit`. + - Please feel free to change, [squash](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html), and rearrange commits or to force push. Keep in mind, however, that if other people are committing on the same branch then you can mess up their history. You are perfectly safe if you are the only one pushing commits to that branch. + - Squash minor commits such as typo fixes or fixes to previous commits in the pull request. + +4. If you end up needing more than a few commits, consider splitting the pull request into separate components. Discuss in the new pull request and in the comments why the branch was broken apart and any changes that may have taken place that necessitated the split. Our goal is to catch early in the review process those pull requests that attempt to do too much. + +5. When you feel that you are ready for a formal review or for merging into `trunk` make sure you check this list. + + - Make sure your branch merges cleanly and consider rebasing against `trunk` to keep the branch history short and clean. + - If there are visual changes, add before and after screenshots in the pull request comments. + - Add unit tests, or at a minimum, provide helpful instructions for the reviewer so they can test your changes. This will help speed up the review process. + - Ensure that your commit messages are [meaningful](https://thoughtbot.com/blog/5-useful-tips-for-a-better-commit-message). + - Mention that the PR is ready for review or if you have write access remove the **[Status] In Progress** label from the pull request and add the **[Status] Needs Review** label - someone will provide feedback on the latest unreviewed changes. The reviewer will also mark the pull request as **[Status] Needs Author Reply** if they think you need to change anything. + +6. If you get a :thumbsup: and the status has been changed to **[Status] Ready to Merge** - this is great - the pull request is ready to be merged. + +If you feel yourself waiting for someone to review a PR, don't hesitate to personally ask for someone to review it or to mention them on Github. Remember, the PR author is responsible for pushing the change through. + + + +#### Sign your work + +We use the Developer Certificate of Origin (DCO) as an additional safeguard for the Linagora/Twake projects. This is a well established and widely used mechanism to assure contributors have confirmed their right to license their contributions under the project's license. Please read [Developer Certificate of Origin](https://github.com/linagora/Twake/blob/main/Contribute/Linagora%20Developer's%20Certificate%20of%20Origin.md). If you can certify it, then just add a line to every git commit message: + +`Signed-Off by: Unicorn John ` + +Use your real name (sorry, no pseudonyms or anonymous contributions). If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit-s`. + + + +#### Code Reviews + +Code Reviews are an important part of the Twake workflow. They help to keep code quality consistent, and they help every person working on Twake learn and improve over time. We want to make you the best Twake contributor you can be. + +Every PR should be reviewed and approved by someone other than the author, even if the author has write access. Fresh eyes can find problems that can hide in the open if you have been working on the code for a while. + +The recommended way of finding an appropriate person to review your code is by [blaming](https://docs.github.com/en/github/managing-files-in-a-repository/tracking-changes-in-a-file) one of the files you are updating and looking at who was responsible for previous commits on that file. + +Then, you may ask that person to review your code by mentioning their Github username on the PR comments like this: + +`cc @username` + +*Everyone* is encouraged to review PRs and add feedback and ask questions. Reading other people's code is a great way to learn new techniques, and seeing code outside of your own feature helps you to see patterns across the project. It's also helpful to see the feedback other contributors are getting on their PRs. + + + +#### Apply a license + +In case you are not sure about how to apply our license correctly, please have a look at [How to Apply Licence](https://github.com/linagora/Twake/blob/main/Contribute/HowtoApplyOurLicense.md). + + + +#### How to report a bug? + +If you find a security vulnerability, do NOT open an issue. Email schauhan@linagora.com instead. + +In order to determine whether you are dealing with a security issue, ask yourself these two questions: + +- Can I access something that's not mine, or something I should not have access to? + +- Can I disable something for other people? + + If the answer to either of those two questions are "yes", then you are probably dealing with a security issue. Note that even if you answer "no" to both questions, you may still be dealing with a security issue, so if you're unsure, just email us at schauhan@linagora.com. + +For reporting any other bug, just file [a Github issue.](https://github.com/linagora/Twake/issues/new/choose) + + + +#### How to suggest a feature or enhancement? + +If you find yourself wishing for a feature that doesn't exist in Twake, you are probably not alone. There are bound to be others out there with similar needs. Many of the features that Twake has today have been added because our users saw the need. Open an issues on our issues list on Github which describes the feature you would like to see, why you need it. + + + +## Community + +You can chat with the core team at [- Gitter](https://gitter.im/linagora/Twake) and we will try our best to reply to you as soon as possible. diff --git a/Contribute/Commit & Pull Request Title Format.md b/Contribute/Commit & Pull Request Title Format.md new file mode 100644 index 0000000000..9119bd8fd0 --- /dev/null +++ b/Contribute/Commit & Pull Request Title Format.md @@ -0,0 +1,24 @@ +# Commit and Pull Request Format + +Your pull request and commits titles must respect this format: + +`[Emoji] [Verb] [Details]` + +The description of the commit must contain the issues fixed by your proposition. +Example: +`Fixes #43` + +List of commit emojis: + +- 🛠 Fixing broken code. +- ♻️ Refactoring code and making it work better. +- 🔍 Writing or fixing tests. +- 🌈 Making your code or your app beautiful with style +- 🐳 Deployment / docker +- 📚 Documentation +- 🌟 New feature + +Examples of commits: + +`🛠 Fix broken login page` +`🌟 Implement SpaceX Crew Dragon plugin` diff --git a/Contribute/HowtoApplyOurLicense.md b/Contribute/HowtoApplyOurLicense.md new file mode 100644 index 0000000000..10efd19eac --- /dev/null +++ b/Contribute/HowtoApplyOurLicense.md @@ -0,0 +1,19 @@ +# How to apply our license? + +In order to distribute a program under the GNU Affero General Public License version 3 with the additional terms for TWAKE software, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + +`` + +`Copyright (c) ` + +`This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the license, or (at your option) any later version, provided you comply with the Additional Terms applicable for TWAKE software by Linagora pursuant to Section 7 of the GNU Affero General Public License, subsections (b), (c), and (e), pursuant to which you most notably (i) retain the "TWAKE is powered by LINAGORA" notice appended to any type of outbound messages (e.g. e-mail and meeting requests) as well as in the TWAKE user interface, (ii) retain all hypertext links between TWAKE and https://twake.app, as well as between LINAGORA and https://linagora.com, and (iii) refrain from infringing LINAGORA intellectual property rights over its trademark and commercial brands. Other Additional Terms apply, see for more details.` + +`This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.` + +`You should have received a copy of the GNU Affero General Public License and its applicable Additional Terms for TWAKE along with this program. If not, see for the GNU Affero Public License version 3 and for the Additional Terms applicable to the TWAKE software.` + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . diff --git a/Contribute/Linagora Developer's Certificate of Origin.md b/Contribute/Linagora Developer's Certificate of Origin.md new file mode 100644 index 0000000000..6768eb9244 --- /dev/null +++ b/Contribute/Linagora Developer's Certificate of Origin.md @@ -0,0 +1,35 @@ +# Developer Certificate of Origin + +[^Copyright (C) 2021 Linagora]: + + + +If you are reading this, then you're considering contributing to one or several LINAGORA project(s). That's great! We are enthusiastic about welcoming you as a LINAGORA project contributor, and working with you to make **#GoodTech4Good!** + +However, we have to ensure that anything you contribute to our projects: + +• is really your own creation, developed with your bare brain and fingers (or whatever organs you favor to type with your preferred input device), or that you’re allowed to contribute it; + +• is not “license locked”, i.e. that we can publish it under any other open source license in order to help our projects remain open source; + +• can remain in our projects and not suddenly become unusable because you change your mind and demand that we either use your code differently or not at all. + +To achieve this, we first need you to agree to this Developer Certificate of Origin before we can accept merging your contributions to our projects. Once you've done so, you can create your pull requests right away! + +By submitting a contribution to a LINAGORA project, you certify: + +a) that this contribution is provided under the terms and conditions of the Creative Commons Zero (CC0) license (https://creativecommons.org/publicdomain/zero/1.0/legalcode); + +b) being the rightful copyright owner of the contribution, and/or being fully and lawfully authorized to provide the contribution under the CC0 license on behalf of all entities which participated in the creation of the contribution (for example your employer); + +c) if the contribution is based upon a previous work, that this previous work is covered by an open source license which enables you to lawfully redistribute your contribution and this previous work both under the LINAGORA project license (Just reach out to us if you have any doubts, and we will help you); + +d) if your contribution is a derivative of one of our projects under a different license than the CC0 license, LINAGORA grants you a special authorization to provide this contribution to LINAGORA under the CC0 license regardless of the project license; + +d) if moral rights apply to your contribution, to the extent permitted by applicable law, that you will not try to assert your moral rights in a manner which would, directly or indirectly, interfere with the use of your contribution either by LINAGORA or by any project user (though, of course, you will always be credited as a contributor to the project); + +e) either that there are no patents applicable to your contribution, or if there are, that you then grant (and are allowed to lawfully grant) any users of your contribution a non-exclusive, perpetual, worldwide, no-charge, royalty-free, transferable and irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the contribution in any form and any combination; + +f) understanding and acknowledging that the LINAGORA project, your contribution, and any record pertaining thereto are and might remain indefinitely public, and might also be re-distributed to third-parties under the terms of the LINAGORA project license and/or the CC0 license; + +And that’s it! Let’s code now! diff --git a/LICENSE.md b/LICENSE.md index 106ea93e58..f3eb83374f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,28 +1,26 @@ -GNU Affero General Public License version 3 – Twake +# GNU Affero General Public License version 3 +License and Additional Terms for TWAKE software -License and Additional Terms for Twake software - -Twake is an open-source, cloud-based and enterprise-centric SaaS -dedicated to social and collaborative services, distributed under the GNU -Affero GPL v3 License terms, with Additional Terms pursuant to Section 7 of -said license. +TWAKE is a secure, open-source, and enterprise-centric SaaS collaboration +platform, distributed under the GNU Affero GPL v3 License terms, with +Additional Terms pursuant to Section 7 of said license. These Additional Terms are not intended to be taken as a change of heart by -Linagora over the principles of free software and open source distribution, as -Linagora strongly believes in free software and open source distribution, since -it warrants an easy and reasonable access to software innovation to large user -communities, and is highly committed to supporting free software and open -source whenever possible. +LINAGORA over the principles of free software and open source distribution, as +LINAGORA strongly believes in free software and open source distribution. +Free and open source software warrants an easy and reasonable access to software +innovation to large user communities, and LINAGORA is highly committed to supporting +free and open source software whenever possible. -Linagora wishes its paternity over Twake to be acknowledged, +LINAGORA wishes its paternity over TWAKE software to be acknowledged, regardless of its present or later use, modification, distribution and/or -evolutions. Accordingly, these terms aim at preserving Linagora moral rights -over Twake. +evolutions. Accordingly, these terms aim at preserving LINAGORA moral rights +over TWAKE. We have taken care of not affecting product copying, improvements or deploying. It is our conviction that the community will not be affected by these terms, the ultimate goal of which is to ensure the sustainability of free and open -source software by supporting R&D and improving the visibility of Linagora as a +source software by supporting R&D and improving the visibility of LINAGORA as a free and open source software publisher, while encouraging others to comply with our common ideals. @@ -38,16 +36,16 @@ you comply with its requirements, notably: General Public License version 3, including its Additional Terms pursuant to its section 7, subsections (b), (c) and (e). -Following are the applicable Additional Terms for use of Twake +Following are the applicable Additional Terms for use of the TWAKE software pursuant to section 7, subsections (b), (c) and (e) of the GNU Affero General Public License version 3. -Additional Terms applicable for Twake +### Additional Terms applicable for TWAKE software The following additional terms are applicable to the use, modification and -distribution of Twake: +distribution of TWAKE software: -1. Notices and Attribution: +**1. Notices and Attribution:** The interactive user interfaces in modified source and object code versions of this program must display Appropriate Legal Notices, as required under Section @@ -55,54 +53,61 @@ this program must display Appropriate Legal Notices, as required under Section In accordance with Section 7 and subsection (b) of the GNU Affero General Public License version 3, these Appropriate Legal Notices consist in the -display of the Signature Notice “Twake is powered by Linagora.” for any -and all type of outbound messages (e.g. e-mail and meeting requests). -Retaining this Signature Notice in any and all free and Open Source versions -of Twake is mandatory notwhistanding any other terms and conditions. +display, in a clearly legible manner, of the Notice “Twake is powered by +Linagora.” in the TWAKE user interface as well as for any and all type of +outbound messages (e.g. e-mail and meeting requests). + +Retaining this Notice in any and all free and Open Source versions of TWAKE +is mandatory notwithstanding any other terms and conditions. -These Signature Notices can be freely translated and replaced by any notice of -strictly identical meaning in another language according to localization of the -software, provided such notice clearly displays the words “Twake” and -“Linagora”. +If the display of the Appropriate Legal Notices, and/or logos is not reasonably +feasible for technical reasons, the Appropriate Legal Notices must display the +words "Twake is powered by Linagora." -Regardless of the notice language, the Logo/words "Twake" must be a clickable -hypertext link that leads directly to the Internet URL http://twake.app. -The Logo/word "Linagora" must be a clickable hypertext link that leads directly -to the Internet URL http://www.linagora.com. +These Notices can be freely translated and replaced by any notice of strictly +identical meaning in another language according to localization of the software, +provided such notice clearly displays the words “TWAKE” and “LINAGORA”. -2. Use of the Twake and Linagora trademarks and logos +Regardless of the notice language, the Logo/words "TWAKE" must be a clickable +hypertext link that leads directly to the Internet URL https://twake.app. +The Logo/word "LINAGORA" must be a clickable hypertext link that leads directly +to the Internet URL https://linagora.com. -Twake™ and Linagora™ are registered trademarks of Linagora. +**2. Use of the TWAKE and LINAGORA trademarks and logos** + +TWAKE™ and LINAGORA™ are registered trademarks of LINAGORA. Pursuant to Section 7, subsections (c) and (e) of the GNU Affero General Public License version 3, this license allows limited use of these trademarks under the following terms: -All Linagora trademarks, including Twake™ and Linagora™ logos shall be used by +All LINAGORA trademarks, including TWAKE™ and LINAGORA™ logos shall be used by the licensees and sublicensees for the sole purpose of complying with the present Additional Terms to the GNU Affero General Public License version 3, -excluding any other purpose without written consent obtained from Linagora. +excluding any other purpose without written consent obtained from LINAGORA. Using these trademarks without the (TM) trademark notice symbol, removing these trademarks from the software, modifying these trademarks in any manner except proportional scaling (under the proviso that such scaling keeps the trademark clearly legible), or using these trademarks to promote any products or services commercially, or on product packaging, websites, books, documentation or any -other publication without a written, signed agreement with Linagora is strictly -prohibited, and constitutes an infringement of Linagora intellectual property -rights over these trademarks. Using these trademarks in a way harmful, -damaging or detrimental to the value of the Twake brand or any other Linagora -trademarks, integrity, image, reputation, and/or goodwill, as determined by -Linagora, is also strictly prohibited, and constitutes an infringement of -Linagora intellectual property rights over these trademarks as well. - -Please report any possible violation of the GNU Affero General Public License +other publication without a written, signed agreement with LINAGORA is strictly +prohibited, and constitutes an infringement of LINAGORA intellectual property +rights over these trademarks. + +Using these trademarks in a way harmful,damaging or detrimental to the value of +the TWAKE brand or any other LINAGORA trademarks, integrity, image, reputation, +and/or goodwill, as determined by LINAGORA, is also strictly prohibited, and +constitutes an infringement of LINAGORA intellectual property rights over these +trademarks as well. + +**Please report any possible violation of the GNU Affero General Public License version 3, any violation of the hereabove Additional Terms, any infringement -and/or misuse of any Twake or Linagora trade marks and/or a violation of the -aforementioned Trademark Policy at . +and/or misuse of any TWAKE or LINAGORA trade marks and/or a violation of the +aforementioned Trademark Policy at .** - GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November - 2007 + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but @@ -676,3 +681,49 @@ liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS + +### How to Apply These Terms + +In order to distribute a program under the GNU Affero General Public License +version 3 with the Additional Terms for TWAKE software, attach the following +notices to the program. It is safest to attach them to the start of each source +file to most effectively state the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full notice is found. + +`` + +`Copyright (C) ` + +`This program is free software: you can redistribute it and/or modify it under the +terms of the GNU Affero General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later version, +provided you comply with the Additional Terms applicable for TWAKE software by +LINAGORA pursuant to Section 7 of the GNU Affero General Public License, subsections +(b), (c), and (e), pursuant to which you must notably (i) retain the “Twake is powered +by Linagora” notice appended to any type of outbound messages (e.g. e-mail and meeting +requests) as well as in the TWAKE user interface, (ii) retain all hypertext links between +TWAKE and https://twake.app, as well as between LINAGORA and LINAGORA.com, and (iii) refrain +from infringing LINAGORA intellectual property rights over its trademarks and commercial brands. +Other Additional Terms apply, see for more details.` + +`This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Affero General Public License for more details.` + +`You should have received a copy of the GNU Affero General Public License and its applicable Additional +Terms for TWAKE along with this program. If not, see for the GNU Affero +General Public License version 3 and for the Additional Terms +applicable to the TWAKE software.` + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure +that it provides a way for users to get its source. For example, if your program is a web application, +its interface could display a "Source" link that leads users to an archive of the code. There are many ways +you could offer source, and different solutions will be better for different programs; see section 13 for +the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright +disclaimer" for the program, if necessary. For more information on this, and how to apply and follow +the GNU AGPL, see . + diff --git a/README.md b/README.md index 4e66f4c448..9f0e86c88d 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,15 @@ # Twake - The Open Digital Workplace -![saas-update-backend](https://github.com/TwakeApp/Twake/workflows/saas-update-backend/badge.svg?branch=main&style=flat) -![saas-update-frontend](https://github.com/TwakeApp/Twake/workflows/saas-update-frontend/badge.svg?branch=main&style=flat) -![backend](https://github.com/TwakeApp/Twake/workflows/backend/badge.svg?branch=main&style=flat) -![docker](https://github.com/TwakeApp/Twake/workflows/docker/badge.svg?branch=main&style=flat) +![update-saas-backend](https://github.com/TwakeApp/Twake/workflows/update-saas-backend/badge.svg?branch=main&style=flat) +![update-saas-frontend](https://github.com/TwakeApp/Twake/workflows/update-saas-frontend/badge.svg?branch=main&style=flat) +![backend-build](https://github.com/TwakeApp/Twake/workflows/backend-build/badge.svg?branch=main&style=flat) +[![docker-build](https://github.com/Twake/Twake/actions/workflows/docker.yml/badge.svg)](https://github.com/Twake/Twake/actions/workflows/docker.yml) ![Docker](https://img.shields.io/docker/pulls/twaketech/twake-php?style=flat) [![Docs](https://img.shields.io/badge/docs-up--to--date-blueviolet?style=flat)](https://doc.twake.app) [![Community](https://img.shields.io/badge/community-awesome-brightgreen?style=flat)](https://community.twake.app) -[![Twitter](https://img.shields.io/badge/twitter-%40twake-blue?style=flat)](https://twitter.com/twake) +[![Twitter](https://img.shields.io/badge/twitter-%40twake-blue?style=flat)](https://twitter.com/twake) [![Join the chat at https://gitter.im/linagora/Twake](https://badges.gitter.im/linagora/Twake.svg)](https://gitter.im/linagora/Twake?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Twake is a secure open source collaboration platform to improve organizational productivity. Twake offers all the features for collaboration : @@ -57,6 +57,10 @@ Everyone can contribute at their own level, even if they only give a few minutes Install Twake on your machine with docker-compose using the install documentation here : [doc.twake.app/installation](https://doc.twake.app/installation) +### Migration to 2021.Q1.385 + +If you migrate to the 2021.Q1 version for a 2020.Q4 version or earlier, please follow the documentation at https://github.com/Twake/Twake/tree/main/migration/2020Q3_to_2020Q4 + ## License Twake is licensed under [Affero GPL v3 with additional terms](https://github.com/TwakeApp/Twake/blob/main/LICENSE.md) diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 0000000000..8ed57abc57 --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,35 @@ + + +## Description + + +## Related Issue + + + + + +## Motivation and Context + + +## How Has This Been Tested? + + + + +## Screenshots (if appropriate): + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I have read the **CONTRIBUTING** document. +- [ ] I have added the Signed-off-by statement at the end of my commit message. diff --git a/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php b/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php index 9956a86765..7e0aa1365f 100755 --- a/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php +++ b/twake/backend/core/src/Twake/Core/Command/TwakeSchemaUpdateCommand.php @@ -187,14 +187,18 @@ protected function execute() $fieldname = $mapping["columnName"]; } + $fieldname = $fieldname . "_id"; + + if(isset($mapping["joinColumns"][0]["name"])){ + $fieldname = $mapping["joinColumns"][0]["name"]; + } + if (strtolower($fieldname) != $fieldname) { $ignored_cols++; error_log("ERROR (IGNORING COLUMN) ! Column names MUST be snakecase and lowercase ! (" . $fieldname . " in " . $entity->getName() . ")"); continue; } - $fieldname = $fieldname . "_id"; - if (!(isset($mapping["id"]) && $mapping["id"])) { //isset($mapping["options"]) && isset($mapping["options"]["index"]) && $mapping["options"]["index"]) { $indexed_fields[$fieldname] = true; } diff --git a/twake/backend/core/src/Twake/Notifications/Services/Notifications.php b/twake/backend/core/src/Twake/Notifications/Services/Notifications.php index 2ad91af8ad..1c34ccaa10 100755 --- a/twake/backend/core/src/Twake/Notifications/Services/Notifications.php +++ b/twake/backend/core/src/Twake/Notifications/Services/Notifications.php @@ -147,8 +147,8 @@ public function pushNotification( "workspace_id" => ($workspace != null ? $workspace->getId() : null), "channel_id" => ($channel != null ? $channel->getId() : null), "message_id" => $message->getId(), - "thread_id" => $message->getParentMessageId(), - "click_action" => "FLUTTER_NOTIFICATION_CLICK" + "thread_id" => $message ? $message->getParentMessageId() : "", + "click_action" => "FLUTTER_NOTIFICATION_CLICK", ); $toPush = true; diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Group.php b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php index 9789dd324e..3fc62c3d83 100755 --- a/twake/backend/core/src/Twake/Workspaces/Entity/Group.php +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Group.php @@ -64,7 +64,7 @@ class Group extends SearchableObject * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") * @ORM\JoinColumn(name="logo_id") */ - protected $logoFile; + protected $logofile; /** * @ORM\Column(name="display_name", type="twake_text") @@ -229,7 +229,7 @@ public function setIdentityProviderId($identity_provider_id) */ public function getLogoFile() { - return $this->logoFile; + return $this->logofile; } /** diff --git a/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php index 438a0f7957..1c82ed3da2 100755 --- a/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php +++ b/twake/backend/core/src/Twake/Workspaces/Entity/Workspace.php @@ -64,7 +64,7 @@ class Workspace extends SearchableObject * @ORM\ManyToOne(targetEntity="Twake\Upload\Entity\File") * @ORM\JoinColumn(name="logo_id") */ - private $logoFile; + private $logofile; /** * @ORM\Column(name="uniquename", type="twake_no_salt_text", nullable=true) @@ -197,7 +197,7 @@ public function setUniqueName($name) */ public function getLogoFile() { - return $this->logoFile; + return $this->logofile; } /** diff --git a/twake/docker-compose.yml.onpremise b/twake/docker-compose.yml.onpremise index af4abc49a9..12f6714739 100644 --- a/twake/docker-compose.yml.onpremise +++ b/twake/docker-compose.yml.onpremise @@ -34,6 +34,8 @@ services: environment: - DEV=production volumes: + - ./configuration/backend/Parameters.php:/configuration/Parameters.php + - ./connectors/:/twake-core/src/BuiltInConnectors/Connectors - ./docker-data/drive/:/twake-core/drive/ - ./docker-data/fpm/:/etc/docker-data/fpm/ - ./docker-data/drive-preview/:/twake-core/web/medias/ From 2406047b2d72d66ecc95b7cc61544aeaf96e0c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Tallandier?= Date: Mon, 12 Apr 2021 18:12:05 +0200 Subject: [PATCH 11/15] =?UTF-8?q?=F0=9F=9B=A0=20FIX=20Marketing=20Bug=20Fe?= =?UTF-8?q?ature/2021.q2.dev=20(#1128)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIXing bug 2021.Q2 * FIX #1115 #1124 * FIX #1123 * Update #1123 * ADD #1131 * START #1054 : auto select channel * Avoid auto-login user if new credentials are provided * Do not show onboarding page for verified accounts * Add a logout option in the blocked account modal * Add loading and update function on blocked account verify mail action * Update BlockedAccount.tsx * Fix logout redirect uri * Update BlockedAccount.tsx * Improve code and remove channel auto select from collection Co-authored-by: Romaric Mourgues --- .../Users/Controller/Adapters/Console.php | 4 +- .../Users/Controller/UsersConnections.php | 3 +- .../Workspaces/Services/WorkspaceMembers.php | 15 -------- .../AddUserButton/AddUserButton.scss | 25 +++++++++++++ .../AddUserButton/AddUserButton.tsx | 37 +++++++++++++++++++ .../OnBoarding/CompanyStatusComponent.tsx | 2 +- .../OnBoarding/popups/BlockedAccount.tsx | 15 +++++++- .../scenes/Client/ChannelsBar/ChannelsBar.tsx | 4 +- .../scenes/Client/Popup/AddUser/AddUser.tsx | 13 +++---- .../Popup/AddUser/AddUserFromTwakeConsole.tsx | 14 ++++--- .../CreateWorkspacePage.js | 5 ++- .../Pages/WorkspaceAppsSearch.js | 12 ------ .../Pages/WorkspacePartner.js | 2 +- .../src/app/services/ConsoleService.ts | 9 +++-- .../services/channels/ChannelsBarService.ts | 1 + .../src/app/services/languages/locale/de.js | 6 +-- .../src/app/services/languages/locale/en.js | 8 ++-- .../src/app/services/languages/locale/es.js | 2 +- .../src/app/services/languages/locale/fr.js | 6 +-- .../src/app/services/languages/locale/ru.js | 6 +-- .../app/services/popupManager/popupManager.js | 3 ++ .../src/app/services/workspaces/workspaces.js | 3 +- 22 files changed, 127 insertions(+), 68 deletions(-) create mode 100644 twake/frontend/src/app/components/AddUserButton/AddUserButton.scss create mode 100644 twake/frontend/src/app/components/AddUserButton/AddUserButton.tsx diff --git a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php index bc5e10782f..1094cbbb43 100755 --- a/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php +++ b/twake/backend/core/src/Twake/Users/Controller/Adapters/Console.php @@ -34,10 +34,10 @@ function logoutSuccess(Request $request) try{ $message = json_decode(urldecode($request->query->get("error_code"))); }catch(\Exception $err){ - $message = "success"; + $message = false; } - return $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "/login" . "?error_code=".str_replace('+', '%20', urlencode(json_encode($message)))); + return $this->redirect(rtrim($this->getParameter("env.frontend_server_name", $this->getParameter("env.server_name")), "/") . "/login" . ($message ? ("?error_code=".str_replace('+', '%20', urlencode(json_encode($message)))) : "?auto")); } function logout(Request $request, $message = null) diff --git a/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php index d7c463c774..4aa8887fc3 100755 --- a/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php +++ b/twake/backend/core/src/Twake/Users/Controller/UsersConnections.php @@ -49,7 +49,8 @@ public function login(Request $request) $response = new Response(); $logged = $this->getUser() && !is_string($this->getUser()); - if(!$logged){ + if(!$logged || ($usernameOrMail && $password)){ + $this->get("app.session_handler")->setUser(null); $loginResult = $this->get("app.user")->login($usernameOrMail, $password, $rememberMe, $request, $response); } diff --git a/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php index f9f69405e7..148aa9077b 100755 --- a/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php +++ b/twake/backend/core/src/Twake/Workspaces/Services/WorkspaceMembers.php @@ -318,21 +318,6 @@ public function addMemberByMail($workspaceId, $mail, $asExterne, $currentUserId $this->doctrine->flush(); $retour = "mail"; } - - if($sendEmail){ - - //Send mail - $this->twake_mailer->send($mail, "inviteToWorkspaceMail", Array( - "_language" => $currentUser ? $currentUser->getLanguage() : "en", - "mail" => $mail, - "sender_user" => $currentUser ? $currentUser->getUsername() : "TwakeBot", - "sender_user_mail" => $currentUser ? $currentUser->getEmail() : "noreply@twakeapp.com", - "workspace" => $workspace->getName(), - "group" => $workspace->getGroup()->getDisplayName() - )); - - } - return $retour; } diff --git a/twake/frontend/src/app/components/AddUserButton/AddUserButton.scss b/twake/frontend/src/app/components/AddUserButton/AddUserButton.scss new file mode 100644 index 0000000000..5d0941aaa2 --- /dev/null +++ b/twake/frontend/src/app/components/AddUserButton/AddUserButton.scss @@ -0,0 +1,25 @@ +.addUserButton { + color: var(--primary); + + &:hover { + background: var(--primary-background); + + .iconBox { + background-color: transparent !important; + } + } + .icon { + .iconBox { + width: 18px; + height: 18px; + background-color: var(--primary-background); + border-radius: 4px; + padding-left: 2px; + + .icon-unicon { + color: var(--primary) !important; + } + } + color: var(--primary) !important ; + } +} diff --git a/twake/frontend/src/app/components/AddUserButton/AddUserButton.tsx b/twake/frontend/src/app/components/AddUserButton/AddUserButton.tsx new file mode 100644 index 0000000000..a5895ac2dc --- /dev/null +++ b/twake/frontend/src/app/components/AddUserButton/AddUserButton.tsx @@ -0,0 +1,37 @@ +import React, { Component } from 'react'; +import Icon from 'components/Icon/Icon.js'; +import Languages from 'services/languages/languages.js'; +import './AddUserButton.scss'; +import popupManager from 'services/popupManager/popupManager.js'; +import workspaceUserRightsService from 'services/workspaces/workspace_user_rights.js'; +import AddUser from 'app/scenes/Client/Popup/AddUser/AddUser'; +import AddUserFromTwakeConsole from 'app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole'; +import InitService from 'app/services/InitService'; + +export default (props: any) => { + return ( +
{ + if (InitService.server_infos?.auth?.console?.use) { + return popupManager.open(); + } else { + return popupManager.open(); + } + }} + > +
+
+ +
+
+
+ {Languages.t( + 'scenes.app.popup.workspaceparameter.pages.collaboraters_adding_button', + [], + 'Ajouter des collaborateurs', + )} +
+
+ ); +}; diff --git a/twake/frontend/src/app/components/OnBoarding/CompanyStatusComponent.tsx b/twake/frontend/src/app/components/OnBoarding/CompanyStatusComponent.tsx index 12d6a05c07..83ba9b0d40 100644 --- a/twake/frontend/src/app/components/OnBoarding/CompanyStatusComponent.tsx +++ b/twake/frontend/src/app/components/OnBoarding/CompanyStatusComponent.tsx @@ -31,7 +31,7 @@ const CompanyStatusComponent = (): JSX.Element => { if (!workspace?.id) return; const isNewUser: boolean = - onboarding !== 'completed' && workspace?.group?.stats?.total_members <= 1 && isNewCompany(); + onboarding !== 'completed' && workspace?.group?.stats?.total_members <= 1 && isNewCompany() && !user?.is_verified; if (isNewUser) { localStorage.setItem(`onboarding_${companyId}`, 'completed'); diff --git a/twake/frontend/src/app/components/OnBoarding/popups/BlockedAccount.tsx b/twake/frontend/src/app/components/OnBoarding/popups/BlockedAccount.tsx index b34ac131ab..34406503e5 100644 --- a/twake/frontend/src/app/components/OnBoarding/popups/BlockedAccount.tsx +++ b/twake/frontend/src/app/components/OnBoarding/popups/BlockedAccount.tsx @@ -2,13 +2,20 @@ import { Button, Row, Typography } from 'antd'; import React, { useState } from 'react'; import ObjectModal from '../../ObjectModal/ObjectModal'; import Languages from 'services/languages/languages.js'; +import ConsoleService from 'app/services/ConsoleService'; +import LoginService from 'services/login/login'; type PropsType = { email: string; }; const BlockedAccount = ({ email }: PropsType): JSX.Element => { - const onClickButton = () => console.log('clicked'); + const [loading, setLoading] = useState(false); + + const onClickButton = () => { + setLoading(true); + return ConsoleService.verifyMail().finally(() => setLoading(false)); + }; return ( { hideFooterDivider footerAlign="center" footer={ - } @@ -73,6 +80,10 @@ const BlockedAccount = ({ email }: PropsType): JSX.Element => { {Languages.t('components.unverified_account.re_send_email')} + + + LoginService.logout()}>{Languages.t('scenes.apps.account.account.logout')} + ); }; diff --git a/twake/frontend/src/app/scenes/Client/ChannelsBar/ChannelsBar.tsx b/twake/frontend/src/app/scenes/Client/ChannelsBar/ChannelsBar.tsx index 82ac0fa2a0..e2e24eeac6 100755 --- a/twake/frontend/src/app/scenes/Client/ChannelsBar/ChannelsBar.tsx +++ b/twake/frontend/src/app/scenes/Client/ChannelsBar/ChannelsBar.tsx @@ -9,6 +9,8 @@ import Footer from './Parts/Footer.js'; import RouterServices from 'app/services/RouterService'; import './ChannelsBar.scss'; import Shortcuts, { defaultShortcutsMap, ShortcutType } from 'app/services/ShortcutService'; +import AddUserButton from 'components/AddUserButton/AddUserButton'; +import Workspaces from 'services/workspaces/workspaces.js'; import ModalManager from 'app/components/Modal/ModalManager'; import WorkspaceChannelList from './Modals/WorkspaceChannelList'; import ScrollWithHiddenComponents from 'app/components/ScrollHiddenComponents/ScrollWithHiddenComponents'; @@ -49,7 +51,6 @@ export default () => { if (!companyId || !workspaceId) { return <>; } - return ( { > + {Workspaces.getCurrentWorkspace().stats.total_members <= 1 && } diff --git a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUser.tsx b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUser.tsx index 5214fb91a9..1615a17362 100644 --- a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUser.tsx +++ b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUser.tsx @@ -12,12 +12,12 @@ import './AddUser.scss'; import WorkspacesUsers from 'services/workspaces/workspaces_users.js'; type Props = { - standalone: boolean; - inline: boolean; - onChange: (members: any) => any; - previous: () => void; - finish: () => void; - loading: boolean; + standalone?: boolean; + inline?: boolean; + onChange?: (members: any) => any; + previous?: () => void; + finish?: () => void; + loading?: boolean; }; type State = { @@ -167,7 +167,6 @@ export default class AddUser extends Component {
{this.state.i18n.t('scenes.app.workspaces.create_company.invitations.title_2')}{' '} -
{this.state.multi && ( diff --git a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx index de16adffe0..e2808949a9 100644 --- a/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx +++ b/twake/frontend/src/app/scenes/Client/Popup/AddUser/AddUserFromTwakeConsole.tsx @@ -24,13 +24,14 @@ const AddUserFromTwakeConsole = (props: PropsType) => { const onChange = (e: React.ChangeEvent) => setEmails(e.target.value); const onClickBtn = async () => { - if (props.onChange) props.onChange(emails); + if (props.onChange) { + props.onChange(emails); + } if (props.finish) { props.finish(); return; } - setLoading(true); setDisabled(true); @@ -53,12 +54,10 @@ const AddUserFromTwakeConsole = (props: PropsType) => { popupManager.close(); }, 200); }; - return (
{Languages.t('scenes.app.workspaces.create_company.invitations.title_2')}{' '} -
{
-