diff --git a/.docker/Dockerfile.rhel b/.docker/Dockerfile.rhel
index f7d457caac43..7bb70bfcbb04 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 3.6.0
+ENV RC_VERSION 3.6.1
MAINTAINER buildmaster@rocket.chat
diff --git a/.github/history.json b/.github/history.json
index c78904930158..e68ca04ba221 100644
--- a/.github/history.json
+++ b/.github/history.json
@@ -15363,14 +15363,6 @@
]
},
"HEAD": {
- "node_version": "12.16.1",
- "npm_version": "6.14.0",
- "apps_engine_version": "1.17.0",
- "mongo_versions": [
- "3.4",
- "3.6",
- "4.0"
- ],
"pull_requests": []
},
"0.66.0-rc.0": {
@@ -48026,8 +48018,8 @@
]
}
]
- },
- "3.6.0-rc.0": {
+ },
+ "3.6.0-rc.0": {
"node_version": "12.16.1",
"npm_version": "6.14.0",
"apps_engine_version": "1.17.0-beta.3629",
@@ -49197,6 +49189,81 @@
]
}
]
+ },
+ "3.6.1": {
+ "node_version": "12.16.1",
+ "npm_version": "6.14.0",
+ "apps_engine_version": "1.17.0",
+ "mongo_versions": [
+ "3.4",
+ "3.6",
+ "4.0"
+ ],
+ "pull_requests": [
+ {
+ "pr": "18862",
+ "title": "[FIX] Showing alerts during setup wizard",
+ "userLogin": "sampaiodiego",
+ "milestone": "3.6.1",
+ "contributors": [
+ "sampaiodiego"
+ ]
+ },
+ {
+ "pr": "18852",
+ "title": "[FIX] User can't invite or join other Omnichannel rooms",
+ "userLogin": "renatobecker",
+ "milestone": "3.6.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "18851",
+ "title": "[FIX] User administration throwing a blank page if user has no role",
+ "userLogin": "ggazzo",
+ "milestone": "3.6.1",
+ "contributors": [
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "18850",
+ "title": "[FIX] IE11 support livechat widget",
+ "userLogin": "ggazzo",
+ "milestone": "3.6.1",
+ "contributors": [
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "18841",
+ "title": "[FIX] File upload (Avatars, Emoji, Sounds)",
+ "userLogin": "ggazzo",
+ "milestone": "3.6.1",
+ "contributors": [
+ "ggazzo"
+ ]
+ },
+ {
+ "pr": "18835",
+ "title": "[FIX][ENTERPRISE] Omnichannel service status switching to unavailable",
+ "userLogin": "renatobecker",
+ "milestone": "3.6.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ },
+ {
+ "pr": "18795",
+ "title": "[FIX] Omnichannel Current Chats open status filter not working",
+ "userLogin": "renatobecker",
+ "milestone": "3.6.1",
+ "contributors": [
+ "renatobecker"
+ ]
+ }
+ ]
}
}
-}
+}
\ No newline at end of file
diff --git a/.snapcraft/resources/prepareRocketChat b/.snapcraft/resources/prepareRocketChat
index f49ee9bacfd9..dc5cc39db64f 100755
--- a/.snapcraft/resources/prepareRocketChat
+++ b/.snapcraft/resources/prepareRocketChat
@@ -1,6 +1,6 @@
#!/bin/bash
-curl -SLf "https://releases.rocket.chat/3.6.0/download/" -o rocket.chat.tgz
+curl -SLf "https://releases.rocket.chat/3.6.1/download/" -o rocket.chat.tgz
tar xf rocket.chat.tgz --strip 1
diff --git a/.snapcraft/snap/snapcraft.yaml b/.snapcraft/snap/snapcraft.yaml
index a2cbc9074427..3b4bad1d80d0 100644
--- a/.snapcraft/snap/snapcraft.yaml
+++ b/.snapcraft/snap/snapcraft.yaml
@@ -7,7 +7,7 @@
# 5. `snapcraft snap`
name: rocketchat-server
-version: 3.6.0
+version: 3.6.1
summary: Rocket.Chat server
description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/
confinement: strict
diff --git a/HISTORY.md b/HISTORY.md
index 17ff8d1d393e..d447e35f3a4d 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,4 +1,36 @@
+# 3.6.1
+`2020-09-11 ยท 7 ๐ ยท 3 ๐ฉโ๐ป๐จโ๐ป`
+
+### Engine versions
+- Node: `12.16.1`
+- NPM: `6.14.0`
+- MongoDB: `3.4, 3.6, 4.0`
+- Apps-Engine: `1.17.0`
+
+### ๐ Bug fixes
+
+
+- **ENTERPRISE:** Omnichannel service status switching to unavailable ([#18835](https://github.com/RocketChat/Rocket.Chat/pull/18835))
+
+- File upload (Avatars, Emoji, Sounds) ([#18841](https://github.com/RocketChat/Rocket.Chat/pull/18841))
+
+- IE11 support livechat widget ([#18850](https://github.com/RocketChat/Rocket.Chat/pull/18850))
+
+- Omnichannel Current Chats open status filter not working ([#18795](https://github.com/RocketChat/Rocket.Chat/pull/18795))
+
+- Showing alerts during setup wizard ([#18862](https://github.com/RocketChat/Rocket.Chat/pull/18862))
+
+- User administration throwing a blank page if user has no role ([#18851](https://github.com/RocketChat/Rocket.Chat/pull/18851))
+
+- User can't invite or join other Omnichannel rooms ([#18852](https://github.com/RocketChat/Rocket.Chat/pull/18852))
+
+### ๐ฉโ๐ป๐จโ๐ป Core Team ๐ค
+
+- [@ggazzo](https://github.com/ggazzo)
+- [@renatobecker](https://github.com/renatobecker)
+- [@sampaiodiego](https://github.com/sampaiodiego)
+
# 3.6.0
`2020-08-29 ยท 10 ๐ ยท 5 ๐ ยท 26 ๐ ยท 36 ๐ ยท 23 ๐ฉโ๐ป๐จโ๐ป`
diff --git a/app/2fa/server/code/index.ts b/app/2fa/server/code/index.ts
index 7da600862962..6bf56df20d66 100644
--- a/app/2fa/server/code/index.ts
+++ b/app/2fa/server/code/index.ts
@@ -43,6 +43,7 @@ export function getUserForCheck(userId: string): IUser {
fields: {
emails: 1,
language: 1,
+ createdAt: 1,
'services.totp': 1,
'services.email2fa': 1,
'services.emailCode': 1,
@@ -61,6 +62,19 @@ export function getFingerprintFromConnection(connection: IMethodConnection): str
return crypto.createHash('md5').update(data).digest('hex');
}
+function getRememberDate(from: Date = new Date()): Date | undefined {
+ const rememberFor = parseInt(settings.get('Accounts_TwoFactorAuthentication_RememberFor') as string, 10);
+
+ if (rememberFor <= 0) {
+ return;
+ }
+
+ const expires = new Date(from);
+ expires.setSeconds(expires.getSeconds() + rememberFor);
+
+ return expires;
+}
+
export function isAuthorizedForToken(connection: IMethodConnection, user: IUser, options: ITwoFactorOptions): boolean {
const currentToken = Accounts._getLoginToken(connection.id);
const tokenObject = user.services?.resume?.loginTokens?.find((i) => i.hashedToken === currentToken);
@@ -77,6 +91,12 @@ export function isAuthorizedForToken(connection: IMethodConnection, user: IUser,
return false;
}
+ // remember user right after their registration
+ const rememberAfterRegistration = user.createdAt && getRememberDate(user.createdAt);
+ if (rememberAfterRegistration && rememberAfterRegistration >= new Date()) {
+ return true;
+ }
+
if (!tokenObject.twoFactorAuthorizedUntil || !tokenObject.twoFactorAuthorizedHash) {
return false;
}
@@ -95,15 +115,11 @@ export function isAuthorizedForToken(connection: IMethodConnection, user: IUser,
export function rememberAuthorization(connection: IMethodConnection, user: IUser): void {
const currentToken = Accounts._getLoginToken(connection.id);
- const rememberFor = parseInt(settings.get('Accounts_TwoFactorAuthentication_RememberFor') as string, 10);
-
- if (rememberFor <= 0) {
+ const expires = getRememberDate();
+ if (!expires) {
return;
}
- const expires = new Date();
- expires.setSeconds(expires.getSeconds() + rememberFor);
-
Users.setTwoFactorAuthorizationHashAndUntilForUserIdAndToken(user._id, currentToken, getFingerprintFromConnection(connection), expires);
}
diff --git a/app/lib/server/functions/addUserToRoom.js b/app/lib/server/functions/addUserToRoom.js
index 2d97b88184db..69b7bd21f0ad 100644
--- a/app/lib/server/functions/addUserToRoom.js
+++ b/app/lib/server/functions/addUserToRoom.js
@@ -31,7 +31,7 @@ export const addUserToRoom = function(rid, user, inviter, silenced) {
throw error;
}
- if (room.t === 'c' || room.t === 'p') {
+ if (room.t === 'c' || room.t === 'p' || room.t === 'l') {
// Add a new event, with an optional inviter
callbacks.run('beforeAddedToRoom', { user, inviter }, room);
diff --git a/app/lib/server/startup/settings.js b/app/lib/server/startup/settings.js
index ca9c21c0c7df..af11aabf4b33 100644
--- a/app/lib/server/startup/settings.js
+++ b/app/lib/server/startup/settings.js
@@ -2679,7 +2679,7 @@ settings.addGroup('Setup_Wizard', function() {
this.add('Allow_Marketing_Emails', true, {
type: 'boolean',
});
- this.add('Register_Server', true, {
+ this.add('Register_Server', false, {
type: 'boolean',
});
this.add('Organization_Email', '', {
diff --git a/app/livechat/lib/LivechatRoomType.js b/app/livechat/lib/LivechatRoomType.js
index 19dccc3201e9..1bcbe8bebc3b 100644
--- a/app/livechat/lib/LivechatRoomType.js
+++ b/app/livechat/lib/LivechatRoomType.js
@@ -5,7 +5,7 @@ import { ChatRoom } from '../../models';
import { settings } from '../../settings';
import { hasPermission } from '../../authorization';
import { openRoom } from '../../ui-utils';
-import { RoomSettingsEnum, UiTextContext, RoomTypeRouteConfig, RoomTypeConfig } from '../../utils';
+import { RoomMemberActions, RoomSettingsEnum, UiTextContext, RoomTypeRouteConfig, RoomTypeConfig } from '../../utils';
import { getAvatarURL } from '../../utils/lib/getAvatarURL';
let LivechatInquiry;
@@ -85,6 +85,10 @@ export default class LivechatRoomType extends RoomTypeConfig {
}
}
+ allowMemberAction(room, action) {
+ return [RoomMemberActions.INVITE, RoomMemberActions.JOIN].includes(action);
+ }
+
getUiText(context) {
switch (context) {
case UiTextContext.HIDE_WARNING:
diff --git a/app/livechat/server/startup.js b/app/livechat/server/startup.js
index 8ae1e047bab8..1c05756727cc 100644
--- a/app/livechat/server/startup.js
+++ b/app/livechat/server/startup.js
@@ -83,6 +83,14 @@ Meteor.startup(async () => {
}));
}, callbacks.priority.LOW, 'cant-leave-room');
+ callbacks.add('beforeJoinRoom', function(user, room) {
+ if (room.t === 'l' && !hasPermission(user._id, 'view-l-room')) {
+ throw new Meteor.Error('error-user-is-not-agent', 'User is not an Omnichannel Agent', { method: 'beforeJoinRoom' });
+ }
+
+ return user;
+ }, callbacks.priority.LOW, 'cant-join-room');
+
createLivechatQueueView();
const monitor = new LivechatAgentActivityMonitor();
diff --git a/app/tokenpass/server/startup.js b/app/tokenpass/server/startup.js
index 459cac9111fa..4ed4a9074315 100644
--- a/app/tokenpass/server/startup.js
+++ b/app/tokenpass/server/startup.js
@@ -47,7 +47,7 @@ Meteor.startup(function() {
throw new Meteor.Error('error-not-allowed', 'Token required', { method: 'joinRoom' });
}
- return room;
+ return user;
});
});
diff --git a/app/utils/rocketchat.info b/app/utils/rocketchat.info
index 9a8ea3d5eef6..b5f6e0bc1f41 100644
--- a/app/utils/rocketchat.info
+++ b/app/utils/rocketchat.info
@@ -1,3 +1,3 @@
{
- "version": "3.6.0"
+ "version": "3.6.1"
}
diff --git a/client/admin/users/UserInfo.js b/client/admin/users/UserInfo.js
index 9006d9e38aca..e7e89f282ef7 100644
--- a/client/admin/users/UserInfo.js
+++ b/client/admin/users/UserInfo.js
@@ -61,11 +61,13 @@ export function UserInfoWithData({ uid, username, ...props }) {
return {t('User_not_found')};
}
+ const admin = data.user?.roles?.includes('admin');
+
return }
+ actions={data && data.user && }
{...props}
/>;
}
diff --git a/client/contexts/ServerContext.ts b/client/contexts/ServerContext.ts
index 2fc8d0fced23..25784a340319 100644
--- a/client/contexts/ServerContext.ts
+++ b/client/contexts/ServerContext.ts
@@ -10,7 +10,7 @@ type ServerContextValue = {
absoluteUrl: (path: string) => string;
callMethod: (methodName: string, ...args: any[]) => Promise;
callEndpoint: (httpMethod: 'GET' | 'POST' | 'DELETE', endpoint: string, ...args: any[]) => Promise;
- uploadToEndpoint: (endpoint: string) => Promise;
+ uploadToEndpoint: (endpoint: string, params: any, formData: any) => Promise;
getStream: (streamName: string, options?: {}) => IServerStream;
};
@@ -40,9 +40,9 @@ export const useEndpoint = (httpMethod: 'GET' | 'POST' | 'DELETE', endpoint: str
return useCallback((...args: any[]) => callEndpoint(httpMethod, endpoint, ...args), [callEndpoint, httpMethod, endpoint]);
};
-export const useUpload = (endpoint: string): () => Promise => {
+export const useUpload = (endpoint: string): (params: any, formData: any) => Promise => {
const { uploadToEndpoint } = useContext(ServerContext);
- return useCallback(() => uploadToEndpoint(endpoint), [endpoint, uploadToEndpoint]);
+ return useCallback((params, formData: any) => uploadToEndpoint(endpoint, params, formData), [endpoint, uploadToEndpoint]);
};
export const useStream = (streamName: string, options?: {}): IServerStream => {
diff --git a/client/hooks/useFileInput.js b/client/hooks/useFileInput.js
index e7457592a97a..6ac59b3b0da8 100644
--- a/client/hooks/useFileInput.js
+++ b/client/hooks/useFileInput.js
@@ -1,7 +1,7 @@
import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
import { useRef, useEffect } from 'react';
-export const useFileInput = (onSetFile, fileType = 'image/*') => {
+export const useFileInput = (onSetFile, fileType = 'image/*', fileField = 'image') => {
const ref = useRef();
useEffect(() => {
@@ -14,7 +14,7 @@ export const useFileInput = (onSetFile, fileType = 'image/*') => {
ref.current = fileInput;
const handleFiles = () => {
- formData.append(fileType, fileInput.files[0]);
+ formData.append(fileField, fileInput.files[0]);
onSetFile(fileInput.files[0], formData);
};
fileInput.addEventListener('change', handleFiles, false);
diff --git a/client/hooks/useUpdateAvatar.js b/client/hooks/useUpdateAvatar.js
index 8aa8e1fa30fe..3671ac487b3e 100644
--- a/client/hooks/useUpdateAvatar.js
+++ b/client/hooks/useUpdateAvatar.js
@@ -17,7 +17,7 @@ export const useUpdateAvatar = (avatarObj, userId) => {
const saveAvatarQuery = useMemo(() => ({
userId,
- avatarUrl,
+ ...avatarUrl && { avatarUrl },
}), [avatarUrl, userId]);
const resetAvatarQuery = useMemo(() => ({
diff --git a/client/omnichannel/currentChats/CurrentChatsRoute.js b/client/omnichannel/currentChats/CurrentChatsRoute.js
index da9edc10ea86..d4ff9f77ef9f 100644
--- a/client/omnichannel/currentChats/CurrentChatsRoute.js
+++ b/client/omnichannel/currentChats/CurrentChatsRoute.js
@@ -69,7 +69,7 @@ const useQuery = ({ guest, servedBy, department, status, from, to, tags, customF
query.createdAt = JSON.stringify({ start: from, end: to });
}
if (status !== 'all') {
- query.open = status === 'open';
+ query.open = status === 'opened';
}
if (servedBy && servedBy !== 'all') {
query.agents = [servedBy];
diff --git a/ee/app/livechat-enterprise/server/startup.js b/ee/app/livechat-enterprise/server/startup.js
index e9615a5735df..cda5f67331ee 100644
--- a/ee/app/livechat-enterprise/server/startup.js
+++ b/ee/app/livechat-enterprise/server/startup.js
@@ -31,7 +31,9 @@ Meteor.startup(async function() {
});
settings.onload('Livechat_business_hour_type', (_, value) => {
businessHourManager.registerBusinessHourBehavior(businessHours[value]);
- businessHourManager.startManager();
+ if (settings.get('Livechat_enable_business_hours')) {
+ businessHourManager.startManager();
+ }
});
await resetDefaultBusinessHourIfNeeded();
});
diff --git a/package-lock.json b/package-lock.json
index 8c71c377394b..092ba07e31a0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "Rocket.Chat",
- "version": "3.6.0",
+ "version": "3.6.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -5123,14 +5123,15 @@
"integrity": "sha512-V/lq5xdIxx016pKB8kSQuQ+IKLC0ULdkZ72M/DEMU1DqXahWDEJeRiBppOO8YN5/mw5INaf8asWOqxJfIFld0w=="
},
"@rocket.chat/livechat": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/@rocket.chat/livechat/-/livechat-1.7.2.tgz",
- "integrity": "sha512-CikbwDG2ohvnQbSlQIYBe9YUmIyrBgGYtPUXFAI5J9zp6UFg2S0icO2wAN7O3IJJl/RKOVKyWO+3/L83DypVVw==",
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/livechat/-/livechat-1.7.3.tgz",
+ "integrity": "sha512-Az3zyqILC61LfVa0amkO1vb4rXJniFIOuc/iw1TFLqaG1wWow8aBohqqIPoQs2DptJThp0R8w8APlrJEQrGZJw==",
"dev": true,
"requires": {
"@kossnocorp/desvg": "^0.2.0",
"@rocket.chat/sdk": "^1.0.0-alpha.41",
"@rocket.chat/ui-kit": "^0.14.1",
+ "css-vars-ponyfill": "^2.3.2",
"date-fns": "^2.15.0",
"desvg": "^1.0.2",
"emoji-mart": "^3.0.0",
@@ -5142,7 +5143,8 @@
"preact": "^10.4.6",
"preact-i18nline": "^2.0.0",
"preact-router": "^3.2.1",
- "query-string": "^6.13.1"
+ "query-string": "^6.13.1",
+ "whatwg-fetch": "^3.4.0"
},
"dependencies": {
"query-string": {
@@ -5155,6 +5157,12 @@
"split-on-first": "^1.0.0",
"strict-uri-encode": "^2.0.0"
}
+ },
+ "whatwg-fetch": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz",
+ "integrity": "sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ==",
+ "dev": true
}
}
},
@@ -14932,6 +14940,12 @@
}
}
},
+ "css-vars-ponyfill": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.3.2.tgz",
+ "integrity": "sha512-XkZfj0ROhem0Zdv44+LF15COsYmxnqL7Wd/gvwuWAauYoALbt2x94b6dIKF9fB6SIyOMYEQngA82t9RnC6b/aw==",
+ "dev": true
+ },
"css-what": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.2.tgz",
@@ -15335,9 +15349,9 @@
"integrity": "sha512-lcWy3AXDRJOD7MplwZMmNSRM//kZtJaLz4n6D1P5z9wEmZGBKhJRBIr1Xs9KNQJmdXPblvgffynYji4iylUTcA=="
},
"date-fns": {
- "version": "2.16.0",
- "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.0.tgz",
- "integrity": "sha512-DWTRyfOA85sZ4IiXPHhiRIOs3fW5U6Msrp+gElXARa6EpoQTXPyHQmh7hr+ssw2nx9FtOQWnAMJKgL5vaJqILw==",
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
+ "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==",
"dev": true
},
"date-now": {
diff --git a/package.json b/package.json
index 722260a72ed2..e482bed3d734 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "Rocket.Chat",
"description": "The Ultimate Open Source WebChat Platform",
- "version": "3.6.0",
+ "version": "3.6.1",
"author": {
"name": "Rocket.Chat",
"url": "https://rocket.chat/"
@@ -55,7 +55,7 @@
"@babel/preset-react": "^7.10.4",
"@octokit/rest": "^16.43.2",
"@rocket.chat/eslint-config": "^0.3.0",
- "@rocket.chat/livechat": "^1.7.2",
+ "@rocket.chat/livechat": "^1.7.3",
"@settlin/spacebars-loader": "^1.0.8",
"@storybook/addon-actions": "^5.3.19",
"@storybook/addon-knobs": "^5.3.19",
diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json
index f6b4b89e0374..c091cbc561cf 100644
--- a/packages/rocketchat-i18n/i18n/en.i18n.json
+++ b/packages/rocketchat-i18n/i18n/en.i18n.json
@@ -1522,7 +1522,7 @@
"error-transcript-already-requested": "Transcript already requested",
"error-user-has-no-roles": "User has no roles",
"error-user-is-not-activated": "User is not activated",
- "error-user-is-not-agent": "User is not a Omnichannel Agent",
+ "error-user-is-not-agent": "User is not an Omnichannel Agent",
"error-user-is-offline": "User if offline",
"error-user-limit-exceeded": "The number of users you are trying to invite to #channel_name exceeds the limit set by the administrator",
"error-user-not-in-room": "User is not in this room",