From 2e958cace723cb78c8a6459becd543db3e3ec532 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Thu, 28 Jun 2018 17:41:10 -0300 Subject: [PATCH 01/28] Bump version to 0.67.0-develop --- .docker/Dockerfile.rhel | 2 +- .sandstorm/sandstorm-pkgdef.capnp | 4 ++-- .travis/snap.sh | 2 +- package.json | 2 +- packages/rocketchat-lib/rocketchat.info | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.docker/Dockerfile.rhel b/.docker/Dockerfile.rhel index 48af2bb2ed9a..3cdb4e368b78 100644 --- a/.docker/Dockerfile.rhel +++ b/.docker/Dockerfile.rhel @@ -1,6 +1,6 @@ FROM registry.access.redhat.com/rhscl/nodejs-8-rhel7 -ENV RC_VERSION 0.66.0 +ENV RC_VERSION 0.67.0-develop MAINTAINER buildmaster@rocket.chat diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index dc00db9464e0..b8b8cabc1b77 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,9 +19,9 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 77, # Increment this for every release. + appVersion = 78, # Increment this for every release. - appMarketingVersion = (defaultText = "0.66.0"), + appMarketingVersion = (defaultText = "0.67.0-develop"), # Human-readable representation of appVersion. Should match the way you # identify versions of your app in documentation and marketing. diff --git a/.travis/snap.sh b/.travis/snap.sh index 7f1e84ea2daf..6e54bc03d119 100755 --- a/.travis/snap.sh +++ b/.travis/snap.sh @@ -17,7 +17,7 @@ elif [[ $TRAVIS_TAG ]]; then RC_VERSION=$TRAVIS_TAG else CHANNEL=edge - RC_VERSION=0.66.0 + RC_VERSION=0.67.0-develop fi echo "Preparing to trigger a snap release for $CHANNEL channel" diff --git a/package.json b/package.json index 0844c1edd671..1d369b2de64f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "Rocket.Chat", "description": "The Ultimate Open Source WebChat Platform", - "version": "0.66.0", + "version": "0.67.0-develop", "author": { "name": "Rocket.Chat", "url": "https://rocket.chat/" diff --git a/packages/rocketchat-lib/rocketchat.info b/packages/rocketchat-lib/rocketchat.info index e04e03c812a5..301d768313e5 100644 --- a/packages/rocketchat-lib/rocketchat.info +++ b/packages/rocketchat-lib/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "0.66.0" + "version": "0.67.0-develop" } From fe4290be1b9e2d581b1d52ddf06a15905d8b5b07 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Tue, 3 Jul 2018 09:02:04 -0300 Subject: [PATCH 02/28] [FIX] Notification preferences being lost when switching view mode (#11295) --- package-lock.json | 65 ++++++++++++++++++--------- server/methods/saveUserPreferences.js | 6 +-- server/startup/migrations/v129.js | 60 +++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 server/startup/migrations/v129.js diff --git a/package-lock.json b/package-lock.json index e696dd348d37..1587fdbdda34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "Rocket.Chat", - "version": "0.66.0-develop", + "version": "0.67.0-develop", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -742,7 +742,7 @@ "autolinker": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-1.6.2.tgz", - "integrity": "sha1-Z66donLoCODY644Cy8jN4wOUdFc=" + "integrity": "sha512-IKLGtYFb3jzGTtgCpb4bm//1sXmmmgmr0msKshhYoc7EsWmLCFvuyxLcEIfcZ5gbCgZGXrnXkOkcBblOFEnlog==" }, "autoprefixer": { "version": "8.6.0", @@ -2957,7 +2957,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -3002,7 +3002,7 @@ "mocha": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", - "integrity": "sha1-fYbPvPNcuCnidUwy4XNV7AUzh5Q=", + "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", "dev": true, "requires": { "browser-stdout": "1.3.0", @@ -3020,13 +3020,13 @@ "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", "dev": true }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { "fs.realpath": "1.0.0", @@ -3054,7 +3054,7 @@ "supports-color": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha1-iD992rwWUUKyphQn8zUt7RldGj4=", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", "dev": true, "requires": { "has-flag": "2.0.0" @@ -4024,6 +4024,14 @@ "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, + "dbly-linked-list": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.2.0.tgz", + "integrity": "sha512-Ool7y15f6JRDs0YKx7Dh9uiTb1jS1SZLNdT3Y2q16DlaEghXbMsmODS/XittjR2xztt1gJUpz7jVxpqAPF8VGg==", + "requires": { + "lodash.isequal": "4.5.0" + } + }, "ddp-ejson": { "version": "0.8.1-3", "resolved": "https://registry.npmjs.org/ddp-ejson/-/ddp-ejson-0.8.1-3.tgz", @@ -6218,7 +6226,7 @@ "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -8178,7 +8186,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8753,6 +8761,11 @@ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=" + }, "lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", @@ -8776,7 +8789,7 @@ "lodash.merge": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=" + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" }, "lodash.once": { "version": "4.1.1", @@ -8944,7 +8957,7 @@ "mailsplit": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-4.1.2.tgz", - "integrity": "sha1-xhi8MRpM/IOyJqHtwbUD9akk0IM=", + "integrity": "sha512-5UWjUfhKlC4OR5PqZKcl4h7vnz2EP4M3Zg2SBbrztvAYX5lM/rA7tvaXkZ6zRcvK32Uul0GkRA037icDbiJIOw==", "requires": { "libbase64": "1.0.2", "libmime": "3.1.0", @@ -8954,7 +8967,7 @@ "libbase64": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.0.2.tgz", - "integrity": "sha1-L/E//mmx5AFZ9JNo4w0N2LsWNbU=" + "integrity": "sha512-CyPjvTFbsGps2Sdvy9GVjSRPvUGpji8Hxb+iunp466guzxcd3QaK0k8Hur1sPkgD9FonW8V1z2F1y066YiliEg==" } } }, @@ -9195,7 +9208,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "1.1.11" } @@ -9601,7 +9614,7 @@ "npmlog": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "1.1.5", "console-control-strings": "1.1.0", @@ -10006,7 +10019,7 @@ "path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha1-zvMdyOCho7sNEFwM2Xzzv0f0428=", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "requires": { "pify": "3.0.0" } @@ -10338,7 +10351,7 @@ "postcss-import": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", - "integrity": "sha1-Vck2LJGSmU7GiGXSJEGd8dspgfA=", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", "dev": true, "requires": { "postcss": "6.0.22", @@ -10387,7 +10400,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { @@ -11275,6 +11288,14 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=" }, + "queue-fifo": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/queue-fifo/-/queue-fifo-0.2.5.tgz", + "integrity": "sha512-GrHy3RDy0BOEVjelr+htts/QJyZAJr+7m4TisCA+RlUSsegQT6EGOf+NyxLDhSRflFI5vq3aADFOR/tNZCasxg==", + "requires": { + "dbly-linked-list": "0.2.0" + } + }, "quick-lru": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", @@ -11814,7 +11835,7 @@ "retry-request": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-3.3.1.tgz", - "integrity": "sha1-+3EnYjWmF+l1Uem+c3q1uRWR+54=", + "integrity": "sha512-PjAmtWIxjNj4Co/6FRtBl8afRP3CxrrIAnUzb1dzydfROd+6xt7xAebFeskgQgkfFf8NmzrXIoaB3HxmswXyxw==", "requires": { "request": "2.87.0", "through2": "2.0.3" @@ -13014,7 +13035,7 @@ "stylelint-order": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-0.8.1.tgz", - "integrity": "sha1-Nfca86FZVBVODpnlZGuj1vvjT40=", + "integrity": "sha512-8mp1P2wnI9XShYXVXDsxVigE2eXnc0C2O4ktbwUvTBwjCP4xZskIbUVxp1evSG3OK4R7hXVNl/2BnJCZkrcc/w==", "dev": true, "requires": { "lodash": "4.17.10", @@ -13062,7 +13083,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "supports-color": { @@ -13632,7 +13653,7 @@ "uc.micro": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", - "integrity": "sha1-DGXxX4FaoItWCmHOi023/8P0U3Y=" + "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==" }, "uglify-js": { "version": "2.8.29", @@ -14429,7 +14450,7 @@ "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha1-aGwg8hMgnpSr8NG88e+qKRx4J6c=", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", "requires": { "sax": "1.2.1", "xmlbuilder": "9.0.7" diff --git a/server/methods/saveUserPreferences.js b/server/methods/saveUserPreferences.js index f0516a11cf9f..b13ecc3d41bc 100644 --- a/server/methods/saveUserPreferences.js +++ b/server/methods/saveUserPreferences.js @@ -69,7 +69,7 @@ Meteor.methods({ // propagate changed notification preferences Meteor.defer(() => { - if (oldDesktopNotifications !== settings.desktopNotifications) { + if (settings.desktopNotifications && oldDesktopNotifications !== settings.desktopNotifications) { if (settings.desktopNotifications === 'default') { RocketChat.models.Subscriptions.clearDesktopNotificationUserPreferences(user._id); } else { @@ -77,7 +77,7 @@ Meteor.methods({ } } - if (oldMobileNotifications !== settings.mobileNotifications) { + if (settings.mobileNotifications && oldMobileNotifications !== settings.mobileNotifications) { if (settings.mobileNotifications === 'default') { RocketChat.models.Subscriptions.clearMobileNotificationUserPreferences(user._id); } else { @@ -85,7 +85,7 @@ Meteor.methods({ } } - if (oldEmailNotifications !== settings.emailNotificationMode) { + if (settings.emailNotificationMode && oldEmailNotifications !== settings.emailNotificationMode) { if (settings.emailNotificationMode === 'default') { RocketChat.models.Subscriptions.clearEmailNotificationUserPreferences(user._id); } else { diff --git a/server/startup/migrations/v129.js b/server/startup/migrations/v129.js new file mode 100644 index 000000000000..17a92c8a7ceb --- /dev/null +++ b/server/startup/migrations/v129.js @@ -0,0 +1,60 @@ +RocketChat.Migrations.add({ + version: 129, + up() { + RocketChat.models.Users.find({ + $or: [ + { 'settings.preferences.desktopNotifications': { $exists: true, $ne: 'default' } }, + { 'settings.preferences.mobileNotifications': { $exists: true, $ne: 'default' } }, + { 'settings.preferences.emailNotificationMode': { $exists: true, $ne: 'default' } } + ] + }, { + fields: { + 'settings.preferences.desktopNotifications': 1, + 'settings.preferences.mobileNotifications': 1, + 'settings.preferences.emailNotificationMode': 1 + } + }).forEach(user => { + if (user.settings.preferences.desktopNotifications && user.settings.preferences.desktopNotifications !== 'default') { + RocketChat.models.Subscriptions.update({ + 'u._id': user._id, + desktopPrefOrigin: 'user', + desktopNotifications: null + }, { + $set: { + desktopNotifications: user.settings.preferences.desktopNotifications + } + }, { + multi: true + }); + } + + if (user.settings.preferences.mobileNotifications && user.settings.preferences.mobileNotifications !== 'default') { + RocketChat.models.Subscriptions.update({ + 'u._id': user._id, + mobilePrefOrigin: 'user', + mobilePushNotifications: null + }, { + $set: { + mobilePushNotifications: user.settings.preferences.mobileNotifications + } + }, { + multi: true + }); + } + + if (user.settings.preferences.emailNotificationMode && user.settings.preferences.emailNotificationMode !== 'default') { + RocketChat.models.Subscriptions.update({ + 'u._id': user._id, + emailPrefOrigin: 'user', + emailNotifications: null + }, { + $set: { + emailNotifications: user.settings.preferences.emailNotificationMode === 'disabled' || user.settings.preferences.emailNotificationMode === 'nothing' ? 'nothing' : 'mentions' + } + }, { + multi: true + }); + } + }); + } +}); From 8b908bad87f5578f2a9a982ffdf2e59f5df756c7 Mon Sep 17 00:00:00 2001 From: Gabriel Delavald Date: Tue, 3 Jul 2018 09:03:09 -0300 Subject: [PATCH 03/28] [FIX] Livestream muted when audio only option was enabled (#11267) --- .../client/views/liveStreamView.html | 10 ---------- .../client/imports/components/popout.css | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/rocketchat-livestream/client/views/liveStreamView.html b/packages/rocketchat-livestream/client/views/liveStreamView.html index 43bec7b18288..765b2b52bcf7 100644 --- a/packages/rocketchat-livestream/client/views/liveStreamView.html +++ b/packages/rocketchat-livestream/client/views/liveStreamView.html @@ -1,15 +1,5 @@ diff --git a/packages/rocketchat-theme/client/imports/components/popout.css b/packages/rocketchat-theme/client/imports/components/popout.css index 96ba48dec29d..8b774f08bc5f 100644 --- a/packages/rocketchat-theme/client/imports/components/popout.css +++ b/packages/rocketchat-theme/client/imports/components/popout.css @@ -180,7 +180,7 @@ &.rc-popout__content { height: 0px; - visibility: hidden; + overflow: hidden; & .streaming-object { visibility: 'hidden'; From c37a90aabea2ca986219dd12b67d61df2e2d867e Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Tue, 3 Jul 2018 17:39:29 -0300 Subject: [PATCH 04/28] [IMPROVE] Setup Wizard username validation, step progress and optin/optout (#11254) Closes #11198 - [x] Show all steps on info box - [x] Properly display errors in registration process of admin user - [x] Break steps in subtemplates - [x] Redesign "Register Server" step ![Register Server](https://user-images.githubusercontent.com/2263066/42013253-cd691bc2-7a72-11e8-8832-fe9ccd9e89b4.png) - [x] Update end-to-end tests --- packages/rocketchat-i18n/i18n/en.i18n.json | 14 + .../rocketchat-lib/server/startup/settings.js | 3 + .../rocketchat-setup-wizard/client/final.html | 18 + .../rocketchat-setup-wizard/client/final.js | 51 ++ .../client/setupWizard.html | 360 +++++++------ .../client/setupWizard.js | 509 ++++++++++-------- packages/rocketchat-setup-wizard/package.js | 4 +- .../server/getSetupWizardParameters.js | 18 + .../server/lib/getWizardSettings.js | 9 - .../imports/components/setup-wizard.css | 143 ++++- tests/end-to-end/ui/00-login.js | 18 + tests/pageobjects/setup-wizard.page.js | 2 + 12 files changed, 713 insertions(+), 436 deletions(-) create mode 100644 packages/rocketchat-setup-wizard/client/final.html create mode 100644 packages/rocketchat-setup-wizard/client/final.js create mode 100644 packages/rocketchat-setup-wizard/server/getSetupWizardParameters.js delete mode 100644 packages/rocketchat-setup-wizard/server/lib/getWizardSettings.js diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 4c8582bfa328..96b4e6c56eee 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -234,6 +234,7 @@ "Allow_Invalid_SelfSigned_Certs": "Allow Invalid Self-Signed Certs", "Allow_Invalid_SelfSigned_Certs_Description": "Allow invalid and self-signed SSL certificate's for link validation and previews.", "Allow_switching_departments": "Allow Visitor to Switch Departments", + "Allow_Marketing_Emails": "Allow Marketing Emails", "Alphabetical": "Alphabetical", "Always_open_in_new_window": "Always Open in New Window", "Analytics_features_enabled": "Features Enabled", @@ -1370,6 +1371,7 @@ "InternalHubot_Username_Description": "This must be a valid username of a bot registered on your server.", "Invalid_confirm_pass": "The password confirmation does not match password", "Invalid_email": "The email entered is invalid", + "Invalid_username": "The username entered is invalid", "Invalid_Export_File": "The file uploaded isn't a valid %s export file.", "Invalid_Import_File_Type": "Invalid Import file type.", "Invalid_name": "The name must not be empty", @@ -2035,6 +2037,17 @@ "Regenerate_codes": "Regenerate codes", "Register": "Register a new account", "Register_Server": "Register Server", + "Register_Server_Info": "Use the preconfigured gateways and proxies provided by Rocket.Chat Technologies Corp.", + "Register_Server_Registered": "Register to access", + "Register_Server_Registered_Push_Notifications": "Mobile push notifications gateway", + "Register_Server_Registered_Livechat": "Livechat omnichannel proxy", + "Register_Server_Registered_OAuth": "OAuth proxy for social network", + "Register_Server_Registered_Marketplace": "Apps Marketplace", + "Register_Server_Opt_In": "Newsletter, offers and product updates", + "Register_Server_Standalone": "Keep standalone, you'll need to", + "Register_Server_Standalone_Service_Providers": "Create accounts with service providers", + "Register_Server_Standalone_Update_Settings": "Update the preconfigured settings", + "Register_Server_Standalone_Own_Certificates": "Recompile the mobile apps with your own certificates", "Registration": "Registration", "Registration_Succeeded": "Registration Succeeded", "Registration_via_Admin": "Registration via Admin", @@ -2215,6 +2228,7 @@ "Shared_Location": "Shared Location", "Should_be_a_URL_of_an_image": "Should be a URL of an image.", "Should_exists_a_user_with_this_username": "The user must already exist.", + "Show_Setup_Wizard": "Show Setup Wizard", "Show_agent_email": "Show agent email", "Show_all": "Show All", "Show_Avatars": "Show Avatars", diff --git a/packages/rocketchat-lib/server/startup/settings.js b/packages/rocketchat-lib/server/startup/settings.js index 4d8a0e329f3f..cd870f383ef4 100644 --- a/packages/rocketchat-lib/server/startup/settings.js +++ b/packages/rocketchat-lib/server/startup/settings.js @@ -2902,6 +2902,9 @@ RocketChat.settings.addGroup('Setup_Wizard', function() { order: 2 } }); + this.add('Allow_Marketing_Emails', true, { + type: 'boolean' + }); }); }); diff --git a/packages/rocketchat-setup-wizard/client/final.html b/packages/rocketchat-setup-wizard/client/final.html new file mode 100644 index 000000000000..f44289e9b1c5 --- /dev/null +++ b/packages/rocketchat-setup-wizard/client/final.html @@ -0,0 +1,18 @@ + diff --git a/packages/rocketchat-setup-wizard/client/final.js b/packages/rocketchat-setup-wizard/client/final.js new file mode 100644 index 000000000000..3fea0f68212c --- /dev/null +++ b/packages/rocketchat-setup-wizard/client/final.js @@ -0,0 +1,51 @@ +Template.setupWizardFinal.onCreated(function() { + const isSetupWizardDone = localStorage.getItem('wizardFinal'); + if (isSetupWizardDone === null) { + FlowRouter.go('setup-wizard'); + } + + this.autorun(c => { + const showSetupWizard = RocketChat.settings.get('Show_Setup_Wizard'); + if (!showSetupWizard) { + // Setup Wizard state is not defined yet + return; + } + + const userId = Meteor.userId(); + const user = userId && RocketChat.models.Users.findOne(userId, { fields: { status: true } }); + if (userId && (!user || !user.status)) { + // User and its status are not defined yet + return; + } + + c.stop(); + + const isComplete = showSetupWizard === 'completed'; + const noUserLoggedInAndIsNotPending = !userId && showSetupWizard !== 'pending'; + const userIsLoggedButIsNotAdmin = userId && !RocketChat.authz.hasRole(userId, 'admin'); + if (isComplete || noUserLoggedInAndIsNotPending || userIsLoggedButIsNotAdmin) { + FlowRouter.go('home'); + return; + } + }); +}); + +Template.setupWizardFinal.onRendered(function() { + $('#initial-page-loading').remove(); +}); + +Template.setupWizardFinal.events({ + 'click .js-finish'() { + RocketChat.settings.set('Show_Setup_Wizard', 'completed', function() { + localStorage.removeItem('wizard'); + localStorage.removeItem('wizardFinal'); + FlowRouter.go('home'); + }); + } +}); + +Template.setupWizardFinal.helpers({ + siteUrl() { + return RocketChat.settings.get('Site_Url'); + } +}); diff --git a/packages/rocketchat-setup-wizard/client/setupWizard.html b/packages/rocketchat-setup-wizard/client/setupWizard.html index 6f082939f37c..26a4613d4f3b 100644 --- a/packages/rocketchat-setup-wizard/client/setupWizard.html +++ b/packages/rocketchat-setup-wizard/client/setupWizard.html @@ -1,196 +1,214 @@ - - + + + + + + + + diff --git a/packages/rocketchat-setup-wizard/client/setupWizard.js b/packages/rocketchat-setup-wizard/client/setupWizard.js index 445cb3b504c9..715ea2e83518 100644 --- a/packages/rocketchat-setup-wizard/client/setupWizard.js +++ b/packages/rocketchat-setup-wizard/client/setupWizard.js @@ -1,90 +1,135 @@ -import s from 'underscore.string'; +const cannotSetup = () => { + const showSetupWizard = RocketChat.settings.get('Show_Setup_Wizard'); + if (!showSetupWizard) { + // Setup Wizard state is not defined yet + return; + } -const setSettingsAndGo = (settings, registerServer = true) => { - const settingsFilter = Object.entries(settings) - .filter(([key]) => !/registration-|registerServer|currentStep/.test(key)) - .map(([_id, value]) => ({_id, value})); + const userId = Meteor.userId(); + const user = userId && RocketChat.models.Users.findOne(userId, { fields: { status: true } }); + if (userId && (!user || !user.status)) { + // User and its status are not defined yet + return; + } - settingsFilter.push({ - _id: 'Statistics_reporting', - value: registerServer - }); + const isComplete = showSetupWizard === 'completed'; + const noUserLoggedInAndIsNotPending = !userId && showSetupWizard !== 'pending'; + const userIsLoggedButIsNotAdmin = userId && !RocketChat.authz.hasRole(userId, 'admin'); - RocketChat.settings.batchSet(settingsFilter, function(err) { - if (err) { - return handleError(err); + return isComplete || noUserLoggedInAndIsNotPending || userIsLoggedButIsNotAdmin; +}; + +const registerAdminUser = (state, callback) => { + const registrationData = Object.entries(state) + .filter(([ key ]) => /registration-/.test(key)) + .map(([ key, value ]) => ([ key.replace('registration-', ''), value ])) + .reduce((o, [ key, value ]) => ({ ...o, [key]: value }), {}); + + Meteor.call('registerUser', registrationData, error => { + if (error) { + return handleError(error); } - localStorage.setItem('wizardFinal', true); - FlowRouter.go('setup-wizard-final'); + RocketChat.callbacks.run('userRegistered'); + Meteor.loginWithPassword(registrationData.email, registrationData.pass, error => { + if (error) { + if (error.error === 'error-invalid-email') { + toastr.success(t('We_have_sent_registration_email')); + return false; + } else { + return handleError(error); + } + } + + Session.set('forceLogin', false); + Meteor.call('setUsername', registrationData.username, error => { + if (error) { + return handleError(error); + } + + RocketChat.callbacks.run('usernameSet'); + callback && callback(); + }); + }); }); }; -Template.setupWizard.onCreated(function() { - const userId = Meteor.userId(); - - this.autorun((c) => { - const Show_Setup_Wizard = RocketChat.settings.get('Show_Setup_Wizard'); - const user = Meteor.user(); +const persistSettings = (state, callback) => { + const settings = Object.entries(state) + .filter(([ key ]) => !/registration-|registerServer|optIn|currentStep|invalidUsername|invalidEmail/.test(key)) + .map(([ _id, value ]) => ({ _id, value })) + .concat([ + { + _id: 'Statistics_reporting', + value: state['registerServer'] + }, + { + _id: 'Allow_Marketing_Emails', + value: state['optIn'] + } + ]); - // Wait for roles and setup wizard setting - if ((userId && (!user || !user.status)) || !Show_Setup_Wizard) { - return; + RocketChat.settings.batchSet(settings, error => { + if (error) { + return handleError(error); } - c.stop(); - - if ((!userId && Show_Setup_Wizard !== 'pending') || Show_Setup_Wizard === 'completed' || (userId && !RocketChat.authz.hasRole(userId, 'admin'))) { - FlowRouter.go('home'); - } + callback && callback(); }); +}; + +Template.setupWizard.onCreated(function() { + this.state = new ReactiveDict(); + this.state.set('currentStep', 1); + this.state.set('registerServer', true); + this.state.set('optIn', true); + + this.wizardSettings = new ReactiveVar([]); + this.allowStandaloneServer = new ReactiveVar(false); if (localStorage.getItem('wizardFinal')) { FlowRouter.go('setup-wizard-final'); + return; } - this.hasAdmin = new ReactiveVar(false); - this.state = new ReactiveDict(); - this.wizardSettings = new ReactiveVar([]); - this.invalidEmail = new ReactiveVar(false); + const jsonString = localStorage.getItem('wizard'); + const state = jsonString && JSON.parse(jsonString) || {}; + Object.entries(state).forEach(entry => this.state.set(...entry)); - const storage = JSON.parse(localStorage.getItem('wizard')); - if (storage) { - Object.entries(storage).forEach(([key, value]) => { - this.state.set(key, value); - }); - } + this.autorun(c => { + const cantSetup = cannotSetup(); + if (typeof cantSetup === 'undefined') { + return; + } - this.autorun(() => { - const user = Meteor.user(); - if (user) { - if (!this.hasAdmin.get()) { - if (user.roles && user.roles.includes('admin')) { - this.state.set('currentStep', 2); - this.hasAdmin.set(true); - } else { - this.hasAdmin.set(false); - } - } + if (cantSetup) { + c.stop(); + FlowRouter.go('home'); + return; + } + + const state = this.state.all(); + state['registration-pass'] = ''; + localStorage.setItem('wizard', JSON.stringify(state)); - Meteor.call('getWizardSettings', (error, result) => { + if (Meteor.userId()) { + Meteor.call('getSetupWizardParameters', (error, { settings, allowStandaloneServer }) => { if (error) { return handleError(error); } - this.wizardSettings.set(result); + this.wizardSettings.set(settings); + this.allowStandaloneServer.set(allowStandaloneServer); }); - } else { - this.state.set('currentStep', 1); - } - if (RocketChat.settings.get('Show_Setup_Wizard') === 'completed') { - FlowRouter.go('home'); + if (this.state.get('currentStep') === 1) { + this.state.set('currentStep', 2); + } else { + this.state.set('registration-pass', ''); + } + } else if (this.state.get('currentStep') !== 1) { + this.state.set('currentStep', 1); } - - const states = this.state.all(); - states['registration-pass'] = ''; - localStorage.setItem('wizard', JSON.stringify(states)); }); }); @@ -93,67 +138,83 @@ Template.setupWizard.onRendered(function() { }); Template.setupWizard.events({ + 'submit .setup-wizard-forms__box'() { + return false; + }, 'click .setup-wizard-forms__footer-next'(e, t) { - const currentStep = t.state.get('currentStep'); - const hasAdmin = t.hasAdmin.get(); - - if (!hasAdmin && currentStep === 1) { - const emailValue = t.state.get('registration-email'); - const invalidEmail = !/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+\b/i.test(emailValue); - t.invalidEmail.set(invalidEmail); + switch (t.state.get('currentStep')) { + case 1: { + const usernameValue = t.state.get('registration-username'); + const usernameRegex = new RegExp(`^${ RocketChat.settings.get('UTF8_Names_Validation') }$`); + t.state.set('invalidUsername', !usernameRegex.test(usernameValue)); + + const emailValue = t.state.get('registration-email'); + const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$/i; + t.state.set('invalidEmail', !emailRegex.test(emailValue)); + + if (t.state.get('invalidUsername') || t.state.get('invalidEmail')) { + return false; + } - if (invalidEmail) { + registerAdminUser(t.state.all(), () => t.state.set('currentStep', 2)); return false; } - - const state = t.state.all(); - const registration = Object.entries(state).filter(([key]) => /registration-/.test(key)); - const registrationData = Object.assign(...registration.map(d => ({[d[0].replace('registration-', '')]: d[1]}))); - - Meteor.call('registerUser', registrationData, error => { - if (error) { - return handleError(error); - } - - RocketChat.callbacks.run('userRegistered'); - - Meteor.loginWithPassword(s.trim(registrationData.email), registrationData.pass, error => { - if (error && error.error === 'error-invalid-email') { - toastr.success(t('We_have_sent_registration_email')); - return false; - } - - Session.set('forceLogin', false); - - Meteor.call('setUsername', registrationData.username, error => { - if (error) { - return handleError(error); - } - - RocketChat.callbacks.run('usernameSet'); - }); + case 2: { + t.state.set('currentStep', 3); + return false; + } + case 3: { + t.state.set('currentStep', 4); + return false; + } + case 4: { + persistSettings(t.state.all(), () => { + localStorage.removeItem('wizard'); + localStorage.setItem('wizardFinal', true); + FlowRouter.go('setup-wizard-final'); }); - }); + return false; + } } - if (hasAdmin && currentStep === 3) { - setSettingsAndGo(t.state.all()); - return false; + return false; + }, + 'click .setup-wizard-forms__footer-back'(e, t) { + switch (t.state.get('currentStep')) { + case 2: + t.state.set('currentStep', 1); + break; + case 3: + t.state.set('currentStep', 2); + break; + case 4: + t.state.set('currentStep', 3); + break; } - if (currentStep === 4) { - setSettingsAndGo(t.state.all(), JSON.parse(t.state.get('registerServer') || true)); + return false; + }, + 'input .js-setting-data'({ currentTarget: { name, value } }, t) { + t.state.set(name, value); + }, + 'click input[name="registerServer"]'({ currentTarget: { value } }, t) { + const oldValue = t.state.get('registerServer'); + const newValue = value === 'true'; + t.state.set('registerServer', newValue); - return false; + if (!oldValue && newValue) { + t.state.set('optIn', true); } - t.state.set('currentStep', currentStep + 1); - }, - 'click .setup-wizard-forms__footer-back'(e, t) { - t.state.set('currentStep', t.state.get('currentStep') - 1); + if (!newValue) { + t.state.set('optIn', false); + } + + return false; }, - 'input .js-setting-data'(e, t) { - t.state.set(e.currentTarget.name, e.currentTarget.value); + 'click input[name="optIn"]'({ currentTarget: { checked } }, t) { + t.state.set('optIn', checked); + return false; } }); @@ -161,144 +222,138 @@ Template.setupWizard.helpers({ currentStep() { return Template.instance().state.get('currentStep'); }, - itemModifier(step) { - const current = Template.instance().state.get('currentStep'); - - if (current === step) { - return 'setup-wizard-info__steps-item--active'; - } - - if (current > step) { - return 'setup-wizard-info__steps-item--past'; + currentStepTitle() { + switch (Template.instance().state.get('currentStep')) { + case 1: + return 'Admin_Info'; + case 2: + return 'Organization_Info'; + case 3: + return 'Server_Info'; + case 4: + return 'Register_Server'; } - - return ''; - }, - getValue(name) { - return Template.instance().state.get(name); - }, - selectedValue(setting, optionValue) { - return Template.instance().state.get(setting) === optionValue; }, - isDisabled() { - const user = Meteor.user(); - if (user && user.roles && !user.roles.includes('admin')) { - return 'disabled'; - } - - if (Template.instance().state.get('currentStep') === 1) { - const state = Template.instance().state.all(); - - if (Object.entries(state).filter(([key, value]) => /registration-/.test(key) && !value).length) { - return 'disabled'; - } + formLoadStateClass() { + switch (Template.instance().state.get('currentStep')) { + case 1: + return RocketChat.settings.get('Show_Setup_Wizard') === 'pending' && 'setup-wizard-forms__box--loaded'; + case 2: + case 3: + return Template.instance().wizardSettings.get().length > 0 && 'setup-wizard-forms__box--loaded'; + case 4: + return 'setup-wizard-forms__box--loaded'; } - - return ''; }, - headerTitle(step) { - if (!step) { - step = Template.instance().state.get('currentStep'); + showBackButton() { + switch (Template.instance().state.get('currentStep')) { + case 3: + return true; + case 4: + return true; } - switch (step) { - case 1: return t('Admin_Info'); - case 2: return t('Organization_Info'); - case 3: return t('Server_Info'); - case 4: return t('Register_Server'); - } + return false; }, - showStep() { - const currentStep = Template.instance().state.get('currentStep'); - if (currentStep === 2 || currentStep === 3) { - return 'setup-wizard-forms__content-step--active'; + isContinueDisabled() { + switch (Template.instance().state.get('currentStep')) { + case 1: + return Object.entries(Template.instance().state.all()) + .filter(([key, value]) => /registration-/.test(key) && !value) + .length !== 0; } - return ''; - }, - getSettings(step) { - return Template.instance().wizardSettings.get() - .filter(setting => setting.wizard.step === step) - .sort((a, b) => a.wizard.order - b.wizard.order); + return false; }, - languages() { - const languages = TAPi18n.getLanguages(); - - const result = Object.entries(languages).map(language => { - const obj = language[1]; - obj.key = language[0]; - return obj; - }).sort((a, b) => a.key - b.key); - - result.unshift({ - 'name': 'Default', - 'en': 'Default', - 'key': '' - }); + infoArgs() { + const t = Template.instance(); - return result; + return { + currentStep: t.state.get('currentStep') + }; }, - hasAdmin() { - return Template.instance().hasAdmin.get(); + adminInfoArgs() { + const t = Template.instance(); + + return { + currentStep: t.state.get('currentStep'), + name: t.state.get('registration-name'), + username: t.state.get('registration-username'), + email: t.state.get('registration-email'), + password: t.state.get('registration-pass'), + invalidUsername: t.state.get('invalidUsername'), + invalidEmail: t.state.get('invalidEmail') + }; }, - invalidEmail() { - return Template.instance().invalidEmail.get(); + registerServerArgs() { + const t = Template.instance(); + + return { + currentStep: t.state.get('currentStep'), + allowStandaloneServer: t.allowStandaloneServer.get(), + registerServer: t.allowStandaloneServer.get() ? t.state.get('registerServer') : true, + optIn: t.state.get('optIn') + }; }, - showBackButton() { - if (Template.instance().hasAdmin.get()) { - if (Template.instance().state.get('currentStep') > 2) { - return true; - } - - return false; - } - - if (Template.instance().state.get('currentStep') > 1) { - return true; - } - - return false; + customStepArgs(step) { + const t = Template.instance(); + + return { + currentStep: t.state.get('currentStep'), + step, + settings: t.wizardSettings.get() + .filter(setting => setting.wizard.step === step) + .sort((a, b) => a.wizard.order - b.wizard.order) + .map(({ type, _id, i18nLabel, values }) => ({ + type, + id: _id, + label: i18nLabel, + value: t.state.get(_id), + options: ( + type === 'select' && + values && + values.map(({ i18nLabel, key }) => ({ optionLabel: i18nLabel, optionValue: key })) + ) || ( + type === 'language' && + ([{ + optionLabel: 'Default', + optionValue: '' + }].concat( + Object.entries(TAPi18n.getLanguages()) + .map(([ key, { name } ]) => ({ optionLabel: name, optionValue: key })) + .sort((a, b) => a.key - b.key) + )) + ), + isValueSelected: (value) => value === t.state.get(_id) + })) + }; } }); -Template.setupWizardFinal.onCreated(function() { - this.autorun(() => { - const userId = Meteor.userId(); - - this.autorun((c) => { - const Show_Setup_Wizard = RocketChat.settings.get('Show_Setup_Wizard'); - const user = Meteor.user(); - - // Wait for roles and setup wizard setting - if ((userId && (!user || !user.status)) || !Show_Setup_Wizard) { - return; - } - - c.stop(); - - if ((!userId && Show_Setup_Wizard !== 'pending') || Show_Setup_Wizard === 'completed' || (userId && !RocketChat.authz.hasRole(userId, 'admin'))) { - FlowRouter.go('home'); - } - }); - }); -}); +Template.setupWizardInfo.helpers({ + stepItemModifier(step) { + const { currentStep } = Template.currentData(); -Template.setupWizardFinal.onRendered(function() { - $('#initial-page-loading').remove(); -}); + if (currentStep === step) { + return 'setup-wizard-info__steps-item--active'; + } -Template.setupWizardFinal.events({ - 'click .js-finish'() { - RocketChat.settings.set('Show_Setup_Wizard', 'completed', function() { - localStorage.removeItem('wizard'); - localStorage.removeItem('wizardFinal'); - FlowRouter.go('home'); - }); - } -}); + if (currentStep > step) { + return 'setup-wizard-info__steps-item--past'; + } -Template.setupWizardFinal.helpers({ - siteUrl() { - return RocketChat.settings.get('Site_Url'); + return ''; + }, + stepTitle(step) { + switch (step) { + case 1: + return 'Admin_Info'; + case 2: + return 'Organization_Info'; + case 3: + return 'Server_Info'; + case 4: + return 'Register_Server'; + } } }); diff --git a/packages/rocketchat-setup-wizard/package.js b/packages/rocketchat-setup-wizard/package.js index b9d07f3caeb3..ba70d31fd112 100644 --- a/packages/rocketchat-setup-wizard/package.js +++ b/packages/rocketchat-setup-wizard/package.js @@ -12,6 +12,8 @@ Package.onUse(function(api) { api.addFiles('client/setupWizard.html', 'client'); api.addFiles('client/setupWizard.js', 'client'); + api.addFiles('client/final.html', 'client'); + api.addFiles('client/final.js', 'client'); - api.addFiles('server/lib/getWizardSettings.js', 'server'); + api.addFiles('server/getSetupWizardParameters.js', 'server'); }); diff --git a/packages/rocketchat-setup-wizard/server/getSetupWizardParameters.js b/packages/rocketchat-setup-wizard/server/getSetupWizardParameters.js new file mode 100644 index 000000000000..910947c0418e --- /dev/null +++ b/packages/rocketchat-setup-wizard/server/getSetupWizardParameters.js @@ -0,0 +1,18 @@ +Meteor.methods({ + getSetupWizardParameters() { + const userId = Meteor.userId(); + const userHasAdminRole = userId && RocketChat.authz.hasRole(userId, 'admin'); + + if (!userHasAdminRole) { + throw new Meteor.Error('error-not-allowed'); + } + + const settings = RocketChat.models.Settings.findSetupWizardSettings().fetch(); + const allowStandaloneServer = process.env.DEPLOY_PLATFORM !== 'rocket-cloud'; + + return { + settings, + allowStandaloneServer + }; + } +}); diff --git a/packages/rocketchat-setup-wizard/server/lib/getWizardSettings.js b/packages/rocketchat-setup-wizard/server/lib/getWizardSettings.js deleted file mode 100644 index 918c3225bd23..000000000000 --- a/packages/rocketchat-setup-wizard/server/lib/getWizardSettings.js +++ /dev/null @@ -1,9 +0,0 @@ -Meteor.methods({ - getWizardSettings() { - if (RocketChat.authz.hasRole(Meteor.userId(), 'admin') && RocketChat.models && RocketChat.models.Settings) { - return RocketChat.models.Settings.findSetupWizardSettings().fetch(); - } - - throw new Meteor.Error('settings-are-not-ready', 'Settings are not ready'); - } -}); diff --git a/packages/rocketchat-theme/client/imports/components/setup-wizard.css b/packages/rocketchat-theme/client/imports/components/setup-wizard.css index fa2825348d28..3dea99d8cd8d 100644 --- a/packages/rocketchat-theme/client/imports/components/setup-wizard.css +++ b/packages/rocketchat-theme/client/imports/components/setup-wizard.css @@ -1,4 +1,7 @@ .setup-wizard { + --step-color: var(--rc-color-button-primary); + --highlight-color: var(--rc-color-button-primary); + display: flex; width: 100%; @@ -12,6 +15,7 @@ flex: 0 1 350px; margin: 55px 65px 30px 80px; + overflow: hidden; &__header{ display: flex; @@ -125,28 +129,30 @@ } &--active { - color: #1d74f5; + color: var(--rc-color-button-primary); &::before { - color: #1d74f5; - border-color: #1d74f5; + color: var(--rc-color-button-primary); + background-color: transparent; + border-color: var(--rc-color-button-primary); } } &--past { - color: #2f343d; + color: var(--rc-color-primary); &::before { - color: #ffffff; - background-color: #1d74f5; + color: var(--rc-color-content); + background-color: var(--rc-color-button-primary); + border-color: var(--rc-color-button-primary); } &::after { - background-color: #1d74f5 !important; + background-color: var(--rc-color-button-primary) !important; } & .setup-wizard-info__steps-item-bonding { - background-color: #1d74f5; + background-color: var(--rc-color-button-primary); } } @@ -177,8 +183,6 @@ height: calc(100% - 2rem); margin: 1rem 1rem 1rem 0; - padding: 3rem; - border-radius: 2px; background: #ffffff; box-shadow: 0 2px 4px 0 rgba(0,0,0,0.08); @@ -190,6 +194,17 @@ flex-direction: column; width: 350px; + min-height: min-content; + margin: 3rem; + + visibility: hidden; + opacity: 0; + transition: opacity 1s linear; + + &--loaded { + visibility: visible; + opacity: 1; + } } &__header { @@ -259,7 +274,7 @@ cursor: pointer; color: #2f343d; - border: 1px solid #e7ebf2; + border: 2px solid #e7ebf2; border-radius: 2px; @@ -267,6 +282,14 @@ line-height: 1.25rem; + &--selected { + border-color: var(--highlight-color); + } + + &--disabled { + opacity: 0.25; + } + &:first-child { margin-bottom: 1rem; } @@ -292,22 +315,21 @@ position: relative; - border-color: #1d74f5; + border-color: var(--highlight-color); &::before { - position: absolute; - - top: 3px; - left: 3px; + content: ""; - width: 12px; - height: 12px; + position: absolute; - content: ""; + width: 100%; + height: 100%; + background-clip: padding-box; border-radius: 50%; + border: 2px solid transparent; - background-color: #1d74f5; + background-color: var(--highlight-color); } } } @@ -319,7 +341,7 @@ height: 20px; margin: 0 0.5rem; - border: 1px solid #cfd8e6; + border: 2px solid #cfd8e6; border-radius: 50px; } @@ -328,6 +350,63 @@ } } + &-checkbox { + position: relative; + + display: flex; + + margin: 0 -0.5rem 1rem; + + cursor: inherit; + + &-element { + position: absolute; + z-index: -1; + top: 0; + left: 0; + + width: 0; + height: 0; + + &:checked + .setup-wizard-forms__content-register-checkbox-fake { + position: relative; + + border-color: var(--highlight-color); + background-color: var(--highlight-color); + color: var(--rc-color-content); + + .setup-wizard-forms__content-register-checkbox-fake-icon { + display: block; + } + } + } + + &-fake { + display: block; + + width: 16px; + height: 16px; + margin: 2px 0.5rem; + + border: 2px solid #cfd8e6; + border-radius: 2px; + + &-icon { + width: 100%; + height: 100%; + display: none; + } + } + + &-text { + color: #666666; + } + } + + &-items + * { + margin-top: 1rem; + } + &-item { display: flex; @@ -340,13 +419,20 @@ } & .setup-wizard-forms__content-register-radio-icon { - margin: 0 calc(4px + 0.5rem); + min-width: 20px; + width: 20px; + height: 20px; + margin: 0 0.5rem; + align-self: baseline; - font-size: 10px; - } + &--check { + color: var(--highlight-color); + } - & .setup-wizard-forms__content-register-radio-icon--check { - color: #1d74f5; + &--circle { + height: 6px; + margin: 7px 0.5rem; + } } } } @@ -354,8 +440,9 @@ &__footer { display: flex; + flex-direction: row; - margin: 0 -0.5rem; + margin: 0 -0.5rem 2rem -0.5rem; & .rc-button { margin: 0 0.5rem; @@ -390,7 +477,7 @@ letter-spacing: 0; - color: #1d74f5; + color: var(--highlight-color); font-size: 1rem; diff --git a/tests/end-to-end/ui/00-login.js b/tests/end-to-end/ui/00-login.js index 4cd6c69f86e6..3934bfb9da9e 100644 --- a/tests/end-to-end/ui/00-login.js +++ b/tests/end-to-end/ui/00-login.js @@ -123,6 +123,24 @@ describe('[Setup Wizard]', () => { }); }); + describe('[Render - Step 3]', () => { + it('it should have option for registered server', () => { + setupWizard.registeredServer.isExisting().should.be.true; + }); + + it('it should have option for standalone server', () => { + setupWizard.standaloneServer.isExisting().should.be.true; + }); + + it('it should check option for registered server by default', () => { + setupWizard.registeredServer.isSelected().should.be.true; + }); + + after(() => { + setupWizard.goNext(); + }); + }); + describe('[Render - Final Step]', () => { it('it should render "Go to your workspace button', () => { setupWizard.goToWorkspace.waitForVisible(15000); diff --git a/tests/pageobjects/setup-wizard.page.js b/tests/pageobjects/setup-wizard.page.js index 593b9b646e75..f6a652fee44a 100644 --- a/tests/pageobjects/setup-wizard.page.js +++ b/tests/pageobjects/setup-wizard.page.js @@ -14,6 +14,8 @@ class SetupWizard extends Page { get siteName() { return browser.element('input[name="Site_Name"]'); } get language() { return browser.element('select[name="Language"]'); } get serverType() { return browser.element('select[name="Server_Type"]'); } + get registeredServer() { return browser.element('input[name="registerServer"][value="true"]'); } + get standaloneServer() { return browser.element('input[name="registerServer"][value="false"]'); } login() { browser.execute(function(email, password) { From 851c93d07b70f81b90047820419a2b9d273f89d8 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Wed, 4 Jul 2018 10:23:44 -0300 Subject: [PATCH 05/28] [FIX] Outgoing integrations were stopping the oplog tailing sometimes (#11333) When the integrations has a script that access some kind of async (made sync by Fibers) method the VM timeout would be fired after the timeout time and would generate some zoombie fibers cousing the oplog tailing (that uses Fibers) to stop working util a cursor timeout. --- .../server/lib/triggerHandler.js | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/rocketchat-integrations/server/lib/triggerHandler.js b/packages/rocketchat-integrations/server/lib/triggerHandler.js index 887fada828bb..36a9b4777634 100644 --- a/packages/rocketchat-integrations/server/lib/triggerHandler.js +++ b/packages/rocketchat-integrations/server/lib/triggerHandler.js @@ -3,6 +3,8 @@ import _ from 'underscore'; import s from 'underscore.string'; import moment from 'moment'; import vm from 'vm'; +import Fiber from 'fibers'; +import Future from 'fibers/future'; RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler { constructor() { @@ -202,7 +204,15 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler buildSandbox(store = {}) { const sandbox = { - _, s, console, moment, + scriptTimeout(reject) { + return setTimeout(() => reject('timed out'), 3000); + }, + _, + s, + console, + moment, + Fiber, + Promise, Store: { set: (key, val) => store[key] = val, get: (key) => store[key] @@ -303,7 +313,21 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler sandbox.params = params; this.updateHistory({ historyId, step: `execute-script-before-running-${ method }` }); - const result = this.vm.runInNewContext('script[method](params)', sandbox, { timeout: 3000 }); + + const result = Future.fromPromise(this.vm.runInNewContext(` + new Promise((resolve, reject) => { + Fiber(() => { + scriptTimeout(reject); + try { + resolve(script[method](params)) + } catch(e) { + reject(e); + } + }).run(); + }).catch((error) => { throw new Error(error); }); + `, sandbox, { + timeout: 3000 + })).wait(); logger.outgoing.debug(`Script method "${ method }" result of the Integration "${ integration.name }" is:`); logger.outgoing.debug(result); From ec377bde9252bd6fd1305fc4c1d5ea7512d37212 Mon Sep 17 00:00:00 2001 From: "Pierre H. Lehnen" Date: Wed, 4 Jul 2018 14:02:16 -0300 Subject: [PATCH 06/28] Fixes issues with SAML attribute mapping (#11315) --- packages/meteor-accounts-saml/saml_utils.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/meteor-accounts-saml/saml_utils.js b/packages/meteor-accounts-saml/saml_utils.js index e1274111ba67..d749f02e9ddc 100644 --- a/packages/meteor-accounts-saml/saml_utils.js +++ b/packages/meteor-accounts-saml/saml_utils.js @@ -395,8 +395,7 @@ SAML.prototype.validateResponse = function(samlResponse, relayState, callback) { if (attributes) { attributes.forEach(function(attribute) { const value = self.getElement(attribute, 'AttributeValue'); - let key = attribute.$.Name.value; - key=key.replace(/\./g, '-'); + const key = attribute.$.Name.value; if (typeof value[0] === 'string') { profile[key] = value[0]; } else { @@ -422,6 +421,16 @@ SAML.prototype.validateResponse = function(samlResponse, relayState, callback) { console.log(`NameID: ${ JSON.stringify(profile) }`); } + const profileKeys = Object.keys(profile); + for (let i = 0; i < profileKeys.length; i++) { + const key = profileKeys[i]; + + if (key.match(/\./)) { + profile[key.replace(/\./g, '-')] = profile[key]; + delete profile[key]; + } + } + callback(null, profile, false); } else { const logoutResponse = self.getElement(doc, 'LogoutResponse'); From 64d969f4c8bd905dd8a8f50f84bb78aef837a9a1 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Wed, 4 Jul 2018 14:02:43 -0300 Subject: [PATCH 07/28] [FIX] Some updates were returning errors when based on queries with position operators (#11335) --- packages/rocketchat-lib/server/models/_BaseDb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rocketchat-lib/server/models/_BaseDb.js b/packages/rocketchat-lib/server/models/_BaseDb.js index 60dee3248d2b..b93f3e917701 100644 --- a/packages/rocketchat-lib/server/models/_BaseDb.js +++ b/packages/rocketchat-lib/server/models/_BaseDb.js @@ -160,7 +160,7 @@ class ModelsBaseDb extends EventEmitter { } updateHasPositionalOperator(update) { - return Object.keys(update).some(key => key.includes('.$') || (!Match.test(update[key], Object) && this.updateHasPositionalOperator(update[key]))); + return Object.keys(update).some(key => key.includes('.$') || (Match.test(update[key], Object) && this.updateHasPositionalOperator(update[key]))); } processOplogRecord(action) { From 9a13ac50426444aa789a61791f8d3f10b3ea3c79 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Wed, 4 Jul 2018 18:25:51 -0300 Subject: [PATCH 08/28] Bump version to 0.67.0-develop --- .sandstorm/sandstorm-pkgdef.capnp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sandstorm/sandstorm-pkgdef.capnp b/.sandstorm/sandstorm-pkgdef.capnp index b8b8cabc1b77..56ea6cb64f71 100644 --- a/.sandstorm/sandstorm-pkgdef.capnp +++ b/.sandstorm/sandstorm-pkgdef.capnp @@ -19,7 +19,7 @@ const pkgdef :Spk.PackageDefinition = ( appTitle = (defaultText = "Rocket.Chat"), - appVersion = 78, # Increment this for every release. + appVersion = 79, # Increment this for every release. appMarketingVersion = (defaultText = "0.67.0-develop"), # Human-readable representation of appVersion. Should match the way you From b0e341c9ff99a1ee9ac43cabfc578fc0181655a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20Gl=C3=B6e?= Date: Thu, 5 Jul 2018 01:42:06 +0200 Subject: [PATCH 09/28] [FIX] Loading avatar suggestions with no internet connection --- .../client/accountProfile.html | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/rocketchat-ui-account/client/accountProfile.html b/packages/rocketchat-ui-account/client/accountProfile.html index 32761147d9c1..7e027d4e3910 100644 --- a/packages/rocketchat-ui-account/client/accountProfile.html +++ b/packages/rocketchat-ui-account/client/accountProfile.html @@ -33,40 +33,40 @@ {{/unless}} {{#if allowAvatarChange}} - {{#if suggestions.ready}} -
-
- {{> avatar username=initialsUsername }} -
-
- - -
-
- -
+
+
+ {{> avatar username=initialsUsername }} +
+
+ + +
+
+ +
+ {{#if suggestions.ready}} {{#each service in services}} {{ > avatarService service}} {{/each}} -
- - + {{else}} +
+ {{_ "Loading_suggestion"}}
+ {{/if}} +
+ +
- {{else}} -
- {{_ "Loading_suggestion"}} -
- {{/if}} +
{{/if}}
From ae150fb61f0426f3ec7fcf324e20f1b19fa34287 Mon Sep 17 00:00:00 2001 From: Nikhil Kaushik Date: Thu, 5 Jul 2018 22:19:58 +0530 Subject: [PATCH 10/28] [FIX] Parse inline code without space before initial backtick (#9754) --- packages/rocketchat-markdown/parser/original/code.js | 4 ++-- packages/rocketchat-markdown/tests/client.tests.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/rocketchat-markdown/parser/original/code.js b/packages/rocketchat-markdown/parser/original/code.js index dc69dcc9f590..fadc54ac1dd1 100644 --- a/packages/rocketchat-markdown/parser/original/code.js +++ b/packages/rocketchat-markdown/parser/original/code.js @@ -8,12 +8,12 @@ import hljs from 'highlight.js'; const inlinecode = (message) => { // Support `text` - return message.html = message.html.replace(/(^|>|[ >_*~])\`([^`\r\n]+)\`([<_*~]|\B|\b|$)/gm, (match, p1, p2, p3) => { + return message.html = message.html.replace(/\`([^`\r\n]+)\`([<_*~]|\B|\b|$)/gm, (match, p1, p2) => { const token = ` =!=${ Random.id() }=!=`; message.tokens.push({ token, - text: `${ p1 }\`${ p2 }\`${ p3 }`, + text: `\`${ p1 }\`${ p2 }`, noHtml: match }); diff --git a/packages/rocketchat-markdown/tests/client.tests.js b/packages/rocketchat-markdown/tests/client.tests.js index fa376d6bb03d..ef30feab9854 100644 --- a/packages/rocketchat-markdown/tests/client.tests.js +++ b/packages/rocketchat-markdown/tests/client.tests.js @@ -200,8 +200,8 @@ const inlinecode = { 'End `code`': `End ${ inlinecodeWrapper('code') }`, 'Middle `code` middle': `Middle ${ inlinecodeWrapper('code') } middle`, '`code`begin': `${ inlinecodeWrapper('code') }begin`, - 'End`code`': 'End`code`', - 'Middle`code`middle': 'Middle`code`middle' + 'End`code`': `End${ inlinecodeWrapper('code') }`, + 'Middle`code`middle': `Middle${ inlinecodeWrapper('code') }middle` }; const code = { From d08d48cd0dc868f58fe7df27839913212c58a369 Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Thu, 5 Jul 2018 14:35:14 -0300 Subject: [PATCH 11/28] [IMPROVE] Stop sort callbacks on run (#11330) --- packages/rocketchat-lib/lib/callbacks.js | 107 +++++++++++------------ packages/rocketchat-lib/lib/promises.js | 26 ++---- 2 files changed, 62 insertions(+), 71 deletions(-) diff --git a/packages/rocketchat-lib/lib/callbacks.js b/packages/rocketchat-lib/lib/callbacks.js index a1a2fee70878..d9b644074106 100644 --- a/packages/rocketchat-lib/lib/callbacks.js +++ b/packages/rocketchat-lib/lib/callbacks.js @@ -26,6 +26,7 @@ RocketChat.callbacks.priority = { LOW: 1000 }; +const getHooks = hookName => RocketChat.callbacks[hookName] || []; /* * Add a callback function to a hook @@ -33,24 +34,26 @@ RocketChat.callbacks.priority = { * @param {Function} callback - The callback function */ -RocketChat.callbacks.add = function(hook, callback, priority, id) { - if (priority == null) { - priority = RocketChat.callbacks.priority.MEDIUM; - } +RocketChat.callbacks.add = function(hook, callback, priority, id = Random.id()) { if (!_.isNumber(priority)) { priority = RocketChat.callbacks.priority.MEDIUM; } callback.priority = priority; - callback.id = id || Random.id(); - RocketChat.callbacks[hook] = RocketChat.callbacks[hook] || []; + callback.id = id; + RocketChat.callbacks[hook] = getHooks(hook); + if (RocketChat.callbacks.showTime === true) { const err = new Error; callback.stack = err.stack; } + if (RocketChat.callbacks[hook].find((cb) => cb.id === callback.id)) { return; } RocketChat.callbacks[hook].push(callback); + RocketChat.callbacks[hook] = _.sortBy(RocketChat.callbacks[hook], function(callback) { + return callback.priority || RocketChat.callbacks.priority.MEDIUM; + }); }; @@ -60,8 +63,8 @@ RocketChat.callbacks.add = function(hook, callback, priority, id) { * @param {string} id - The callback's id */ -RocketChat.callbacks.remove = function(hookName, id) { - RocketChat.callbacks[hookName] = _.reject(RocketChat.callbacks[hookName], (callback) => callback.id === id); +RocketChat.callbacks.remove = function(hook, id) { + RocketChat.callbacks[hook] = getHooks(hook).filter(callback => callback.id !== id); }; @@ -75,59 +78,56 @@ RocketChat.callbacks.remove = function(hookName, id) { RocketChat.callbacks.run = function(hook, item, constant) { const callbacks = RocketChat.callbacks[hook]; - if (callbacks && callbacks.length) { + if (!callbacks || !callbacks.length) { + return item; + } + + let rocketchatHooksEnd; + if (Meteor.isServer) { + rocketchatHooksEnd = RocketChat.metrics.rocketchatHooks.startTimer({hook, callbacks_length: callbacks.length}); + } - let rocketchatHooksEnd; + let totalTime = 0; + const result = callbacks.reduce(function(result, callback) { + let rocketchatCallbacksEnd; if (Meteor.isServer) { - rocketchatHooksEnd = RocketChat.metrics.rocketchatHooks.startTimer({hook, callbacks_length: callbacks.length}); + rocketchatCallbacksEnd = RocketChat.metrics.rocketchatCallbacks.startTimer({hook, callback: callback.id}); } - - let totalTime = 0; - const result = _.sortBy(callbacks, function(callback) { - return callback.priority || RocketChat.callbacks.priority.MEDIUM; - }).reduce(function(result, callback) { - let rocketchatCallbacksEnd; - if (Meteor.isServer) { - rocketchatCallbacksEnd = RocketChat.metrics.rocketchatCallbacks.startTimer({hook, callback: callback.id}); - } - let time = 0; - if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { - time = Date.now(); - } - const callbackResult = callback(result, constant); - if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { - const currentTime = Date.now() - time; - totalTime += currentTime; - if (RocketChat.callbacks.showTime === true) { - if (Meteor.isServer) { - rocketchatCallbacksEnd(); - RocketChat.statsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]); - } else { - let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n'); - stack = stack && stack[2] && (stack[2].match(/\(.+\)/)||[])[0]; - console.log(String(currentTime), hook, callback.id, stack); - } + const time = RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true ? Date.now() : 0; + + const callbackResult = callback(result, constant); + + if (RocketChat.callbacks.showTime === true || RocketChat.callbacks.showTotalTime === true) { + const currentTime = Date.now() - time; + totalTime += currentTime; + if (RocketChat.callbacks.showTime === true) { + if (Meteor.isServer) { + rocketchatCallbacksEnd(); + RocketChat.statsTracker.timing('callbacks.time', currentTime, [`hook:${ hook }`, `callback:${ callback.id }`]); + } else { + let stack = callback.stack && typeof callback.stack.split === 'function' && callback.stack.split('\n'); + stack = stack && stack[2] && (stack[2].match(/\(.+\)/)||[])[0]; + console.log(String(currentTime), hook, callback.id, stack); } } - return (typeof callbackResult === 'undefined') ? result : callbackResult; - }, item); + } + return (typeof callbackResult === 'undefined') ? result : callbackResult; + }, item); + if (Meteor.isServer) { + rocketchatHooksEnd(); + } + + if (RocketChat.callbacks.showTotalTime === true) { if (Meteor.isServer) { - rocketchatHooksEnd(); + RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]); + } else { + console.log(`${ hook }:`, totalTime); } + } - if (RocketChat.callbacks.showTotalTime === true) { - if (Meteor.isServer) { - RocketChat.statsTracker.timing('callbacks.totalTime', totalTime, [`hook:${ hook }`]); - } else { - console.log(`${ hook }:`, totalTime); - } - } + return result; - return result; - } else { - return item; - } }; @@ -142,9 +142,8 @@ RocketChat.callbacks.runAsync = function(hook, item, constant) { const callbacks = RocketChat.callbacks[hook]; if (Meteor.isServer && callbacks && callbacks.length) { Meteor.defer(function() { - _.sortBy(callbacks, (callback) => callback.priority || RocketChat.callbacks.priority.MEDIUM).forEach((callback) => callback(item, constant)); + callbacks.forEach(callback => callback(item, constant)); }); - } else { - return item; } + return item; }; diff --git a/packages/rocketchat-lib/lib/promises.js b/packages/rocketchat-lib/lib/promises.js index 6a52e562ae91..2b0244629c15 100644 --- a/packages/rocketchat-lib/lib/promises.js +++ b/packages/rocketchat-lib/lib/promises.js @@ -18,6 +18,7 @@ RocketChat.promises.priority = { LOW: 1000 }; +const getHook = hookName => RocketChat.promises[hookName] || []; /* * Add a callback function to a hook @@ -26,14 +27,14 @@ RocketChat.promises.priority = { */ RocketChat.promises.add = function(hook, callback, p = RocketChat.promises.priority.MEDIUM, id) { - const priority = !_.isNumber(p) ? RocketChat.promises.priority.MEDIUM : p; - callback.priority = priority; + callback.priority = _.isNumber(p) ? p : RocketChat.promises.priority.MEDIUM; callback.id = id || Random.id(); - RocketChat.promises[hook] = RocketChat.promises[hook] || []; + RocketChat.promises[hook] = getHook(hook); if (RocketChat.promises[hook].find(cb => cb.id === callback.id)) { return; } RocketChat.promises[hook].push(callback); + RocketChat.promises[hook] = _.sortBy(RocketChat.promises[hook], callback => callback.priority || RocketChat.promises.priority.MEDIUM); }; @@ -43,8 +44,8 @@ RocketChat.promises.add = function(hook, callback, p = RocketChat.promises.prior * @param {string} id - The callback's id */ -RocketChat.promises.remove = function(hookName, id) { - RocketChat.promises[hookName] = _.reject(RocketChat.promises[hookName], (callback) => callback.id === id); +RocketChat.promises.remove = function(hook, id) { + RocketChat.promises[hook] = getHook(hook).filter(callback => callback.id !== id); }; @@ -57,16 +58,11 @@ RocketChat.promises.remove = function(hookName, id) { */ RocketChat.promises.run = function(hook, item, constant) { - let callbacks = RocketChat.promises[hook]; + const callbacks = RocketChat.promises[hook]; if (callbacks == null || callbacks.length === 0) { return Promise.resolve(item); } - callbacks = _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM); - return callbacks.reduce(function(previousPromise, callback) { - return new Promise(function(resolve, reject) { - return previousPromise.then((result) => callback(result, constant).then(resolve, reject)); - }); - }, Promise.resolve(item)); + return callbacks.reduce((previousPromise, callback) => previousPromise.then(result => callback(result, constant)), Promise.resolve(item)); }; @@ -82,9 +78,5 @@ RocketChat.promises.runAsync = function(hook, item, constant) { if (!Meteor.isServer || callbacks == null || callbacks.length === 0) { return item; } - Meteor.defer(() => { - _.sortBy(callbacks, (callback) => callback.priority || RocketChat.promises.priority.MEDIUM).forEach(function(callback) { - callback(item, constant); - }); - }); + Meteor.defer(() => callbacks.forEach(callback => callback(item, constant))); }; From b4e9a2efb5699b7c840aa9c2f8bb63b9c3c298c4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Thu, 5 Jul 2018 15:51:27 -0300 Subject: [PATCH 12/28] [FIX] Message attachment's fields with different sizes (#11342) --- .../client/stylesheets/messageAttachments.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.css b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.css index 705008a24cf0..446b8b41b692 100644 --- a/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.css +++ b/packages/rocketchat-message-attachments/client/stylesheets/messageAttachments.css @@ -87,6 +87,7 @@ html.rtl .attachment { } & .attachment-fields { + display: flex; margin-top: 4px; & .attachment-field { @@ -103,10 +104,6 @@ html.rtl .attachment { } } - & .attachment-field ~ .attachment-field { - margin-top: 8px; - } - & .attachment-thumb { padding-top: 5px; padding-right: 10px; From f0f7ef2f1c15b535a40d374d9d18d3f061a4e523 Mon Sep 17 00:00:00 2001 From: Justin Ribeiro Date: Thu, 5 Jul 2018 12:01:46 -0700 Subject: [PATCH 13/28] [FIX] web app manifest errors as reported by Chrome DevTools (#9991) @RocketChat/core Closes #9990 This pull request properly brings the web app manifest up-to-date to the current specification and resolves the incorrect start_url origin and the path to the broken images as seen in this screenshot. This resolves the unwanted and incorrect behavior experienced in both Google Chrome and Mozilla Firefox for Android. ![image](https://user-images.githubusercontent.com/643503/36929663-052fe33c-1e49-11e8-8a68-3d8e666d30e8.png) --- public/images/manifest.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/public/images/manifest.json b/public/images/manifest.json index 36be779fed28..b846cad037e9 100644 --- a/public/images/manifest.json +++ b/public/images/manifest.json @@ -1,17 +1,19 @@ { "name": "Rocket.Chat", + "short_name": "Rocket.Chat", + "background_color": "#fff", "icons": [ { - "src": "assets\/favicon_192.png", + "src": "/assets/favicon_192.png", "sizes": "192x192", - "type": "image\/png" + "type": "image/png" }, { - "src": "assets\/favicon_512.png", + "src": "/assets/favicon_512.png", "sizes": "512x512", - "type": "image\/png" + "type": "image/png" } ], - "start_url": "https:\/\/rocket.chat\/home", + "start_url": "/home?homescreen", "display": "standalone" } From 3ebe15d97b11acfb93505b99ea699db9bc216b26 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Thu, 5 Jul 2018 19:08:02 -0300 Subject: [PATCH 14/28] [FIX] Message popup responsiveness in slash commands (#11313) * Fix icons in channels message popup * Fix descriptions in slash commands message popup * Add scrolling in message popup --- .../client/imports/general/base_old.css | 31 ++++++++++++++++--- .../client/popup/messagePopup.js | 2 ++ .../client/popup/messagePopupChannel.html | 2 +- .../client/popup/messagePopupChannel.js | 2 +- .../popup/messagePopupSlashCommand.html | 8 +++-- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/packages/rocketchat-theme/client/imports/general/base_old.css b/packages/rocketchat-theme/client/imports/general/base_old.css index 5bf0d8970a5a..4747c4590d1b 100644 --- a/packages/rocketchat-theme/client/imports/general/base_old.css +++ b/packages/rocketchat-theme/client/imports/general/base_old.css @@ -2614,6 +2614,33 @@ .rc-old .message-popup-position { position: relative; + + .message-popup { + display: flex; + flex-direction: column; + align-items: stretch; + max-height: 20rem; + + .message-popup-items { + overflow-y: auto; + + .popup-slash-command { + display: flex; + flex-direction: row; + flex-wrap: wrap; + + &-format { + flex-grow: 1; + } + + &-description { + flex-grow: 2; + font-style: italic; + text-align: right; + } + } + } + } } .rc-old .message-popup-items.preview-items { @@ -2773,10 +2800,6 @@ border-radius: 10px; } -.rc-old .popup-slash-command-description { - float: right; -} - .messages-box { position: relative; diff --git a/packages/rocketchat-ui-message/client/popup/messagePopup.js b/packages/rocketchat-ui-message/client/popup/messagePopup.js index db9ed11f1d3a..e04b317e8806 100644 --- a/packages/rocketchat-ui-message/client/popup/messagePopup.js +++ b/packages/rocketchat-ui-message/client/popup/messagePopup.js @@ -81,6 +81,7 @@ Template.messagePopup.onCreated(function() { if (previous != null) { current.className = current.className.replace(/\sselected/, '').replace('sidebar-item__popup-active', ''); previous.className += ' selected sidebar-item__popup-active'; + previous.scrollIntoView(false); return template.value.set(previous.getAttribute('data-id')); } }; @@ -90,6 +91,7 @@ Template.messagePopup.onCreated(function() { if (next && next.classList.contains('popup-item')) { current.className = current.className.replace(/\sselected/, '').replace('sidebar-item__popup-active', ''); next.className += ' selected sidebar-item__popup-active'; + next.scrollIntoView(false); return template.value.set(next.getAttribute('data-id')); } }; diff --git a/packages/rocketchat-ui-message/client/popup/messagePopupChannel.html b/packages/rocketchat-ui-message/client/popup/messagePopupChannel.html index fc2eae0c225d..52ff78339509 100644 --- a/packages/rocketchat-ui-message/client/popup/messagePopupChannel.html +++ b/packages/rocketchat-ui-message/client/popup/messagePopupChannel.html @@ -1,4 +1,4 @@ diff --git a/packages/rocketchat-ui-message/client/popup/messagePopupChannel.js b/packages/rocketchat-ui-message/client/popup/messagePopupChannel.js index a3836b1fa177..8686c9e6b65e 100644 --- a/packages/rocketchat-ui-message/client/popup/messagePopupChannel.js +++ b/packages/rocketchat-ui-message/client/popup/messagePopupChannel.js @@ -1,5 +1,5 @@ Template.messagePopupChannel.helpers({ - icon() { + channelIcon() { return RocketChat.roomTypes.getIcon(this.t); } }); diff --git a/packages/rocketchat-ui-message/client/popup/messagePopupSlashCommand.html b/packages/rocketchat-ui-message/client/popup/messagePopupSlashCommand.html index c1f1ec4dd813..f23ab768ea61 100644 --- a/packages/rocketchat-ui-message/client/popup/messagePopupSlashCommand.html +++ b/packages/rocketchat-ui-message/client/popup/messagePopupSlashCommand.html @@ -1,4 +1,6 @@ \ No newline at end of file + + From ff112f889d495d2cb32eb6c5a7b88aa23a5e9d93 Mon Sep 17 00:00:00 2001 From: Rodrigo Nascimento Date: Thu, 5 Jul 2018 19:12:03 -0300 Subject: [PATCH 15/28] Send setting Allow_Marketing_Emails to statistics collector (#11359) --- packages/rocketchat-statistics/server/functions/get.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/rocketchat-statistics/server/functions/get.js b/packages/rocketchat-statistics/server/functions/get.js index d3eca9f5a680..1a32dafb1389 100644 --- a/packages/rocketchat-statistics/server/functions/get.js +++ b/packages/rocketchat-statistics/server/functions/get.js @@ -11,7 +11,8 @@ const wizardFields = [ 'Website', 'Site_Name', 'Language', - 'Server_Type' + 'Server_Type', + 'Allow_Marketing_Emails' ]; RocketChat.statistics.get = function _getStatistics() { From 050d06a3dbdab7b2b27f984674bcb09848a62051 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Thu, 5 Jul 2018 23:05:29 -0300 Subject: [PATCH 16/28] Fix migration 125 checking for settings field (#11364) --- server/startup/migrations/v125.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/startup/migrations/v125.js b/server/startup/migrations/v125.js index d191feffd246..4f8ecfab4f3f 100644 --- a/server/startup/migrations/v125.js +++ b/server/startup/migrations/v125.js @@ -1,7 +1,9 @@ RocketChat.Migrations.add({ version: 125, up() { - RocketChat.models.Users.update({}, { + RocketChat.models.Users.update({ + 'settings.preferences.groupByType': { $exists: true } + }, { $rename: { 'settings.preferences.groupByType': 'settings.preferences.sidebarGroupByType' } From f635293852cc6b2eb9cffd66815096e73c815f28 Mon Sep 17 00:00:00 2001 From: Aaron Ogle Date: Thu, 5 Jul 2018 21:49:11 -0500 Subject: [PATCH 17/28] Remove file snap store doesn't like (#11365) --- .snapcraft/resources/prepareRocketChat | 1 + 1 file changed, 1 insertion(+) diff --git a/.snapcraft/resources/prepareRocketChat b/.snapcraft/resources/prepareRocketChat index 2251551e6d0b..cd653b6fcfc2 100755 --- a/.snapcraft/resources/prepareRocketChat +++ b/.snapcraft/resources/prepareRocketChat @@ -19,6 +19,7 @@ npm i if [[ $(uname -m) == "x86_64" ]] then cp -r npm/node_modules/grpc/src/node/extension_binary/node-v57-linux-x64-glibc npm/node_modules/grpc/src/node/extension_binary/node-v57-linux-x64-unknown + rm npm/node_modules/grpc/node_modules/tar/lib/.unpack.js.swp fi # sharp needs execution stack removed - https://forum.snapcraft.io/t/snap-and-executable-stacks/1812 From 830607da6450976c3b63283fe6f28effdb2920f5 Mon Sep 17 00:00:00 2001 From: Tasso Evangelista Date: Fri, 6 Jul 2018 00:01:22 -0300 Subject: [PATCH 18/28] [FIX] SVG icons code (#11319) This pull request aims to format the SVG file containing the UI icons. - [x] Fix indentation - [x] Sort icons alphabetically by `id` - [x] Recover icons lost in c1a5d5785f4003016c8faa1daa1c57691bfdcff4 --- .../rocketchat-ui-master/public/icons.svg | 927 +++++++++--------- 1 file changed, 473 insertions(+), 454 deletions(-) diff --git a/packages/rocketchat-ui-master/public/icons.svg b/packages/rocketchat-ui-master/public/icons.svg index f0299fa6c5ff..eed97022f676 100644 --- a/packages/rocketchat-ui-master/public/icons.svg +++ b/packages/rocketchat-ui-master/public/icons.svg @@ -1,456 +1,475 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 22d1caeb24d61cb6d36c2c8abacf89c7b69f34c8 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Fri, 6 Jul 2018 00:22:24 -0300 Subject: [PATCH 19/28] [FIX] Livechat not sending desktop notifications (#11266) --- packages/rocketchat-lib/lib/RoomTypeConfig.js | 39 +++++++++++++++++++ .../rocketchat-lib/lib/RoomTypesCommon.js | 8 ++++ .../rocketchat-lib/lib/roomTypes/direct.js | 19 +++++++++ .../server/functions/notifications/desktop.js | 14 +------ .../server/lib/sendNotificationsOnMessage.js | 2 +- .../rocketchat-livechat/client/roomType.js | 3 ++ .../LivechatRoomType.js} | 6 +-- packages/rocketchat-livechat/package.js | 5 ++- .../rocketchat-livechat/server/roomType.js | 25 ++++++++++++ 9 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 packages/rocketchat-livechat/client/roomType.js rename packages/rocketchat-livechat/{roomType.js => imports/LivechatRoomType.js} (88%) create mode 100644 packages/rocketchat-livechat/server/roomType.js diff --git a/packages/rocketchat-lib/lib/RoomTypeConfig.js b/packages/rocketchat-lib/lib/RoomTypeConfig.js index 7ab4efcc7289..06d8dcfe8ab1 100644 --- a/packages/rocketchat-lib/lib/RoomTypeConfig.js +++ b/packages/rocketchat-lib/lib/RoomTypeConfig.js @@ -150,6 +150,16 @@ export class RoomTypeConfig { return true; } + /** + * Return a room's name + * + * @abstract + * @return {string} Room's name according to it's type + */ + roomName(/* room */) { + return ''; + } + canBeCreated() { return Meteor.isServer ? RocketChat.authz.hasAtLeastOnePermission(Meteor.userId(), [`create-${ this._identifier }`]) : @@ -203,4 +213,33 @@ export class RoomTypeConfig { getUiText(/* context */) { return ''; } + + /** + * Returns the full object of message sender + * @param {string} senderId Sender's _id + * @return {object} Sender's object from db + */ + getMsgSender(senderId) { + return Meteor.isServer ? RocketChat.models.Users.findOneById(senderId) : {}; + } + + /** + * Returns details to use on notifications + * + * @param {object} room + * @param {object} user + * @param {string} notificationMessage + * @return {object} Notification details + */ + getNotificationDetails(room, user, notificationMessage) { + if (!Meteor.isServer) { + return {}; + } + + const title = `#${ this.roomName(room) }`; + + const text = `${ RocketChat.settings.get('UI_Use_Real_Name') ? user.name : user.username }: ${ notificationMessage }`; + + return { title, text }; + } } diff --git a/packages/rocketchat-lib/lib/RoomTypesCommon.js b/packages/rocketchat-lib/lib/RoomTypesCommon.js index e7cead3d9dde..6c5ba9a08979 100644 --- a/packages/rocketchat-lib/lib/RoomTypesCommon.js +++ b/packages/rocketchat-lib/lib/RoomTypesCommon.js @@ -90,4 +90,12 @@ export class RoomTypesCommon { return FlowRouter.go(this.roomTypes[roomType].route.name, routeData, queryParams); } + + /** + * @param {string} roomType room type (e.g.: c (for channels), d (for direct channels)) + * @param {RoomTypeConfig} roomConfig room's type configuration + */ + getConfig(roomType) { + return this.roomTypes[roomType]; + } } diff --git a/packages/rocketchat-lib/lib/roomTypes/direct.js b/packages/rocketchat-lib/lib/roomTypes/direct.js index f1ba44c1cd02..9145751cdd16 100644 --- a/packages/rocketchat-lib/lib/roomTypes/direct.js +++ b/packages/rocketchat-lib/lib/roomTypes/direct.js @@ -111,4 +111,23 @@ export class DirectMessageRoomType extends RoomTypeConfig { return ''; } } + + /** + * Returns details to use on notifications + * + * @param {object} room + * @param {object} user + * @param {string} notificationMessage + * @return {object} Notification details + */ + getNotificationDetails(room, user, notificationMessage) { + if (!Meteor.isServer) { + return {}; + } + + const title = RocketChat.settings.get('UI_Use_Real_Name') ? user.name : `@${ user.username }`; + const text = notificationMessage; + + return { title, text }; + } } diff --git a/packages/rocketchat-lib/server/functions/notifications/desktop.js b/packages/rocketchat-lib/server/functions/notifications/desktop.js index bb58be4ec0ba..2b3cde4f3a61 100644 --- a/packages/rocketchat-lib/server/functions/notifications/desktop.js +++ b/packages/rocketchat-lib/server/functions/notifications/desktop.js @@ -16,19 +16,7 @@ export function notifyDesktopUser({ duration, notificationMessage }) { - const UI_Use_Real_Name = RocketChat.settings.get('UI_Use_Real_Name') === true; - - let title = ''; - let text = ''; - if (room.t === 'd') { - title = UI_Use_Real_Name ? user.name : `@${ user.username }`; - text = notificationMessage; - } else if (room.name) { - title = `#${ room.name }`; - text = `${ UI_Use_Real_Name ? user.name : user.username }: ${ notificationMessage }`; - } else { - return; - } + const { title, text } = RocketChat.roomTypes.getConfig(room.t).getNotificationDetails(room, user, notificationMessage); RocketChat.metrics.notificationsSent.inc({ notification_type: 'desktop' }); RocketChat.Notifications.notifyUser(userId, 'notification', { diff --git a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js index 1f33a449b826..58ac97fe91f3 100644 --- a/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js +++ b/packages/rocketchat-lib/server/lib/sendNotificationsOnMessage.js @@ -157,7 +157,7 @@ function sendAllNotifications(message, room) { return message; } - const sender = (room.t !== 'l') ? RocketChat.models.Users.findOneById(message.u._id) : room.v; + const sender = RocketChat.roomTypes.getConfig(room.t).getMsgSender(message.u._id); if (!sender) { return message; } diff --git a/packages/rocketchat-livechat/client/roomType.js b/packages/rocketchat-livechat/client/roomType.js new file mode 100644 index 000000000000..39927a740195 --- /dev/null +++ b/packages/rocketchat-livechat/client/roomType.js @@ -0,0 +1,3 @@ +import LivechatRoomType from '../imports/LivechatRoomType'; + +RocketChat.roomTypes.add(new LivechatRoomType()); diff --git a/packages/rocketchat-livechat/roomType.js b/packages/rocketchat-livechat/imports/LivechatRoomType.js similarity index 88% rename from packages/rocketchat-livechat/roomType.js rename to packages/rocketchat-livechat/imports/LivechatRoomType.js index a33231c19acf..8914b0de9c4a 100644 --- a/packages/rocketchat-livechat/roomType.js +++ b/packages/rocketchat-livechat/imports/LivechatRoomType.js @@ -1,5 +1,5 @@ /* globals openRoom, LivechatInquiry */ -import {RoomSettingsEnum, RoomTypeConfig, RoomTypeRouteConfig, UiTextContext} from 'meteor/rocketchat:lib'; +import { RoomSettingsEnum, RoomTypeConfig, RoomTypeRouteConfig, UiTextContext } from 'meteor/rocketchat:lib'; class LivechatRoomRoute extends RoomTypeRouteConfig { constructor() { @@ -20,7 +20,7 @@ class LivechatRoomRoute extends RoomTypeRouteConfig { } } -class LivechatRoomType extends RoomTypeConfig { +export default class LivechatRoomType extends RoomTypeConfig { constructor() { super({ identifier: 'l', @@ -82,5 +82,3 @@ class LivechatRoomType extends RoomTypeConfig { } } } - -RocketChat.roomTypes.add(new LivechatRoomType()); diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js index 85745d4c6e9e..8f25b235f225 100644 --- a/packages/rocketchat-livechat/package.js +++ b/packages/rocketchat-livechat/package.js @@ -46,10 +46,10 @@ Package.onUse(function(api) { api.addFiles('server/visitorStatus.js', 'server'); api.addFiles('permissions.js', 'server'); api.addFiles('messageTypes.js'); - api.addFiles('roomType.js'); api.addFiles('config.js', 'server'); + api.addFiles('client/roomType.js', 'client'); api.addFiles('client/ui.js', 'client'); api.addFiles('client/route.js', 'client'); @@ -131,6 +131,9 @@ Package.onUse(function(api) { api.addFiles('client/views/app/triggers/livechatTriggerCondition.html', 'client'); api.addFiles('client/views/app/triggers/livechatTriggerCondition.js', 'client'); + // startup + api.addFiles('server/roomType.js', 'server'); + // hooks api.addFiles('server/hooks/externalMessage.js', 'server'); api.addFiles('server/hooks/leadCapture.js', 'server'); diff --git a/packages/rocketchat-livechat/server/roomType.js b/packages/rocketchat-livechat/server/roomType.js new file mode 100644 index 000000000000..ba36fffbd75b --- /dev/null +++ b/packages/rocketchat-livechat/server/roomType.js @@ -0,0 +1,25 @@ +import LivechatRoomType from '../imports/LivechatRoomType'; +import LivechatVisitors from './models/LivechatVisitors'; + +class LivechatRoomTypeServer extends LivechatRoomType { + getMsgSender(senderId) { + return LivechatVisitors.findOneById(senderId); + } + + /** + * Returns details to use on notifications + * + * @param {object} room + * @param {object} user + * @param {string} notificationMessage + * @return {object} Notification details + */ + getNotificationDetails(room, user, notificationMessage) { + const title = `[livechat] ${ this.roomName(room) }`; + const text = notificationMessage; + + return { title, text }; + } +} + +RocketChat.roomTypes.add(new LivechatRoomTypeServer()); From 801445594217f6866c8996a521ff03027221a681 Mon Sep 17 00:00:00 2001 From: Renato Becker Date: Fri, 6 Jul 2018 17:37:49 -0300 Subject: [PATCH 20/28] [NEW] Additional Livechat iFrame API's (#10918) --- package-lock.json | 7 +- .../.app/client/lib/_livechat.js | 15 ++++ .../.app/client/lib/chatMessages.js | 8 +++ .../.app/client/lib/hooks.js | 28 ++++++++ .../.app/client/lib/msgTyping.js | 5 ++ .../.app/client/views/livechatWindow.js | 36 +++++++--- .../.app/client/views/register.html | 8 +-- .../.app/client/views/register.js | 16 +++-- .../.app/imports/client/visitor.js | 72 ++++++++++++++++++- .../assets/rocket-livechat.js | 20 ++++++ .../server/methods/loginByToken.js | 6 +- .../server/methods/registerGuest.js | 7 ++ 12 files changed, 203 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1587fdbdda34..bcecc3b632dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4481,6 +4481,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "optional": true, "requires": { "prr": "1.0.1" } @@ -9490,7 +9491,8 @@ "natives": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.4.tgz", - "integrity": "sha512-Q29yeg9aFKwhLVdkTAejM/HvYG0Y1Am1+HUkFQGn5k2j8GS+v60TVmZh6nujpEAj/qql+wGUrlryO8bF+b1jEg==" + "integrity": "sha512-Q29yeg9aFKwhLVdkTAejM/HvYG0Y1Am1+HUkFQGn5k2j8GS+v60TVmZh6nujpEAj/qql+wGUrlryO8bF+b1jEg==", + "optional": true }, "natural-compare": { "version": "1.4.0", @@ -11222,7 +11224,8 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "optional": true }, "pseudomap": { "version": "1.0.2", diff --git a/packages/rocketchat-livechat/.app/client/lib/_livechat.js b/packages/rocketchat-livechat/.app/client/lib/_livechat.js index 541af4c2a826..13aae330ea16 100644 --- a/packages/rocketchat-livechat/.app/client/lib/_livechat.js +++ b/packages/rocketchat-livechat/.app/client/lib/_livechat.js @@ -34,6 +34,9 @@ this.Livechat = new (class Livechat { this.stream = new Meteor.Streamer('livechat-room'); + this._guestName = new ReactiveVar(); + this._guestEmail = new ReactiveVar(); + Tracker.autorun(() => { if (this._room.get() && visitor.getId()) { RoomHistoryManager.getMoreIfIsEmpty(this._room.get()); @@ -121,6 +124,12 @@ this.Livechat = new (class Livechat { get agent() { return this._agent.get(); } + get guestName() { + return this._guestName.get(); + } + get guestEmail() { + return this._guestEmail.get(); + } set online(value) { this._online.set(value); @@ -198,6 +207,12 @@ this.Livechat = new (class Livechat { set agent(agentData) { this._agent.set(agentData); } + set guestName(name) { + return this._guestName.set(name); + } + set guestEmail(email) { + return this._guestEmail.set(email); + } ready() { this._ready.set(true); diff --git a/packages/rocketchat-livechat/.app/client/lib/chatMessages.js b/packages/rocketchat-livechat/.app/client/lib/chatMessages.js index 245e998e5e98..6797cace30df 100644 --- a/packages/rocketchat-livechat/.app/client/lib/chatMessages.js +++ b/packages/rocketchat-livechat/.app/client/lib/chatMessages.js @@ -148,6 +148,14 @@ this.ChatMessages = class ChatMessages { guest.department = Livechat.department; } + if (Livechat.guestName) { + guest.name = Livechat.guestName; + } + + if (Livechat.guestEmail) { + guest.email = Livechat.guestEmail; + } + Meteor.call('livechat:registerGuest', guest, (error, result) => { if (error) { return showError(error.reason); diff --git a/packages/rocketchat-livechat/.app/client/lib/hooks.js b/packages/rocketchat-livechat/.app/client/lib/hooks.js index 89436156dc19..93ba1a6f11c6 100644 --- a/packages/rocketchat-livechat/.app/client/lib/hooks.js +++ b/packages/rocketchat-livechat/.app/client/lib/hooks.js @@ -37,6 +37,34 @@ const api = { widgetClosed() { Livechat.setWidgetClosed(); + }, + + setGuestToken(token) { + visitor.setToken(token); + }, + + setGuestName(name) { + visitor.setName(name); + }, + + setGuestEmail(email) { + visitor.setEmail(email); + }, + + registerGuest(data) { + if (typeof data !== 'object') { + return; + } + + if (!data.token) { + data.token = Random.id(); + } + + Meteor.call('livechat:registerGuest', data, function(error, result) { + if (!error && result.visitor && result.visitor.token) { + visitor.setToken(result.visitor.token); + } + }); } }; diff --git a/packages/rocketchat-livechat/.app/client/lib/msgTyping.js b/packages/rocketchat-livechat/.app/client/lib/msgTyping.js index 378af82a34aa..addcfa608ef4 100644 --- a/packages/rocketchat-livechat/.app/client/lib/msgTyping.js +++ b/packages/rocketchat-livechat/.app/client/lib/msgTyping.js @@ -10,6 +10,7 @@ export const MsgTyping = (function() { const selfTyping = new ReactiveVar(false); const usersTyping = {}; const dep = new Tracker.Dependency; + let oldRoom; const addStream = function(room) { if (!_.isEmpty(usersTyping[room] && usersTyping[room].users)) { @@ -38,7 +39,11 @@ export const MsgTyping = (function() { Tracker.autorun(() => { if (visitor.getRoom() && visitor.getId()) { + if (oldRoom) { + Notifications.unRoom(oldRoom, 'typing'); + } addStream(visitor.getRoom()); + oldRoom = visitor.getRoom(); } }); diff --git a/packages/rocketchat-livechat/.app/client/views/livechatWindow.js b/packages/rocketchat-livechat/.app/client/views/livechatWindow.js index 414bd2cdf9a1..07aaa0912f9c 100644 --- a/packages/rocketchat-livechat/.app/client/views/livechatWindow.js +++ b/packages/rocketchat-livechat/.app/client/views/livechatWindow.js @@ -4,7 +4,7 @@ import visitor from '../../imports/client/visitor'; function showDepartments() { return Department.find({ showOnRegistration: true }).count() > 1; }; - + Template.livechatWindow.helpers({ title() { return Livechat.title; @@ -90,11 +90,20 @@ Template.livechatWindow.onCreated(function() { return lng; }; - // get all needed live chat info for the user - Meteor.call('livechat:getInitialData', visitor.getToken(), (err, result) => { - if (err) { - console.error(err); - } else { + const loadDepartments = departments => { + Department.remove({}); + departments.forEach((department) => { + Department.insert(department); + }); + }; + + this.autorun(() => { + // get all needed live chat info for the user + Meteor.call('livechat:getInitialData', visitor.getToken(), (err, result) => { + if (err) { + return console.error(err); + } + if (!result.enabled) { Triggers.setDisabled(); return parentCall('removeWidget'); @@ -129,6 +138,14 @@ Template.livechatWindow.onCreated(function() { if (result.visitor) { visitor.setData(result.visitor); + + if (visitor.name) { + Livechat.guestName = visitor.name; + } + + if (visitor.visitorEmails && visitor.visitorEmails.length > 0) { + Livechat.guestEmail = visitor.visitorEmails[0].address; + } } if (result.agentData) { @@ -146,13 +163,12 @@ Template.livechatWindow.onCreated(function() { Triggers.setTriggers(result.triggers); Triggers.init(); - result.departments.forEach((department) => { - Department.insert(department); - }); + loadDepartments(result.departments); + Livechat.allowSwitchingDepartments = result.allowSwitchingDepartments; Livechat.ready(); - } + }); }); $(window).on('focus', () => { diff --git a/packages/rocketchat-livechat/.app/client/views/register.html b/packages/rocketchat-livechat/.app/client/views/register.html index 142ca7637593..1e3e533b7e34 100644 --- a/packages/rocketchat-livechat/.app/client/views/register.html +++ b/packages/rocketchat-livechat/.app/client/views/register.html @@ -9,11 +9,11 @@

{{#if showNameFieldRegisterForm}} - - {{/if}} + + {{/if}} {{#if showEmailFieldRegisterForm}} - - {{/if}} + + {{/if}} {{#if showDepartments}}