Skip to content

Commit

Permalink
Merge branch 'main' into bc-8571
Browse files Browse the repository at this point in the history
  • Loading branch information
Loki-Afro authored Dec 13, 2024
2 parents 5c390f1 + 0df7b67 commit af5d83f
Show file tree
Hide file tree
Showing 18 changed files with 429 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Migration20241113100535 extends Migration {
);

if (teacherRoleUpdate.modifiedCount > 0) {
console.info('Rollback: Permission ROOM_CREATE added to role teacher.');
console.info('Rollback: Permission ROOM_CREATE removed from role teacher.');
}

const roomEditorRoleUpdate = await this.getCollection('roles').updateOne(
Expand All @@ -61,7 +61,7 @@ export class Migration20241113100535 extends Migration {
);

if (roomEditorRoleUpdate.modifiedCount > 0) {
console.info('Rollback: Permission ROOM_DELETE added to role roomeditor.');
console.info('Rollback: Permission ROOM_DELETE removed from role roomeditor.');
}
}
}
40 changes: 40 additions & 0 deletions apps/server/src/migrations/mikro-orm/Migration20241209165812.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Migration } from '@mikro-orm/migrations-mongodb';

export class Migration20241209165812 extends Migration {
async up(): Promise<void> {
// Add ROOM_OWNER role
await this.getCollection('roles').insertOne({
name: 'roomowner',
permissions: [
'ROOM_VIEW',
'ROOM_EDIT',
'ROOM_DELETE',
'ROOM_MEMBERS_ADD',
'ROOM_MEMBERS_REMOVE',
'ROOM_CHANGE_OWNER',
],
});
console.info(
'Added ROOM_OWNER role with ROOM_VIEW, -_EDIT, _DELETE, -_MEMBERS_ADD, -_MEMBERS_REMOVE AND -_CHANGE_OWNER permission'
);

// Add ROOM_ADMIN role
await this.getCollection('roles').insertOne({
name: 'roomadmin',
permissions: ['ROOM_VIEW', 'ROOM_EDIT', 'ROOM_MEMBERS_ADD', 'ROOM_MEMBERS_REMOVE'],
});
console.info(
'Added ROOM_ADMIN role with ROOM_VIEW, ROOM_EDIT, ROOM_MEMBERS_ADD AND ROOM_MEMBERS_REMOVE permissions'
);
}

async down(): Promise<void> {
// Remove ROOM_OWNER role
await this.getCollection('roles').deleteOne({ name: 'roomowner' });
console.info('Rollback: Removed ROOM_OWNER role');

// Remove ROOM_ADMIN role
await this.getCollection('roles').deleteOne({ name: 'roomadmin' });
console.info('Rollback: Removed ROOM_ADMIN role');
}
}
35 changes: 35 additions & 0 deletions apps/server/src/migrations/mikro-orm/Migration20241210152600.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Migration } from '@mikro-orm/migrations-mongodb';

export class Migration20241210152600 extends Migration {
async up(): Promise<void> {
const roomEditorRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomeditor' },
{
$set: {
permissions: ['ROOM_VIEW', 'ROOM_EDIT'],
},
}
);

if (roomEditorRoleUpdate.modifiedCount > 0) {
console.info('Permission ROOM_DELETE removed from role roomeditor.');
}
}

async down(): Promise<void> {
const roomEditorRoleUpdate = await this.getCollection('roles').updateOne(
{ name: 'roomeditor' },
{
$set: {
permissions: ['ROOM_VIEW', 'ROOM_EDIT', 'ROOM_DELETE'],
},
}
);

if (roomEditorRoleUpdate.modifiedCount > 0) {
console.info(
'Rollback: Permissions ROOM_DELETE added to and ROOM_MEMBERS_ADD and ROOM_MEMBERS_REMOVE removed from role roomeditor.'
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ describe(RoomMembershipRule.name, () => {

expect(res).toBe(false);
});

it('should return false for change owner action', () => {
const { user, roomMembershipAuthorizable } = setup();

const res = service.hasPermission(user, roomMembershipAuthorizable, {
action: Action.read,
requiredPermissions: [Permission.ROOM_CHANGE_OWNER],
});

expect(res).toBe(false);
});
});

describe('when user is not member of room', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ export class RoomMembershipRule implements Rule<RoomMembershipAuthorizable> {
this.authorisationInjectionService.injectAuthorizationRule(this);
}

public isApplicable(user: User, object: unknown): boolean {
public isApplicable(_: User, object: unknown): boolean {
const isMatched = object instanceof RoomMembershipAuthorizable;

return isMatched;
}

public hasPermission(user: User, object: RoomMembershipAuthorizable, context: AuthorizationContext): boolean {
const primarySchoolId = user.school.id;
const secondarySchools = user.secondarySchools ?? [];
const secondarySchoolIds = secondarySchools.map(({ school }) => school.id);
if (!this.hasAccessToSchool(user, object.schoolId)) {
return false;
}

if (![primarySchoolId, ...secondarySchoolIds].includes(object.schoolId)) {
if (!this.hasRequiredRoomPermissions(user, object, context.requiredPermissions)) {
return false;
}

Expand All @@ -36,4 +36,30 @@ export class RoomMembershipRule implements Rule<RoomMembershipAuthorizable> {
}
return permissionsThisUserHas.includes(Permission.ROOM_EDIT);
}

private hasAccessToSchool(user: User, schoolId: string): boolean {
const primarySchoolId = user.school.id;
const secondarySchools = user.secondarySchools ?? [];
const secondarySchoolIds = secondarySchools.map(({ school }) => school.id);

return [primarySchoolId, ...secondarySchoolIds].includes(schoolId);
}

private hasRequiredRoomPermissions(
user: User,
object: RoomMembershipAuthorizable,
requiredPermissions: string[]
): boolean {
const roomPermissionsOfUser = this.resolveRoomPermissions(user, object);
const missingPermissions = requiredPermissions.filter((permission) => !roomPermissionsOfUser.includes(permission));
return missingPermissions.length === 0;
}

private resolveRoomPermissions(user: User, object: RoomMembershipAuthorizable): string[] {
const member = object.members.find((m) => m.userId === user.id);
if (!member) {
return [];
}
return member.roles.flatMap((role) => role.permissions ?? []);
}
}
Loading

0 comments on commit af5d83f

Please sign in to comment.