-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* add FEATURE_SHOW_NEW_CLASS_VIEW_ENABLED * migration script and provisioning impl * add remove cascade *add seed data --------- Co-authored-by: Igor Richter <[email protected]> Co-authored-by: Arne Gnisa <[email protected]> Co-authored-by: Igor Richter <[email protected]>
- Loading branch information
1 parent
00f8125
commit 071a0ef
Showing
98 changed files
with
2,842 additions
and
132 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
export * from './account.module'; | ||
export * from './account-config'; | ||
export { AccountService, AccountDto } from './services'; | ||
export { AccountService, AccountDto, AccountSaveDto } from './services'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
export * from './account.service'; | ||
export { AccountDto } from './dto'; | ||
export { AccountDto, AccountSaveDto } from './dto'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
222 changes: 222 additions & 0 deletions
222
apps/server/src/modules/authorization/domain/rules/school-system-options.rule.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
import { createMock, DeepMocked } from '@golevelup/ts-jest'; | ||
import { ObjectId } from '@mikro-orm/mongodb'; | ||
import { SchoolSystemOptions } from '@modules/legacy-school'; | ||
import { Test, TestingModule } from '@nestjs/testing'; | ||
import { SchoolEntity, SystemEntity, User } from '@shared/domain/entity'; | ||
import { Permission } from '@shared/domain/interface'; | ||
import { | ||
schoolFactory, | ||
schoolSystemOptionsFactory, | ||
setupEntities, | ||
systemEntityFactory, | ||
userFactory, | ||
} from '@shared/testing'; | ||
import { AuthorizationContextBuilder } from '../mapper'; | ||
import { AuthorizationHelper } from '../service/authorization.helper'; | ||
import { SchoolSystemOptionsRule } from './school-system-options.rule'; | ||
|
||
describe(SchoolSystemOptionsRule.name, () => { | ||
let module: TestingModule; | ||
let rule: SchoolSystemOptionsRule; | ||
|
||
let authorizationHelper: DeepMocked<AuthorizationHelper>; | ||
|
||
beforeAll(async () => { | ||
await setupEntities(); | ||
|
||
module = await Test.createTestingModule({ | ||
providers: [ | ||
SchoolSystemOptionsRule, | ||
{ | ||
provide: AuthorizationHelper, | ||
useValue: createMock<AuthorizationHelper>(), | ||
}, | ||
], | ||
}).compile(); | ||
|
||
rule = module.get(SchoolSystemOptionsRule); | ||
authorizationHelper = module.get(AuthorizationHelper); | ||
}); | ||
|
||
afterAll(async () => { | ||
await module.close(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
describe('isApplicable', () => { | ||
describe('when the entity is applicable', () => { | ||
const setup = () => { | ||
const user: User = userFactory.buildWithId(); | ||
const schoolSystemOptions: SchoolSystemOptions = schoolSystemOptionsFactory.build(); | ||
|
||
return { | ||
user, | ||
schoolSystemOptions, | ||
}; | ||
}; | ||
|
||
it('should return true', () => { | ||
const { user, schoolSystemOptions } = setup(); | ||
|
||
const result = rule.isApplicable(user, schoolSystemOptions); | ||
|
||
expect(result).toEqual(true); | ||
}); | ||
}); | ||
|
||
describe('when the entity is not applicable', () => { | ||
const setup = () => { | ||
const user: User = userFactory.buildWithId(); | ||
|
||
return { | ||
user, | ||
}; | ||
}; | ||
|
||
it('should return false', () => { | ||
const { user } = setup(); | ||
|
||
const result = rule.isApplicable(user, {} as unknown as SchoolSystemOptions); | ||
|
||
expect(result).toEqual(false); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('hasPermission', () => { | ||
describe('when the user accesses a system at his school with the required permissions', () => { | ||
const setup = () => { | ||
const systemEntity: SystemEntity = systemEntityFactory.buildWithId(); | ||
const school: SchoolEntity = schoolFactory.buildWithId({ | ||
systems: [systemEntity], | ||
}); | ||
const schoolSystemOptions: SchoolSystemOptions = schoolSystemOptionsFactory.build({ | ||
systemId: systemEntity.id, | ||
schoolId: school.id, | ||
}); | ||
const user: User = userFactory.buildWithId({ school }); | ||
const authorizationContext = AuthorizationContextBuilder.read([Permission.SCHOOL_SYSTEM_VIEW]); | ||
|
||
authorizationHelper.hasAllPermissions.mockReturnValueOnce(true); | ||
|
||
return { | ||
user, | ||
schoolSystemOptions, | ||
authorizationContext, | ||
}; | ||
}; | ||
|
||
it('should check the permission', () => { | ||
const { user, schoolSystemOptions, authorizationContext } = setup(); | ||
|
||
rule.hasPermission(user, schoolSystemOptions, authorizationContext); | ||
|
||
expect(authorizationHelper.hasAllPermissions).toHaveBeenCalledWith( | ||
user, | ||
authorizationContext.requiredPermissions | ||
); | ||
}); | ||
|
||
it('should return true', () => { | ||
const { user, schoolSystemOptions, authorizationContext } = setup(); | ||
|
||
const result = rule.hasPermission(user, schoolSystemOptions, authorizationContext); | ||
|
||
expect(result).toEqual(true); | ||
}); | ||
}); | ||
|
||
describe('when the user accesses a system at his school, but does not have the required permissions', () => { | ||
const setup = () => { | ||
const systemEntity: SystemEntity = systemEntityFactory.buildWithId(); | ||
const school: SchoolEntity = schoolFactory.buildWithId({ | ||
systems: [systemEntity], | ||
}); | ||
const schoolSystemOptions: SchoolSystemOptions = schoolSystemOptionsFactory.build({ | ||
systemId: systemEntity.id, | ||
schoolId: school.id, | ||
}); | ||
const user: User = userFactory.buildWithId({ school }); | ||
const authorizationContext = AuthorizationContextBuilder.read([Permission.SCHOOL_SYSTEM_VIEW]); | ||
|
||
authorizationHelper.hasAllPermissions.mockReturnValueOnce(false); | ||
|
||
return { | ||
user, | ||
schoolSystemOptions, | ||
authorizationContext, | ||
}; | ||
}; | ||
|
||
it('should return false', () => { | ||
const { user, schoolSystemOptions, authorizationContext } = setup(); | ||
|
||
const result = rule.hasPermission(user, schoolSystemOptions, authorizationContext); | ||
|
||
expect(result).toEqual(false); | ||
}); | ||
}); | ||
|
||
describe('when the system is not part of the users school', () => { | ||
const setup = () => { | ||
const systemEntity: SystemEntity = systemEntityFactory.buildWithId(); | ||
const school: SchoolEntity = schoolFactory.buildWithId({ | ||
systems: [systemEntity], | ||
}); | ||
const schoolSystemOptions: SchoolSystemOptions = schoolSystemOptionsFactory.build({ | ||
systemId: new ObjectId().toHexString(), | ||
schoolId: school.id, | ||
}); | ||
const user: User = userFactory.buildWithId({ school }); | ||
const authorizationContext = AuthorizationContextBuilder.read([Permission.SCHOOL_SYSTEM_VIEW]); | ||
|
||
authorizationHelper.hasAllPermissions.mockReturnValueOnce(true); | ||
|
||
return { | ||
user, | ||
schoolSystemOptions, | ||
authorizationContext, | ||
}; | ||
}; | ||
|
||
it('should return false', () => { | ||
const { user, schoolSystemOptions, authorizationContext } = setup(); | ||
|
||
const result = rule.hasPermission(user, schoolSystemOptions, authorizationContext); | ||
|
||
expect(result).toEqual(false); | ||
}); | ||
}); | ||
|
||
describe('when the user is not at the school', () => { | ||
const setup = () => { | ||
const schoolSystemOptions: SchoolSystemOptions = schoolSystemOptionsFactory.build(); | ||
const systemEntity: SystemEntity = systemEntityFactory.buildWithId(); | ||
const school: SchoolEntity = schoolFactory.buildWithId({ | ||
systems: [systemEntity], | ||
}); | ||
const user: User = userFactory.buildWithId({ school }); | ||
const authorizationContext = AuthorizationContextBuilder.read([Permission.SCHOOL_SYSTEM_VIEW]); | ||
|
||
authorizationHelper.hasAllPermissions.mockReturnValueOnce(true); | ||
|
||
return { | ||
user, | ||
schoolSystemOptions, | ||
authorizationContext, | ||
}; | ||
}; | ||
|
||
it('should return false', () => { | ||
const { user, schoolSystemOptions, authorizationContext } = setup(); | ||
|
||
const result = rule.hasPermission(user, schoolSystemOptions, authorizationContext); | ||
|
||
expect(result).toEqual(false); | ||
}); | ||
}); | ||
}); | ||
}); |
28 changes: 28 additions & 0 deletions
28
apps/server/src/modules/authorization/domain/rules/school-system-options.rule.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { AnyProvisioningOptions, SchoolSystemOptions } from '@modules/legacy-school'; | ||
import { Injectable } from '@nestjs/common'; | ||
import { User } from '@shared/domain/entity'; | ||
import { AuthorizationHelper } from '../service/authorization.helper'; | ||
import { AuthorizationContext, Rule } from '../type'; | ||
|
||
@Injectable() | ||
export class SchoolSystemOptionsRule implements Rule<SchoolSystemOptions> { | ||
constructor(private readonly authorizationHelper: AuthorizationHelper) {} | ||
|
||
public isApplicable(user: User, domainObject: SchoolSystemOptions): boolean { | ||
const isMatched: boolean = domainObject instanceof SchoolSystemOptions<AnyProvisioningOptions>; | ||
|
||
return isMatched; | ||
} | ||
|
||
public hasPermission(user: User, domainObject: SchoolSystemOptions, context: AuthorizationContext): boolean { | ||
const hasPermissions: boolean = this.authorizationHelper.hasAllPermissions(user, context.requiredPermissions); | ||
|
||
const isAtSchool: boolean = user.school.id === domainObject.schoolId; | ||
|
||
const hasSystem: boolean = user.school.systems.getIdentifiers().includes(domainObject.systemId); | ||
|
||
const isAuthorized: boolean = hasPermissions && isAtSchool && hasSystem; | ||
|
||
return isAuthorized; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.