diff --git a/src/models/channel.ts b/src/models/channel.ts index cbe891c3f96c912e7d49d9d624ee6bf57c54e77e..c929f713f4cfe352743a9c0972bc7c64921aca6d 100644 --- a/src/models/channel.ts +++ b/src/models/channel.ts @@ -405,6 +405,15 @@ export class Channel extends ApiKeyObject { }); } + // Get QB Brackets channels by access: where group is Member + static qbGroupIsMember(qb: SelectQueryBuilder<unknown>, groupId: string): Brackets { + return new Brackets(accessQB => { + accessQB.where(':groupId IN (groups.id)', { + groupId: groupId, + }); + }); + } + async canSendCritical(authorizationBag: AuthorizationBag) { if (!authorizationBag) return false; if (!this.channelFlags?.includes(ChannelFlags.critical)) return false; diff --git a/src/services/impl/channels/add-group-to-channel.ts b/src/services/impl/channels/add-group-to-channel.ts index eae547a090712abc44bb182fbb8084100257df26..ae35e6bd9a544f6da89e00bbf9ff280b4a6eee14 100644 --- a/src/services/impl/channels/add-group-to-channel.ts +++ b/src/services/impl/channels/add-group-to-channel.ts @@ -6,8 +6,6 @@ import { AuthorizationBag } from '../../../models/authorization-bag'; import { ServiceFactory } from '../../services-factory'; import { GroupsServiceInterface } from '../../groups-service'; import { AuditChannels } from '../../../log/auditing'; -import { ChannelResponse } from '../../../controllers/channels/dto'; -import { Group } from '../../../models/group'; import { GroupResponse } from '../../../controllers/channels/dto'; import { CernAuthorizationService } from '../../../models/cern-authorization-service'; @@ -16,28 +14,40 @@ export class AddGroupToChannel implements Command { groupsService: GroupsServiceInterface = ServiceFactory.getGroupService(); async execute(transactionManager: EntityManager): Promise<GroupResponse> { - const channel = await transactionManager.findOne(Channel, { - relations: ['owner', 'adminGroup', 'groups'], - where: { - id: this.channelId, - }, - }); - + const channel = await transactionManager.findOneBy(Channel, { id: this.channelId }); if (!channel) throw new NotFoundError('Channel does not exist'); - // you need to be channel admin - if (!(await channel.isAdmin(this.authorizationBag))) + // Get current user groups, to be used next in SQL to compare with channel groups + const userGroups = await CernAuthorizationService.getCurrentUserGroups(this.authorizationBag.userName); + + const qb = await transactionManager + .getRepository(Channel) + .createQueryBuilder('channel') + .leftJoin('channel.owner', 'owner') + .leftJoin('channel.adminGroup', 'adminGroup') + .leftJoin('channel.groups', 'groups') + .where('channel.id = :id', { id: this.channelId }) + .select('channel.id'); + + let rawChannel = await qb + .clone() + .andWhere(Channel.qbUserIsAdmin(qb, this.authorizationBag.userId, userGroups)) + .getRawOne(); + if (!rawChannel) { throw new ForbiddenError("You don't have the rights to manage this channel."); + } - //if added group was already added - if (channel.groups.filter(g => g.groupIdentifier === this.groupName).length > 0) { + const groupToAdd = await this.groupsService.GetOrCreateGroup(this.groupName); + + rawChannel = await qb.clone().andWhere(Channel.qbGroupIsMember(qb, groupToAdd.id)).getRawOne(); + if (rawChannel) { throw new ForbiddenError(`Group ${this.groupName} is already a member.`); } - const groupToAdd = await this.groupsService.GetOrCreateGroup(this.groupName); - channel.addGroup(groupToAdd); - const updatedChannel = await transactionManager.save(channel); - await AuditChannels.setValue(updatedChannel.id, { + // optimized save performance + await transactionManager.createQueryBuilder().relation(Channel, 'groups').of(channel).add(groupToAdd); + + await AuditChannels.setValue(channel.id, { event: 'AddGroup', user: this.authorizationBag.email, groupIdentifier: this.groupName,