Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Permissions out of DB Watcher #32360

Merged
merged 11 commits into from
May 14, 2024
2 changes: 2 additions & 0 deletions apps/meteor/app/api/server/v1/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isBodyParamsValidPermissionUpdate } from '@rocket.chat/rest-typings';
import { Meteor } from 'meteor/meteor';

import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener';
import { API } from '../api';

API.v1.addRoute(
Expand Down Expand Up @@ -70,6 +71,7 @@ API.v1.addRoute(

for await (const permission of bodyParams.permissions) {
await Permissions.setRoles(permission._id, permission.roles);
void notifyOnPermissionChangedById(permission._id);
}

const result = (await Meteor.callAsync('permissions/get')) as IPermission[];
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/app/api/server/v1/roles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { getUsersInRolePaginated } from '../../../authorization/server/functions
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { hasRoleAsync, hasAnyRoleAsync } from '../../../authorization/server/functions/hasRole';
import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { notifyListenerOnRoleChanges } from '../../../lib/server/lib/notifyListenerOnRoleChanges';
import { notifyOnRoleChanged } from '../../../lib/server/lib/notifyListener';
import { settings } from '../../../settings/server/index';
import { API } from '../api';
import { getPaginationItems } from '../helpers/getPaginationItems';
Expand Down Expand Up @@ -180,7 +180,7 @@ API.v1.addRoute(

await Roles.removeById(role._id);

void notifyListenerOnRoleChanges(role._id, 'removed', role);
void notifyOnRoleChanged(role, 'removed');

return API.v1.success();
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Permissions } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { Meteor } from 'meteor/meteor';

import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener';
import { CONSTANTS, AuthorizationUtils } from '../../lib';
import { hasPermissionAsync } from '../functions/hasPermission';

Expand Down Expand Up @@ -41,11 +42,15 @@ Meteor.methods<ServerMethods>({
action: 'Adding_permission',
});
}

// for setting-based-permissions, authorize the group access as well
if (permission.groupPermissionId) {
await Permissions.addRole(permission.groupPermissionId, role);
void notifyOnPermissionChangedById(permission.groupPermissionId);
}

await Permissions.addRole(permission._id, role);

void notifyOnPermissionChangedById(permission._id);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Permissions } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { Meteor } from 'meteor/meteor';

import { notifyOnPermissionChangedById } from '../../../lib/server/lib/notifyListener';
import { CONSTANTS } from '../../lib';
import { hasPermissionAsync } from '../functions/hasPermission';

Expand Down Expand Up @@ -36,10 +37,12 @@ Meteor.methods<ServerMethods>({

// for setting based permissions, revoke the group permission once all setting permissions
// related to this group have been removed

if (permission.groupPermissionId) {
await Permissions.removeRole(permission.groupPermissionId, role);
void notifyOnPermissionChangedById(permission.groupPermissionId);
}

await Permissions.removeRole(permission._id, role);
void notifyOnPermissionChangedById(permission._id);
},
});
65 changes: 63 additions & 2 deletions apps/meteor/app/lib/server/lib/notifyListener.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { api, dbWatchersDisabled } from '@rocket.chat/core-services';
import type { IPbxEvent, IRocketChatRecord, IRoom } from '@rocket.chat/core-typings';
import { PbxEvents, Rooms } from '@rocket.chat/models';
import type { IPermission, IRocketChatRecord, IRoom, ISetting, IPbxEvent, IRole } from '@rocket.chat/core-typings';
import { Rooms, Permissions, Settings, PbxEvents, Roles } from '@rocket.chat/models';

type ClientAction = 'inserted' | 'updated' | 'removed';

Expand Down Expand Up @@ -66,6 +66,43 @@ export async function notifyOnRoomChangedByUserDM<T extends IRoom>(
}
}

export async function notifyOnSettingChanged(setting: ISetting, clientAction: ClientAction = 'updated'): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

void api.broadcast('watch.settings', { clientAction, setting });
}

export async function notifyOnPermissionChanged(permission: IPermission, clientAction: ClientAction = 'updated'): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

void api.broadcast('permission.changed', { clientAction, data: permission });

if (permission.level === 'settings' && permission.settingId) {
const setting = await Settings.findOneNotHiddenById(permission.settingId);
if (!setting) {
return;
}
void notifyOnSettingChanged(setting, 'updated');
}
}

export async function notifyOnPermissionChangedById(pid: IPermission['_id'], clientAction: ClientAction = 'updated'): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

const permission = await Permissions.findOneById(pid);
if (!permission) {
return;
}

return notifyOnPermissionChanged(permission, clientAction);
}

export async function notifyOnPbxEventChangedById<T extends IPbxEvent>(
id: T['_id'],
clientAction: ClientAction = 'updated',
Expand All @@ -80,3 +117,27 @@ export async function notifyOnPbxEventChangedById<T extends IPbxEvent>(
void api.broadcast('watch.pbxevents', { clientAction, id, data: item });
}
}

export async function notifyOnRoleChanged<T extends IRole>(role: T, clientAction: 'removed' | 'changed' = 'changed'): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

void api.broadcast('watch.roles', { clientAction, role });
}

export async function notifyOnRoleChangedById<T extends IRole>(
id: T['_id'],
clientAction: 'removed' | 'changed' = 'changed',
): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

const role = await Roles.findOneById(id);
if (!role) {
return;
}

void notifyOnRoleChanged(role, clientAction);
}
25 changes: 0 additions & 25 deletions apps/meteor/app/lib/server/lib/notifyListenerOnRoleChanges.ts

This file was deleted.

4 changes: 2 additions & 2 deletions apps/meteor/ee/server/lib/roles/insertRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { api, MeteorError } from '@rocket.chat/core-services';
import type { IRole } from '@rocket.chat/core-typings';
import { Roles } from '@rocket.chat/models';

import { notifyListenerOnRoleChanges } from '../../../../app/lib/server/lib/notifyListenerOnRoleChanges';
import { notifyOnRoleChanged } from '../../../../app/lib/server/lib/notifyListener';
import { isValidRoleScope } from '../../../../lib/roles/isValidRoleScope';

type InsertRoleOptions = {
Expand All @@ -22,7 +22,7 @@ export const insertRoleAsync = async (roleData: Omit<IRole, '_id'>, options: Ins

const role = await Roles.createWithRandomId(name, scope, description, false, mandatory2fa);

void notifyListenerOnRoleChanges(role._id, 'inserted', role);
void notifyOnRoleChanged(role);

if (options.broadcastUpdate) {
void api.broadcast('user.roleUpdate', {
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/ee/server/lib/roles/updateRole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { api, MeteorError } from '@rocket.chat/core-services';
import type { IRole } from '@rocket.chat/core-typings';
import { Roles } from '@rocket.chat/models';

import { notifyListenerOnRoleChanges } from '../../../../app/lib/server/lib/notifyListenerOnRoleChanges';
import { notifyOnRoleChangedById } from '../../../../app/lib/server/lib/notifyListener';
import { isValidRoleScope } from '../../../../lib/roles/isValidRoleScope';

type UpdateRoleOptions = {
Expand Down Expand Up @@ -39,7 +39,7 @@ export const updateRole = async (roleId: IRole['_id'], roleData: Omit<IRole, '_i

await Roles.updateById(roleId, roleData.name, roleData.scope, roleData.description, roleData.mandatory2fa);

void notifyListenerOnRoleChanges(roleId);
void notifyOnRoleChangedById(roleId);

if (options.broadcastUpdate) {
void api.broadcast('user.roleUpdate', {
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/server/database/watchCollections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export function getWatchCollections(): string[] {
Users.getCollectionName(),
LivechatInquiry.getCollectionName(),
LivechatDepartmentAgents.getCollectionName(),
Permissions.getCollectionName(),
LoginServiceConfiguration.getCollectionName(),
InstanceStatus.getCollectionName(),
IntegrationHistory.getCollectionName(),
Expand All @@ -50,6 +49,7 @@ export function getWatchCollections(): string[] {
collections.push(Roles.getCollectionName());
collections.push(Rooms.getCollectionName());
collections.push(PbxEvents.getCollectionName());
collections.push(Permissions.getCollectionName());
}

if (onlyCollections.length > 0) {
Expand Down
8 changes: 4 additions & 4 deletions apps/meteor/server/lib/roles/createOrUpdateProtectedRole.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IRole, AtLeast } from '@rocket.chat/core-typings';
import { Roles } from '@rocket.chat/models';

import { notifyListenerOnRoleChanges } from '../../../app/lib/server/lib/notifyListenerOnRoleChanges';
import { notifyOnRoleChanged, notifyOnRoleChangedById } from '../../../app/lib/server/lib/notifyListener';

export const createOrUpdateProtectedRoleAsync = async (
roleId: string,
Expand All @@ -20,12 +20,12 @@ export const createOrUpdateProtectedRoleAsync = async (
roleData.mandatory2fa || role.mandatory2fa,
);

void notifyListenerOnRoleChanges(roleId, 'updated', updatedRole);
void notifyOnRoleChanged(updatedRole);

return;
}

const insertedRole = await Roles.insertOne({
await Roles.insertOne({
_id: roleId,
scope: 'Users',
description: '',
Expand All @@ -34,5 +34,5 @@ export const createOrUpdateProtectedRoleAsync = async (
protected: true,
});

void notifyListenerOnRoleChanges(insertedRole.insertedId, 'inserted');
void notifyOnRoleChangedById(roleId);
};
Loading