Skip to content

Commit be9efc2

Browse files
Merge branch 'develop' into fix/failing-to-dismiss-banner
2 parents fa6b70f + 96e66c8 commit be9efc2

File tree

108 files changed

+1102
-582
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+1102
-582
lines changed

.changeset/eighty-wasps-kneel.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
---
4+
5+
Fixed an issue with how the UI checked for permissions when deciding if editing or deleting a message by moderators users

.changeset/short-coins-enjoy.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Fixed an issue where apps installed via the Marketplace would not be shown in the installed list if the app is unpublished

.changeset/tidy-apes-fry.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
---
4+
5+
Fixed inverted navigation direction in the image gallery

.changeset/wild-carrots-know.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
---
4+
5+
Remove password change reason when the `request password change` option is set to false

apps/meteor/app/authorization/server/functions/canDeleteMessage.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const canDeleteMessageAsync = async (
3434
if (!allowed) {
3535
return false;
3636
}
37-
const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete');
37+
const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete', rid);
3838

3939
if (!bypassBlockTimeLimit) {
4040
const blockDeleteInMinutes = await getValue('Message_AllowDeleting_BlockDeleteInMinutes');

apps/meteor/app/lib/server/functions/deleteUser.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { callbacks } from '../../../../lib/callbacks';
1919
import { i18n } from '../../../../server/lib/i18n';
2020
import { FileUpload } from '../../../file-upload/server';
2121
import { settings } from '../../../settings/server';
22-
import { notifyOnRoomChangedById, notifyOnIntegrationChangedByUserId } from '../lib/notifyListener';
22+
import { notifyOnRoomChangedById, notifyOnIntegrationChangedByUserId, notifyOnLivechatDepartmentAgentChanged } from '../lib/notifyListener';
2323
import { getSubscribedRoomsForUserWithDetails, shouldRemoveOrChangeOwner } from './getRoomsWithSingleOwner';
2424
import { getUserSingleOwnedRooms } from './getUserSingleOwnedRooms';
2525
import { relinquishRoomOwnerships } from './relinquishRoomOwnerships';
@@ -95,9 +95,24 @@ export async function deleteUser(userId: string, confirmRelinquish = false, dele
9595

9696
await Subscriptions.removeByUserId(userId); // Remove user subscriptions
9797

98+
// Remove user as livechat agent
9899
if (user.roles.includes('livechat-agent')) {
99-
// Remove user as livechat agent
100-
await LivechatDepartmentAgents.removeByAgentId(userId);
100+
const departmentAgents = await LivechatDepartmentAgents.findByAgentId(userId).toArray();
101+
102+
const { deletedCount } = await LivechatDepartmentAgents.removeByAgentId(userId);
103+
104+
if (deletedCount > 0) {
105+
departmentAgents.forEach((depAgent) => {
106+
void notifyOnLivechatDepartmentAgentChanged(
107+
{
108+
_id: depAgent._id,
109+
agentId: userId,
110+
departmentId: depAgent.departmentId,
111+
},
112+
'removed',
113+
);
114+
});
115+
}
101116
}
102117

103118
if (user.roles.includes('livechat-monitor')) {

apps/meteor/app/lib/server/functions/saveUser.js

+4
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ export const saveUser = async function (userId, userData) {
401401

402402
const updateUser = {
403403
$set: {},
404+
$unset: {},
404405
};
405406

406407
handleBio(updateUser, userData.bio);
@@ -419,6 +420,9 @@ export const saveUser = async function (userId, userData) {
419420

420421
if (typeof userData.requirePasswordChange !== 'undefined') {
421422
updateUser.$set.requirePasswordChange = userData.requirePasswordChange;
423+
if (!userData.requirePasswordChange) {
424+
updateUser.$unset.requirePasswordChangeReason = 1;
425+
}
422426
}
423427

424428
if (typeof userData.verified === 'boolean') {

apps/meteor/app/lib/server/lib/notifyListener.ts

+46
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
IPbxEvent,
1111
LoginServiceConfiguration as LoginServiceConfigurationData,
1212
ILivechatPriority,
13+
ILivechatDepartmentAgents,
1314
IEmailInbox,
1415
IIntegrationHistory,
1516
AtLeast,
@@ -23,6 +24,7 @@ import {
2324
Integrations,
2425
LoginServiceConfiguration,
2526
IntegrationHistory,
27+
LivechatDepartmentAgents,
2628
} from '@rocket.chat/models';
2729

2830
type ClientAction = 'inserted' | 'updated' | 'removed';
@@ -307,3 +309,47 @@ export async function notifyOnIntegrationHistoryChangedById<T extends IIntegrati
307309

308310
void api.broadcast('watch.integrationHistory', { clientAction, id: item._id, data: item, diff });
309311
}
312+
313+
export async function notifyOnLivechatDepartmentAgentChanged<T extends ILivechatDepartmentAgents>(
314+
data: Partial<T> & Pick<T, '_id' | 'agentId' | 'departmentId'>,
315+
clientAction: ClientAction = 'updated',
316+
): Promise<void> {
317+
if (!dbWatchersDisabled) {
318+
return;
319+
}
320+
321+
void api.broadcast('watch.livechatDepartmentAgents', { clientAction, id: data._id, data });
322+
}
323+
324+
export async function notifyOnLivechatDepartmentAgentChangedByDepartmentId<T extends ILivechatDepartmentAgents>(
325+
departmentId: T['departmentId'],
326+
clientAction: 'inserted' | 'updated' = 'updated',
327+
): Promise<void> {
328+
if (!dbWatchersDisabled) {
329+
return;
330+
}
331+
332+
const items = LivechatDepartmentAgents.findByDepartmentId(departmentId, { projection: { _id: 1, agentId: 1, departmentId: 1 } });
333+
334+
for await (const item of items) {
335+
void api.broadcast('watch.livechatDepartmentAgents', { clientAction, id: item._id, data: item });
336+
}
337+
}
338+
339+
export async function notifyOnLivechatDepartmentAgentChangedByAgentsAndDepartmentId<T extends ILivechatDepartmentAgents>(
340+
agentsIds: T['agentId'][],
341+
departmentId: T['departmentId'],
342+
clientAction: 'inserted' | 'updated' = 'updated',
343+
): Promise<void> {
344+
if (!dbWatchersDisabled) {
345+
return;
346+
}
347+
348+
const items = LivechatDepartmentAgents.findByAgentsAndDepartmentId(agentsIds, departmentId, {
349+
projection: { _id: 1, agentId: 1, departmentId: 1 },
350+
});
351+
352+
for await (const item of items) {
353+
void api.broadcast('watch.livechatDepartmentAgents', { clientAction, id: item._id, data: item });
354+
}
355+
}

apps/meteor/app/lib/server/methods/updateMessage.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export async function executeUpdateMessage(uid: IUser['_id'], message: AtLeast<I
5353
}
5454

5555
const blockEditInMinutes = settings.get('Message_AllowEditing_BlockEditInMinutes');
56-
const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete');
56+
const bypassBlockTimeLimit = await hasPermissionAsync(uid, 'bypass-time-limit-edit-and-delete', message.rid);
5757

5858
if (!bypassBlockTimeLimit && Match.test(blockEditInMinutes, Number) && blockEditInMinutes !== 0) {
5959
let currentTsDiff = 0;
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
import { LivechatDepartment, Users, LivechatDepartmentAgents, LivechatVisitors } from '@rocket.chat/models';
22

33
import { callbacks } from '../../../../lib/callbacks';
4+
import { notifyOnLivechatDepartmentAgentChanged } from '../../../lib/server/lib/notifyListener';
45

56
callbacks.add('livechat.afterAgentRemoved', async ({ agent }) => {
6-
const departmentIds = (await LivechatDepartmentAgents.findByAgentId(agent._id).toArray()).map((department) => department.departmentId);
7-
await Promise.all([
7+
const departments = await LivechatDepartmentAgents.findByAgentId(agent._id).toArray();
8+
9+
const [, { deletedCount }] = await Promise.all([
810
Users.removeAgent(agent._id),
911
LivechatDepartmentAgents.removeByAgentId(agent._id),
1012
agent.username && LivechatVisitors.removeContactManagerByUsername(agent.username),
11-
departmentIds.length && LivechatDepartment.decreaseNumberOfAgentsByIds(departmentIds),
13+
departments.length && LivechatDepartment.decreaseNumberOfAgentsByIds(departments.map(({ departmentId }) => departmentId)),
1214
]);
15+
16+
if (deletedCount > 0) {
17+
departments.forEach((depAgent) => {
18+
void notifyOnLivechatDepartmentAgentChanged(
19+
{
20+
_id: depAgent._id,
21+
agentId: agent._id,
22+
departmentId: depAgent.departmentId,
23+
},
24+
'removed',
25+
);
26+
});
27+
}
1328
});

apps/meteor/app/livechat/server/lib/Departments.ts

+23-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type { ILivechatDepartment, ILivechatDepartmentAgents } from '@rocket.chat/core-typings';
1+
import type { ILivechatDepartment } from '@rocket.chat/core-typings';
22
import { Logger } from '@rocket.chat/logger';
33
import { LivechatDepartment, LivechatDepartmentAgents, LivechatRooms } from '@rocket.chat/models';
44

55
import { callbacks } from '../../../../lib/callbacks';
6+
import { notifyOnLivechatDepartmentAgentChanged } from '../../../lib/server/lib/notifyListener';
67

78
class DepartmentHelperClass {
89
logger = new Logger('Omnichannel:DepartmentHelper');
@@ -24,29 +25,42 @@ class DepartmentHelperClass {
2425
throw new Error('error-failed-to-delete-department');
2526
}
2627

27-
const agentsIds: string[] = await LivechatDepartmentAgents.findAgentsByDepartmentId<Pick<ILivechatDepartmentAgents, 'agentId'>>(
28-
department._id,
29-
{ projection: { agentId: 1 } },
30-
)
31-
.cursor.map((agent) => agent.agentId)
32-
.toArray();
28+
const removedAgents = await LivechatDepartmentAgents.findByDepartmentId(department._id, { projection: { agentId: 1 } }).toArray();
3329

3430
this.logger.debug(
3531
`Performing post-department-removal actions: ${_id}. Removing department agents, unsetting fallback department and removing department from rooms`,
3632
);
3733

34+
const removeByDept = LivechatDepartmentAgents.removeByDepartmentId(_id);
35+
3836
const promiseResponses = await Promise.allSettled([
39-
LivechatDepartmentAgents.removeByDepartmentId(_id),
37+
removeByDept,
4038
LivechatDepartment.unsetFallbackDepartmentByDepartmentId(_id),
4139
LivechatRooms.bulkRemoveDepartmentAndUnitsFromRooms(_id),
4240
]);
41+
4342
promiseResponses.forEach((response, index) => {
4443
if (response.status === 'rejected') {
4544
this.logger.error(`Error while performing post-department-removal actions: ${_id}. Action No: ${index}. Error:`, response.reason);
4645
}
4746
});
4847

49-
await callbacks.run('livechat.afterRemoveDepartment', { department, agentsIds });
48+
const { deletedCount } = await removeByDept;
49+
50+
if (deletedCount > 0) {
51+
removedAgents.forEach(({ _id: docId, agentId }) => {
52+
void notifyOnLivechatDepartmentAgentChanged(
53+
{
54+
_id: docId,
55+
agentId,
56+
departmentId: _id,
57+
},
58+
'removed',
59+
);
60+
});
61+
}
62+
63+
await callbacks.run('livechat.afterRemoveDepartment', { department, agentsIds: removedAgents.map(({ agentId }) => agentId) });
5064

5165
return ret;
5266
}

apps/meteor/app/livechat/server/lib/Helper.ts

+45-6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ import { i18n } from '../../../../server/lib/i18n';
3737
import { hasRoleAsync } from '../../../authorization/server/functions/hasRole';
3838
import { sendNotification } from '../../../lib/server';
3939
import { sendMessage } from '../../../lib/server/functions/sendMessage';
40+
import {
41+
notifyOnLivechatDepartmentAgentChanged,
42+
notifyOnLivechatDepartmentAgentChangedByAgentsAndDepartmentId,
43+
} from '../../../lib/server/lib/notifyListener';
4044
import { settings } from '../../../settings/server';
4145
import { Livechat as LivechatTyped } from './LivechatTyped';
4246
import { queueInquiry, saveQueueInquiry } from './QueueManager';
@@ -697,14 +701,31 @@ export const updateDepartmentAgents = async (
697701
});
698702

699703
const { upsert = [], remove = [] } = agents;
700-
const agentsRemoved = [];
704+
705+
const agentsUpdated = [];
706+
const agentsRemoved = remove.map(({ agentId }: { agentId: string }) => agentId);
701707
const agentsAdded = [];
702-
for await (const { agentId } of remove) {
703-
await LivechatDepartmentAgents.removeByDepartmentIdAndAgentId(departmentId, agentId);
704-
agentsRemoved.push(agentId);
705-
}
706708

707709
if (agentsRemoved.length > 0) {
710+
const removedIds = await LivechatDepartmentAgents.findByAgentsAndDepartmentId(agentsRemoved, departmentId, {
711+
projection: { agentId: 1 },
712+
}).toArray();
713+
714+
const { deletedCount } = await LivechatDepartmentAgents.removeByIds(removedIds.map(({ _id }) => _id));
715+
716+
if (deletedCount > 0) {
717+
removedIds.forEach(({ _id, agentId }) => {
718+
void notifyOnLivechatDepartmentAgentChanged(
719+
{
720+
_id,
721+
agentId,
722+
departmentId,
723+
},
724+
'removed',
725+
);
726+
});
727+
}
728+
708729
callbacks.runAsync('livechat.removeAgentDepartment', { departmentId, agentsId: agentsRemoved });
709730
}
710731

@@ -714,14 +735,28 @@ export const updateDepartmentAgents = async (
714735
continue;
715736
}
716737

717-
await LivechatDepartmentAgents.saveAgent({
738+
const livechatDepartmentAgent = await LivechatDepartmentAgents.saveAgent({
718739
agentId: agent.agentId,
719740
departmentId,
720741
username: agentFromDb.username || '',
721742
count: agent.count ? parseFromIntOrStr(agent.count) : 0,
722743
order: agent.order ? parseFromIntOrStr(agent.order) : 0,
723744
departmentEnabled,
724745
});
746+
747+
if (livechatDepartmentAgent.upsertedId) {
748+
void notifyOnLivechatDepartmentAgentChanged(
749+
{
750+
_id: livechatDepartmentAgent.upsertedId as any,
751+
agentId: agent.agentId,
752+
departmentId,
753+
},
754+
'inserted',
755+
);
756+
} else {
757+
agentsUpdated.push(agent.agentId);
758+
}
759+
725760
agentsAdded.push(agent.agentId);
726761
}
727762

@@ -732,6 +767,10 @@ export const updateDepartmentAgents = async (
732767
});
733768
}
734769

770+
if (agentsUpdated.length > 0) {
771+
void notifyOnLivechatDepartmentAgentChangedByAgentsAndDepartmentId(agentsUpdated, departmentId);
772+
}
773+
735774
if (agentsRemoved.length > 0 || agentsAdded.length > 0) {
736775
const numAgents = await LivechatDepartmentAgents.countByDepartmentId(departmentId);
737776
await LivechatDepartment.updateNumAgentsById(departmentId, numAgents);

apps/meteor/app/livechat/server/lib/LivechatTyped.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import { FileUpload } from '../../../file-upload/server';
5757
import { deleteMessage } from '../../../lib/server/functions/deleteMessage';
5858
import { sendMessage } from '../../../lib/server/functions/sendMessage';
5959
import { updateMessage } from '../../../lib/server/functions/updateMessage';
60-
import { notifyOnRoomChangedById } from '../../../lib/server/lib/notifyListener';
60+
import { notifyOnLivechatDepartmentAgentChangedByDepartmentId, notifyOnRoomChangedById } from '../../../lib/server/lib/notifyListener';
6161
import * as Mailer from '../../../mailer/server/api';
6262
import { metrics } from '../../../metrics/server';
6363
import { settings } from '../../../settings/server';
@@ -1002,6 +1002,8 @@ class LivechatClass {
10021002

10031003
await Promise.all([LivechatDepartmentAgents.disableAgentsByDepartmentId(_id), LivechatDepartment.archiveDepartment(_id)]);
10041004

1005+
void notifyOnLivechatDepartmentAgentChangedByDepartmentId(_id);
1006+
10051007
await callbacks.run('livechat.afterDepartmentArchived', department);
10061008
}
10071009

@@ -1014,6 +1016,9 @@ class LivechatClass {
10141016

10151017
// TODO: these kind of actions should be on events instead of here
10161018
await Promise.all([LivechatDepartmentAgents.enableAgentsByDepartmentId(_id), LivechatDepartment.unarchiveDepartment(_id)]);
1019+
1020+
void notifyOnLivechatDepartmentAgentChangedByDepartmentId(_id);
1021+
10171022
return true;
10181023
}
10191024

apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ Meteor.startup(async () => {
185185
return false;
186186
}
187187
const blockEditInMinutes = settings.Message_AllowEditing_BlockEditInMinutes as number;
188-
const bypassBlockTimeLimit = hasPermission('bypass-time-limit-edit-and-delete');
188+
const bypassBlockTimeLimit = hasPermission('bypass-time-limit-edit-and-delete', message.rid);
189189

190190
if (!bypassBlockTimeLimit && blockEditInMinutes) {
191191
let msgTs;

apps/meteor/app/utils/rocketchat.info

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "6.9.0"
2+
"version": "6.10.0-develop"
33
}

0 commit comments

Comments
 (0)