diff --git a/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.spec.ts b/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.spec.ts new file mode 100644 index 00000000000..fda95dab35c --- /dev/null +++ b/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.spec.ts @@ -0,0 +1,69 @@ +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { Test, TestingModule } from '@nestjs/testing'; +import { AuthorizableReferenceType, AuthorizationInjectionService } from '@src/modules/authorization'; +import { CourseReferenceLoader } from './course.reference-loader'; +import { CourseDoService } from '@src/modules/learnroom'; +import { courseFactory } from '@src/modules/learnroom/testing'; + +describe('Course Reference Loader', () => { + let module: TestingModule; + let service: CourseReferenceLoader; + + let courseDoService: DeepMocked; + let injectionService: DeepMocked; + + beforeAll(async () => { + module = await Test.createTestingModule({ + providers: [ + CourseReferenceLoader, + { + provide: CourseDoService, + useValue: createMock(), + }, + { + provide: AuthorizationInjectionService, + useValue: createMock(), + }, + ], + }).compile(); + + service = module.get(CourseReferenceLoader); + courseDoService = module.get(CourseDoService); + injectionService = module.get(AuthorizationInjectionService); + }); + + afterAll(async () => { + await module.close(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe('constructor', () => { + it('should inject itself into the AuthorizationInjectionService', () => { + expect(injectionService.injectReferenceLoader).toHaveBeenCalledWith(AuthorizableReferenceType.Course, service); + }); + }); + + describe('findById', () => { + describe('when id is given', () => { + const setup = () => { + const course = courseFactory.buildWithId(); + courseDoService.findById.mockResolvedValue(course); + + return { + course, + }; + }; + + it('should return a contextExternalTool', async () => { + const { course } = setup(); + + const result = await service.findById(course.id); + + expect(result).toEqual(course); + }); + }); + }); +}); diff --git a/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.ts b/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.ts new file mode 100644 index 00000000000..839259d7bc4 --- /dev/null +++ b/apps/server/src/modules/authorization/domain/reference-loader/course.reference-loader.ts @@ -0,0 +1,22 @@ +import { + AuthorizableReferenceType, + AuthorizationInjectionService, + AuthorizationLoaderServiceGeneric, +} from '@modules/authorization'; +import { Injectable } from '@nestjs/common'; +import { EntityId } from '@shared/domain/types'; +import { CourseDoService } from '@src/modules/learnroom'; +import { Course } from '@src/modules/learnroom/domain'; + +@Injectable() +export class CourseReferenceLoader implements AuthorizationLoaderServiceGeneric { + constructor(private readonly courseService: CourseDoService, injectionService: AuthorizationInjectionService) { + injectionService.injectReferenceLoader(AuthorizableReferenceType.User, this); + } + + public async findById(courseId: EntityId): Promise { + const course: Course = await this.courseService.findById(courseId); + + return course; + } +} diff --git a/apps/server/src/modules/authorization/domain/rules/course.rule.spec.ts b/apps/server/src/modules/authorization/domain/rules/course.rule.spec.ts index 46d616cf45b..8021eec19b7 100644 --- a/apps/server/src/modules/authorization/domain/rules/course.rule.spec.ts +++ b/apps/server/src/modules/authorization/domain/rules/course.rule.spec.ts @@ -3,14 +3,15 @@ import { Test, TestingModule } from '@nestjs/testing'; import { Course, User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; import { courseFactory as courseEntityFactory, roleFactory, setupEntities, userFactory } from '@shared/testing'; -import { AuthorizationHelper } from '../service/authorization.helper'; -import { Action } from '../type'; import { CourseRule } from './course.rule'; +import { AuthorizationHelper, AuthorizationInjectionService } from '../service'; +import { Action } from '../type'; describe('CourseRule', () => { let module: TestingModule; let service: CourseRule; let authorizationHelper: AuthorizationHelper; + let injectionService: AuthorizationInjectionService; let user: User; let entity: Course; const permissionA = 'a' as Permission; @@ -21,11 +22,12 @@ describe('CourseRule', () => { await setupEntities(); module = await Test.createTestingModule({ - providers: [AuthorizationHelper, CourseRule], + providers: [AuthorizationHelper, CourseRule, AuthorizationInjectionService], }).compile(); service = await module.get(CourseRule); authorizationHelper = await module.get(AuthorizationHelper); + injectionService = await module.get(AuthorizationInjectionService); }); beforeEach(() => { @@ -41,6 +43,12 @@ describe('CourseRule', () => { await module.close(); }); + describe('constructor', () => { + it('should inject into AuthorizationInjectionService', () => { + expect(injectionService.getAuthorizationRules()).toContain(service); + }); + }); + describe('when validating an entity', () => { it('should call hasAllPermissions on AuthorizationHelper', () => { entity = courseEntityFactory.build({ teachers: [user] }); diff --git a/apps/server/src/modules/authorization/domain/rules/course.rule.ts b/apps/server/src/modules/authorization/domain/rules/course.rule.ts index c97afb098fa..2e625d75552 100644 --- a/apps/server/src/modules/authorization/domain/rules/course.rule.ts +++ b/apps/server/src/modules/authorization/domain/rules/course.rule.ts @@ -2,12 +2,17 @@ import { Course } from '@modules/learnroom/domain'; import { Injectable } from '@nestjs/common'; import { Course as CourseEntity, User } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; -import { AuthorizationHelper } from '../service/authorization.helper'; import { Action, AuthorizationContext, Rule } from '../type'; +import { AuthorizationHelper, AuthorizationInjectionService } from '../service'; @Injectable() export class CourseRule implements Rule { - constructor(private readonly authorizationHelper: AuthorizationHelper) {} + constructor( + private readonly authorizationHelper: AuthorizationHelper, + authorisationInjectionService: AuthorizationInjectionService + ) { + authorisationInjectionService.injectAuthorizationRule(this); + } public isApplicable(user: User, object: unknown): boolean { const isMatched = object instanceof CourseEntity || object instanceof Course; diff --git a/apps/server/src/modules/authorization/domain/service/reference.loader.ts b/apps/server/src/modules/authorization/domain/service/reference.loader.ts index 6b8342bf969..b9d13cee4c7 100644 --- a/apps/server/src/modules/authorization/domain/service/reference.loader.ts +++ b/apps/server/src/modules/authorization/domain/service/reference.loader.ts @@ -6,7 +6,7 @@ import { Injectable, NotImplementedException } from '@nestjs/common'; import { AuthorizableObject } from '@shared/domain/domain-object'; import { BaseDO } from '@shared/domain/domainobject'; import { EntityId } from '@shared/domain/types'; -import { CourseGroupRepo, CourseRepo, LegacySchoolRepo, SubmissionRepo, TaskRepo, UserRepo } from '@shared/repo'; +import { CourseGroupRepo, CourseRepo, LegacySchoolRepo, SubmissionRepo, TaskRepo } from '@shared/repo'; import { InstanceService } from '../../../instance'; import { AuthorizableReferenceType, AuthorizationLoaderService } from '../type'; import { AuthorizationInjectionService } from './authorization-injection.service'; @@ -14,7 +14,6 @@ import { AuthorizationInjectionService } from './authorization-injection.service @Injectable() export class ReferenceLoader { constructor( - private readonly userRepo: UserRepo, private readonly courseRepo: CourseRepo, private readonly courseGroupRepo: CourseGroupRepo, private readonly taskRepo: TaskRepo, @@ -29,7 +28,6 @@ export class ReferenceLoader { service.injectReferenceLoader(AuthorizableReferenceType.Task, this.taskRepo); service.injectReferenceLoader(AuthorizableReferenceType.Course, this.courseRepo); service.injectReferenceLoader(AuthorizableReferenceType.CourseGroup, this.courseGroupRepo); - service.injectReferenceLoader(AuthorizableReferenceType.User, this.userRepo); service.injectReferenceLoader(AuthorizableReferenceType.School, this.schoolRepo); service.injectReferenceLoader(AuthorizableReferenceType.Lesson, this.lessonService); service.injectReferenceLoader(AuthorizableReferenceType.Team, this.teamAuthorisableService); diff --git a/apps/server/src/modules/authorization/domain/service/rule-manager.ts b/apps/server/src/modules/authorization/domain/service/rule-manager.ts index e601fb84c89..7cc2604acbd 100644 --- a/apps/server/src/modules/authorization/domain/service/rule-manager.ts +++ b/apps/server/src/modules/authorization/domain/service/rule-manager.ts @@ -4,7 +4,6 @@ import { BaseDO } from '@shared/domain/domainobject'; import { User } from '@shared/domain/entity'; import { CourseGroupRule, - CourseRule, GroupRule, InstanceRule, LegacySchoolRule, @@ -25,7 +24,6 @@ import { AuthorizationInjectionService } from './authorization-injection.service export class RuleManager { constructor( courseGroupRule: CourseGroupRule, - courseRule: CourseRule, groupRule: GroupRule, legaySchoolRule: LegacySchoolRule, lessonRule: LessonRule, @@ -41,7 +39,6 @@ export class RuleManager { private readonly authorizationInjectionService: AuthorizationInjectionService ) { this.authorizationInjectionService.injectAuthorizationRule(courseGroupRule); - this.authorizationInjectionService.injectAuthorizationRule(courseRule); this.authorizationInjectionService.injectAuthorizationRule(groupRule); this.authorizationInjectionService.injectAuthorizationRule(legaySchoolRule); this.authorizationInjectionService.injectAuthorizationRule(lessonRule);