Skip to content

Commit

Permalink
Merge pull request #22147 from RocketChat/release-3.14.3
Browse files Browse the repository at this point in the history
Release 3.14.3
  • Loading branch information
sampaiodiego authored May 26, 2021
2 parents 53cfb31 + 881e040 commit b8cd787
Show file tree
Hide file tree
Showing 30 changed files with 159 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .docker/Dockerfile.rhel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM registry.access.redhat.com/ubi8/nodejs-12

ENV RC_VERSION 3.14.2
ENV RC_VERSION 3.14.3

MAINTAINER buildmaster@rocket.chat

Expand Down
43 changes: 43 additions & 0 deletions .github/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -59632,6 +59632,49 @@
]
}
]
},
"3.12.6": {
"node_version": "12.18.4",
"npm_version": "6.14.8",
"apps_engine_version": "1.23.0",
"mongo_versions": [
"3.4",
"3.6",
"4.0"
],
"pull_requests": []
},
"3.13.4": {
"node_version": "12.21.0",
"npm_version": "6.14.8",
"apps_engine_version": "1.24.1",
"mongo_versions": [
"3.4",
"3.6",
"4.0"
],
"pull_requests": []
},
"3.14.3": {
"node_version": "12.22.1",
"npm_version": "6.14.1",
"apps_engine_version": "1.25.0",
"mongo_versions": [
"3.4",
"3.6",
"4.0"
],
"pull_requests": [
{
"pr": "22142",
"title": "[FIX][ENTERPRISE] Omnichannel Monitors can't forward chats to departments that they are not supervising",
"userLogin": "sampaiodiego",
"contributors": [
"renatobecker",
"murtaza98"
]
}
]
}
}
}
2 changes: 1 addition & 1 deletion .snapcraft/resources/prepareRocketChat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

curl -SLf "https://releases.rocket.chat/3.14.2/download/" -o rocket.chat.tgz
curl -SLf "https://releases.rocket.chat/3.14.3/download/" -o rocket.chat.tgz

tar xf rocket.chat.tgz --strip 1

Expand Down
2 changes: 1 addition & 1 deletion .snapcraft/snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# 5. `snapcraft snap`

name: rocketchat-server
version: 3.14.2
version: 3.14.3
summary: Rocket.Chat server
description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/
confinement: strict
Expand Down
19 changes: 19 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@

# 3.14.3
`2021-05-26 · 1 🐛 · 2 👩‍💻👨‍💻`

### Engine versions
- Node: `12.22.1`
- NPM: `6.14.1`
- MongoDB: `3.4, 3.6, 4.0`
- Apps-Engine: `1.25.0`

### 🐛 Bug fixes


- **ENTERPRISE:** Omnichannel Monitors can't forward chats to departments that they are not supervising ([#22142](https://github.com/RocketChat/Rocket.Chat/pull/22142))

### 👩‍💻👨‍💻 Core Team 🤓

- [@murtaza98](https://github.com/murtaza98)
- [@renatobecker](https://github.com/renatobecker)

# 3.14.2
`2021-05-25 · 1 🐛 · 1 🔍 · 4 👩‍💻👨‍💻`

Expand Down
10 changes: 8 additions & 2 deletions app/livechat/imports/server/rest/departments.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ API.v1.addRoute('livechat/department', { authRequired: true }, {
get() {
const { offset, count } = this.getPaginationItems();
const { sort } = this.parseJsonQuery();
const { text, enabled } = this.queryParams;

const { text, enabled, onlyMyDepartments } = this.queryParams;

const departments = Promise.await(findDepartments({
userId: this.userId,
text,
enabled,
onlyMyDepartments: onlyMyDepartments === 'true',
pagination: {
offset,
count,
Expand Down Expand Up @@ -59,10 +61,13 @@ API.v1.addRoute('livechat/department/:_id', { authRequired: true }, {
_id: String,
});

const { onlyMyDepartments } = this.queryParams;

const { department, agents } = Promise.await(findDepartmentById({
userId: this.userId,
departmentId: this.urlParams._id,
includeAgents: this.queryParams.includeAgents && this.queryParams.includeAgents === 'true',
onlyMyDepartments: onlyMyDepartments === 'true',
}));

const result = { department };
Expand Down Expand Up @@ -137,14 +142,15 @@ API.v1.addRoute('livechat/department/:_id', { authRequired: true }, {

API.v1.addRoute('livechat/department.autocomplete', { authRequired: true }, {
get() {
const { selector } = this.queryParams;
const { selector, onlyMyDepartments } = this.queryParams;
if (!selector) {
return API.v1.failure('The \'selector\' param is required');
}

return API.v1.success(Promise.await(findDepartmentsToAutocomplete({
uid: this.userId,
selector: JSON.parse(selector),
onlyMyDepartments: onlyMyDepartments === 'true',
})));
},
});
Expand Down
31 changes: 24 additions & 7 deletions app/livechat/server/api/lib/departments.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { escapeRegExp } from '../../../../../lib/escapeRegExp';
import { hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
import { LivechatDepartment, LivechatDepartmentAgents } from '../../../../models/server/raw';
import { callbacks } from '../../../../callbacks/server';

export async function findDepartments({ userId, text, enabled, pagination: { offset, count, sort } }) {

export async function findDepartments({ userId, onlyMyDepartments = false, text, enabled, pagination: { offset, count, sort } }) {
if (!await hasPermissionAsync(userId, 'view-livechat-departments') && !await hasPermissionAsync(userId, 'view-l-room')) {
throw new Error('error-not-authorized');
}

const query = {
let query = {
...enabled && { enabled: Boolean(enabled) },
...text && { name: new RegExp(escapeRegExp(text), 'i') },
};

if (onlyMyDepartments) {
query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId });
}

const cursor = LivechatDepartment.find(query, {
sort: sort || { name: 1 },
skip: offset,
Expand All @@ -30,13 +36,20 @@ export async function findDepartments({ userId, text, enabled, pagination: { off
};
}

export async function findDepartmentById({ userId, departmentId, includeAgents = true }) {
export async function findDepartmentById({ userId, departmentId, includeAgents = true, onlyMyDepartments = false }) {
const canViewLivechatDepartments = await hasPermissionAsync(userId, 'view-livechat-departments');
if (!canViewLivechatDepartments && !await hasPermissionAsync(userId, 'view-l-room')) {
throw new Error('error-not-authorized');
}

let query = { _id: departmentId };

if (onlyMyDepartments) {
query = callbacks.run('livechat.applyDepartmentRestrictions', query, { userId });
}

const result = {
department: await LivechatDepartment.findOneById(departmentId),
department: await LivechatDepartment.findOne(query),
};
if (includeAgents && canViewLivechatDepartments) {
result.agents = await LivechatDepartmentAgents.find({ departmentId }).toArray();
Expand All @@ -45,23 +58,27 @@ export async function findDepartmentById({ userId, departmentId, includeAgents =
return result;
}

export async function findDepartmentsToAutocomplete({ uid, selector }) {
export async function findDepartmentsToAutocomplete({ uid, selector, onlyMyDepartments = false }) {
if (!await hasPermissionAsync(uid, 'view-livechat-departments') && !await hasPermissionAsync(uid, 'view-l-room')) {
return { items: [] };
}
const { exceptions = [], conditions = {} } = selector;
const { exceptions = [] } = selector;
let { conditions = {} } = selector;

const options = {
fields: {
_id: 1,
name: 1,
},
limit: 10,
sort: {
name: 1,
},
};

if (onlyMyDepartments) {
conditions = callbacks.run('livechat.applyDepartmentRestrictions', conditions, { userId: uid });
}

const items = await LivechatDepartment.findByNameRegexWithExceptionsAndConditions(selector.term, exceptions, conditions, options).toArray();
return {
items,
Expand Down
5 changes: 3 additions & 2 deletions app/models/server/raw/Users.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export class UsersRaw extends BaseRaw {
$and: [
{ $eq: ['$u._id', '$$id'] },
{ $eq: ['$open', true] },
{ $ne: ['$onHold', true] },
{ ...department && { $eq: ['$department', department] } },
],
},
Expand Down Expand Up @@ -196,11 +197,11 @@ export class UsersRaw extends BaseRaw {
return result.value;
}

async getAgentAndAmountOngoingChats(userId, department) {
async getAgentAndAmountOngoingChats(userId) {
const aggregate = [
{ $match: { _id: userId, status: { $exists: true, $ne: 'offline' }, statusLivechat: 'available', roles: 'livechat-agent' } },
{ $lookup: { from: 'rocketchat_subscription', localField: '_id', foreignField: 'u._id', as: 'subs' } },
{ $project: { agentId: '$_id', username: 1, lastAssignTime: 1, lastRoutingTime: 1, 'queueInfo.chats': { $size: { $filter: { input: '$subs', as: 'sub', cond: { $and: [{ $eq: ['$$sub.t', 'l'] }, { $eq: ['$$sub.open', true] }, { $ne: ['$$sub.onHold', true] }, { ...department && { $eq: ['$$sub.department', department] } }] } } } } } },
{ $project: { agentId: '$_id', username: 1, lastAssignTime: 1, lastRoutingTime: 1, 'queueInfo.chats': { $size: { $filter: { input: '$subs', as: 'sub', cond: { $and: [{ $eq: ['$$sub.t', 'l'] }, { $eq: ['$$sub.open', true] }, { $ne: ['$$sub.onHold', true] }] } } } } } },
{ $sort: { 'queueInfo.chats': 1, lastAssignTime: 1, lastRoutingTime: 1, username: 1 } },
];

Expand Down
2 changes: 1 addition & 1 deletion app/utils/rocketchat.info
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "3.14.2"
"version": "3.14.3"
}
6 changes: 3 additions & 3 deletions client/components/AutoCompleteDepartment.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { useTranslation } from '../contexts/TranslationContext';
import { useEndpointData } from '../hooks/useEndpointData';

const AutoCompleteDepartment = (props) => {
const { label, onlyMyDepartments = false } = props;

const t = useTranslation();
const [filter, setFilter] = useState('');
const { value: data } = useEndpointData(
'livechat/department',
useMemo(() => ({ text: filter }), [filter]),
useMemo(() => ({ text: filter, onlyMyDepartments }), [filter, onlyMyDepartments]),
);

const { label } = props;

const options = useMemo(
() =>
(data && [
Expand Down
13 changes: 9 additions & 4 deletions client/views/omnichannel/DepartmentAutoComplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ import React, { memo, useMemo, useState } from 'react';

import { useEndpointData } from '../../hooks/useEndpointData';

const query = (term = '', enabled = false) => ({
selector: JSON.stringify({ term, ...(enabled && { conditions: { enabled } }) }),
const query = (term = '', enabled = false, onlyMyDepartments = false) => ({
selector: JSON.stringify({
term,
...(enabled && { conditions: { enabled } }),
}),
onlyMyDepartments,
});

const DepartmentAutoComplete = (props) => {
const { enabled } = props;
const { enabled, onlyMyDepartments = false } = props;
const [filter, setFilter] = useState('');
const { value: data } = useEndpointData(
'livechat/department.autocomplete',
useMemo(() => query(filter, enabled), [enabled, filter]),
useMemo(() => query(filter, enabled, onlyMyDepartments), [onlyMyDepartments, enabled, filter]),
);

const options = useMemo(
() =>
(data &&
Expand Down
7 changes: 6 additions & 1 deletion client/views/omnichannel/currentChats/FilterByText.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,12 @@ const FilterByText = ({ setFilter, reload, ...props }) => {
</Box>
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'>
<Label mb='x4'>{t('Department')}</Label>
<AutoCompleteDepartment value={department} onChange={handleDepartment} label={t('All')} />
<AutoCompleteDepartment
value={department}
onChange={handleDepartment}
label={t('All')}
onlyMyDepartments
/>
</Box>
<Box display='flex' mie='x8' flexGrow={1} flexDirection='column'>
<Label mb='x4'>{t('Status')}</Label>
Expand Down
14 changes: 10 additions & 4 deletions client/views/omnichannel/departments/DepartmentsRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import RemoveDepartmentButton from './RemoveDepartmentButton';

const sortDir = (sortDir) => (sortDir === 'asc' ? 1 : -1);

const useQuery = ({ text, itemsPerPage, current }, [column, direction]) =>
const useQuery = ({ text, itemsPerPage, current }, [column, direction], onlyMyDepartments) =>
useMemo(
() => ({
fields: JSON.stringify({ name: 1, username: 1, emails: 1, avatarETag: 1 }),
Expand All @@ -25,20 +25,26 @@ const useQuery = ({ text, itemsPerPage, current }, [column, direction]) =>
}),
...(itemsPerPage && { count: itemsPerPage }),
...(current && { offset: current }),
onlyMyDepartments,
}),
[text, itemsPerPage, current, column, direction],
[text, itemsPerPage, current, column, direction, onlyMyDepartments],
);

function DepartmentsRoute() {
const t = useTranslation();
const canViewDepartments = usePermission('manage-livechat-departments');

const [params, setParams] = useState({ text: '', current: 0, itemsPerPage: 25 });
const [params, setParams] = useState({
text: '',
current: 0,
itemsPerPage: 25,
});
const [sort, setSort] = useState(['name', 'asc']);

const debouncedParams = useDebouncedValue(params, 500);
const debouncedSort = useDebouncedValue(sort, 500);
const query = useQuery(debouncedParams, debouncedSort);
const onlyMyDepartments = true;
const query = useQuery(debouncedParams, debouncedSort, onlyMyDepartments);
const departmentsRoute = useRoute('omnichannel-departments');
const context = useRouteParameter('context');
const id = useRouteParameter('id');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import { AsyncStatePhase } from '../../../hooks/useAsyncState';
import { useEndpointData } from '../../../hooks/useEndpointData';
import EditDepartment from './EditDepartment';

const param = { onlyMyDepartments: true };
function EditDepartmentWithData({ id, reload, title }) {
const t = useTranslation();
const { value: data, phase: state, error } = useEndpointData(`livechat/department/${id}`);
const { value: data, phase: state, error } = useEndpointData(`livechat/department/${id}`, param);

if ([state].includes(AsyncStatePhase.LOADING)) {
return <FormSkeleton />;
}

if (error) {
return <Box mbs='x16'>{t('User_not_found')}</Box>;
if (error || (id && !data?.department)) {
return <Box mbs='x16'>{t('Department_not_found')}</Box>;
}
return <EditDepartment id={id} data={data} reload={reload} title={title} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const RealTimeMonitoringPage = () => {
placeholder={t('All')}
value={department}
onChange={setDepartment}
onlyMyDepartments
/>
</Field.Row>
</Field>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { callbacks } from '../../../../../app/callbacks/server';
import { addQueryRestrictionsToDepartmentsModel } from '../lib/query.helper';
import { hasRole } from '../../../../../app/authorization/server/functions/hasRole';

callbacks.add('livechat.applyDepartmentRestrictions', (originalQuery = {}, { userId } = { userId: null }) => {
if (!userId || !hasRole(userId, 'livechat-monitor')) {
return originalQuery;
}

return addQueryRestrictionsToDepartmentsModel(originalQuery);
}, callbacks.priority.HIGH, 'livechat-apply-department-restrictions');
Loading

0 comments on commit b8cd787

Please sign in to comment.