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: LoginServiceConfiguration entity out of DB Watcher #32373

Merged
merged 11 commits into from
May 15, 2024
62 changes: 54 additions & 8 deletions apps/meteor/app/lib/server/lib/notifyListener.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { api, dbWatchersDisabled } from '@rocket.chat/core-services';
import type { IPermission, IRocketChatRecord, IRoom, ISetting, IPbxEvent, IRole, IIntegration } from '@rocket.chat/core-typings';
import { Rooms, Permissions, Settings, PbxEvents, Roles, Integrations } from '@rocket.chat/models';
import type {
IRocketChatRecord,
IRoom,
ILoginServiceConfiguration,
ISetting,
IRole,
IPermission,
IIntegration,
IPbxEvent,
LoginServiceConfiguration as LoginServiceConfigurationData,
} from '@rocket.chat/core-typings';
import { Rooms, Permissions, Settings, PbxEvents, Roles, Integrations, LoginServiceConfiguration } from '@rocket.chat/models';

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

Expand Down Expand Up @@ -28,6 +38,7 @@ export async function notifyOnRoomChangedById<T extends IRocketChatRecord>(
}

const eligibleIds = Array.isArray(ids) ? ids : [ids];

const items = Rooms.findByIds(eligibleIds);

for await (const item of items) {
Expand Down Expand Up @@ -112,10 +123,11 @@ export async function notifyOnPbxEventChangedById<T extends IPbxEvent>(
}

const item = await PbxEvents.findOneById(id);

if (item) {
void api.broadcast('watch.pbxevents', { clientAction, id, data: item });
if (!item) {
return;
}

void api.broadcast('watch.pbxevents', { clientAction, id, data: item });
}

export async function notifyOnRoleChanged<T extends IRole>(role: T, clientAction: 'removed' | 'changed' = 'changed'): Promise<void> {
Expand All @@ -142,6 +154,39 @@ export async function notifyOnRoleChangedById<T extends IRole>(
void notifyOnRoleChanged(role, clientAction);
}

export async function notifyOnLoginServiceConfigurationChanged<T extends ILoginServiceConfiguration>(
service: Partial<T> & Pick<T, '_id'>,
clientAction: ClientAction = 'updated',
): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

void api.broadcast('watch.loginServiceConfiguration', {
clientAction,
id: service._id,
data: service,
});
}

export async function notifyOnLoginServiceConfigurationChangedByService<T extends ILoginServiceConfiguration>(
service: T['service'],
clientAction: ClientAction = 'updated',
): Promise<void> {
if (!dbWatchersDisabled) {
return;
}

const item = await LoginServiceConfiguration.findOneByService<Omit<LoginServiceConfigurationData, 'secret'>>(service, {
projection: { secret: 0 },
});
if (!item) {
return;
}

void notifyOnLoginServiceConfigurationChanged(item, clientAction);
}

export async function notifyOnIntegrationChanged<T extends IIntegration>(data: T, clientAction: ClientAction = 'updated'): Promise<void> {
if (!dbWatchersDisabled) {
return;
Expand All @@ -159,10 +204,11 @@ export async function notifyOnIntegrationChangedById<T extends IIntegration>(
}

const item = await Integrations.findOneById(id);

if (item) {
void api.broadcast('watch.integrations', { clientAction, id: item._id, data: item });
if (!item) {
return;
}

void api.broadcast('watch.integrations', { clientAction, id: item._id, data: item });
}

export async function notifyOnIntegrationChangedByUserId<T extends IIntegration>(
Expand Down
19 changes: 18 additions & 1 deletion apps/meteor/app/meteor-accounts-saml/server/lib/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { LoginServiceConfiguration } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import { SystemLogger } from '../../../../server/lib/logger/system';
import {
notifyOnLoginServiceConfigurationChanged,
notifyOnLoginServiceConfigurationChangedByService,
} from '../../../lib/server/lib/notifyListener';
import { settings, settingsRegistry } from '../../../settings/server';
import type { IServiceProviderOptions } from '../definition/IServiceProviderOptions';
import { SAMLUtils } from './Utils';
Expand Down Expand Up @@ -117,9 +121,22 @@ export const loadSamlServiceProviders = async function (): Promise<void> {
const samlConfigs = getSamlConfigs(key);
SAMLUtils.log(key);
await LoginServiceConfiguration.createOrUpdateService(serviceName, samlConfigs);
void notifyOnLoginServiceConfigurationChangedByService(serviceName);
return configureSamlService(samlConfigs);
}
await LoginServiceConfiguration.removeService(serviceName);

const service = await LoginServiceConfiguration.findOneByService(serviceName, { projection: { _id: 1 } });
if (!service?._id) {
return false;
}

const { deletedCount } = await LoginServiceConfiguration.removeService(service._id);
if (!deletedCount) {
return false;
}

void notifyOnLoginServiceConfigurationChanged({ _id: service._id }, 'removed');

return false;
}),
)
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(),
LoginServiceConfiguration.getCollectionName(),
InstanceStatus.getCollectionName(),
IntegrationHistory.getCollectionName(),
EmailInbox.getCollectionName(),
Expand All @@ -50,6 +49,7 @@ export function getWatchCollections(): string[] {
collections.push(PbxEvents.getCollectionName());
collections.push(Integrations.getCollectionName());
collections.push(Permissions.getCollectionName());
collections.push(LoginServiceConfiguration.getCollectionName());
}

if (onlyCollections.length > 0) {
Expand Down
13 changes: 12 additions & 1 deletion apps/meteor/server/lib/oauth/updateOAuthServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import type {
import { LoginServiceConfiguration } from '@rocket.chat/models';

import { CustomOAuth } from '../../../app/custom-oauth/server/custom_oauth_server';
import {
notifyOnLoginServiceConfigurationChanged,
notifyOnLoginServiceConfigurationChangedByService,
} from '../../../app/lib/server/lib/notifyListener';
import { settings } from '../../../app/settings/server/cached';
import { logger } from './logger';

Expand Down Expand Up @@ -113,8 +117,15 @@ export async function updateOAuthServices(): Promise<void> {
}

await LoginServiceConfiguration.createOrUpdateService(serviceKey, data);
void notifyOnLoginServiceConfigurationChangedByService(serviceKey);
} else {
await LoginServiceConfiguration.removeService(serviceKey);
const service = await LoginServiceConfiguration.findOneByService(serviceName, { projection: { _id: 1 } });
if (service?._id) {
const { deletedCount } = await LoginServiceConfiguration.removeService(service._id);
if (deletedCount > 0) {
void notifyOnLoginServiceConfigurationChanged({ _id: service._id }, 'removed');
}
}
}
}
}
15 changes: 10 additions & 5 deletions apps/meteor/server/models/raw/LoginServiceConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { LoginServiceConfiguration, RocketChatRecordDeleted } from '@rocket.chat/core-typings';
import type { ILoginServiceConfigurationModel } from '@rocket.chat/model-typings';
import type { Collection, Db, DeleteResult } from 'mongodb';
import type { Collection, Db, DeleteResult, Document, FindOptions } from 'mongodb';

import { BaseRaw } from './BaseRaw';

Expand All @@ -15,7 +15,7 @@ export class LoginServiceConfigurationRaw extends BaseRaw<LoginServiceConfigurat
}

async createOrUpdateService(
serviceName: string,
serviceName: LoginServiceConfiguration['service'],
serviceData: Partial<LoginServiceConfiguration>,
): Promise<LoginServiceConfiguration['_id']> {
const service = serviceName.toLowerCase();
Expand Down Expand Up @@ -44,9 +44,14 @@ export class LoginServiceConfigurationRaw extends BaseRaw<LoginServiceConfigurat
return existing._id;
}

async removeService(serviceName: string): Promise<DeleteResult> {
const service = serviceName.toLowerCase();
async removeService(_id: LoginServiceConfiguration['_id']): Promise<DeleteResult> {
return this.deleteOne({ _id });
}

return this.deleteOne({ service });
async findOneByService<P extends Document = LoginServiceConfiguration>(
serviceName: LoginServiceConfiguration['service'],
options?: FindOptions<P>,
): Promise<P | null> {
return this.findOne({ service: serviceName.toLowerCase() }, options);
}
}
2 changes: 1 addition & 1 deletion packages/core-services/src/events/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type LoginServiceConfigurationEvent = {
}
| {
clientAction: Omit<ClientAction, 'removed'>;
data: Partial<ILoginServiceConfiguration>;
data: Omit<Partial<ILoginServiceConfiguration>, 'secret'> & { secret?: never };
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import type { LoginServiceConfiguration } from '@rocket.chat/core-typings';
import type { DeleteResult } from 'mongodb';
import type { DeleteResult, Document, FindOptions } from 'mongodb';

import type { IBaseModel } from './IBaseModel';

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ILoginServiceConfigurationModel extends IBaseModel<LoginServiceConfiguration> {
createOrUpdateService(serviceName: string, serviceData: Partial<LoginServiceConfiguration>): Promise<LoginServiceConfiguration['_id']>;
removeService(serviceName: string): Promise<DeleteResult>;
createOrUpdateService(
serviceName: LoginServiceConfiguration['service'],
serviceData: Partial<LoginServiceConfiguration>,
): Promise<LoginServiceConfiguration['_id']>;
removeService(_id: LoginServiceConfiguration['_id']): Promise<DeleteResult>;
findOneByService<P extends Document = LoginServiceConfiguration>(
serviceName: LoginServiceConfiguration['service'],
options?: FindOptions<P>,
): Promise<P | null>;
}