-
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.
- Loading branch information
1 parent
718ccaf
commit 5bbb8f8
Showing
8 changed files
with
315 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './user'; |
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,78 @@ | ||
import { EntityId, LanguageType } from '@shared/domain'; | ||
import { AuthorizableObject, DomainObject } from '@shared/domain/domain-object'; | ||
|
||
export interface UserProps extends AuthorizableObject { | ||
createdAt?: Date; | ||
updatedAt?: Date; | ||
email: string; | ||
firstName: string; | ||
lastName: string; | ||
roles: EntityId[]; | ||
schoolId: EntityId; | ||
ldapDn?: string; | ||
externalId?: string; | ||
importHash?: string; | ||
firstNameSearchValues?: string[]; | ||
lastNameSearchValues?: string[]; | ||
emailSearchValues?: string[]; | ||
language?: LanguageType; | ||
forcePasswordChange?: boolean; | ||
preferences?: Record<string, unknown>; | ||
lastLoginSystemChange?: Date; | ||
outdatedSince?: Date; | ||
previousExternalId?: string; | ||
} | ||
|
||
export class User extends DomainObject<UserProps> { | ||
get email(): string { | ||
return this.props.email; | ||
} | ||
|
||
get firstName(): string { | ||
return this.props.firstName; | ||
} | ||
|
||
get lastName(): string { | ||
return this.props.lastName; | ||
} | ||
|
||
get schoolId(): string { | ||
return this.props.schoolId; | ||
} | ||
|
||
get roles(): EntityId[] { | ||
return this.props.roles; | ||
} | ||
|
||
get ldapDn(): string | undefined { | ||
return this.props.ldapDn; | ||
} | ||
|
||
get externalId(): string | undefined { | ||
return this.props.externalId; | ||
} | ||
|
||
get language(): LanguageType | undefined { | ||
return this.props.language; | ||
} | ||
|
||
get forcePasswordChange(): boolean | undefined { | ||
return this.props.forcePasswordChange; | ||
} | ||
|
||
get preferences(): Record<string, unknown> | undefined { | ||
return this.props.preferences; | ||
} | ||
|
||
get lastLoginSystemChange(): Date | undefined { | ||
return this.props.lastLoginSystemChange; | ||
} | ||
|
||
get outdatedSince(): Date | undefined { | ||
return this.props.outdatedSince; | ||
} | ||
|
||
get previousExternalId(): string | undefined { | ||
return this.props.previousExternalId; | ||
} | ||
} |
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,2 @@ | ||
export * from './mapper'; | ||
export * from './user.repo'; |
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 @@ | ||
export * from './user.mapper'; |
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,24 @@ | ||
import { School as SchoolEntity } from '@shared/domain'; | ||
|
||
export class SchoolMapper { | ||
static mapToDO(entity: SchoolEntity): School { | ||
return new School({ | ||
Check failure on line 5 in apps/server/src/modules/user/repo/mapper/school.mapper.ts GitHub Actions / nest_lint
|
||
id: entity.id, | ||
createdAt: entity.createdAt, | ||
updatedAt: entity.updatedAt, | ||
email: entity.email, | ||
}); | ||
} | ||
|
||
static mapToEntity(domainObject: School): SchoolEntity { | ||
return new SchoolEntity({}); | ||
} | ||
|
||
static mapToDOs(entities: SchoolEntity[]): School[] { | ||
return entities.map((entity) => this.mapToDO(entity)); | ||
} | ||
|
||
static mapToEntities(domainObjects: School[]): SchoolEntity[] { | ||
return domainObjects.map((domainObject) => this.mapToEntity(domainObject)); | ||
} | ||
} |
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,56 @@ | ||
import { ObjectId } from '@mikro-orm/mongodb'; | ||
import { User as UserEntity } from '@shared/domain'; | ||
import { User } from '../../domain'; | ||
|
||
export class UserMapper { | ||
static mapToDO(entity: UserEntity): User { | ||
return new User({ | ||
id: entity.id, | ||
createdAt: entity.createdAt, | ||
updatedAt: entity.updatedAt, | ||
email: entity.email, | ||
firstName: entity.firstName, | ||
lastName: entity.lastName, | ||
roles: entity.roles.map((role) => role.id), | ||
Check failure on line 14 in apps/server/src/modules/user/repo/mapper/user.mapper.ts GitHub Actions / nest_lint
Check failure on line 14 in apps/server/src/modules/user/repo/mapper/user.mapper.ts GitHub Actions / nest_lint
|
||
school: SchoolMapper.mapToDO(entity.school), | ||
ldapDn: entity.ldapDn, | ||
externalId: entity.externalId, | ||
importHash: entity.importHash, | ||
firstNameSearchValues: entity.firstNameSearchValues, | ||
lastNameSearchValues: entity.lastNameSearchValues, | ||
emailSearchValues: entity.emailSearchValues, | ||
language: entity.language, | ||
forcePasswordChange: entity.forcePasswordChange, | ||
preferences: entity.preferences, | ||
lastLoginSystemChange: entity.lastLoginSystemChange, | ||
outdatedSince: entity.outdatedSince, | ||
previousExternalId: entity.previousExternalId, | ||
}); | ||
} | ||
|
||
static mapToEntity(domainObject: User): UserEntity { | ||
return new UserEntity({ | ||
email: domainObject.email, | ||
firstName: domainObject.firstName, | ||
lastName: domainObject.lastName, | ||
school: new ObjectId(domainObject.school), | ||
roles: domainObject.roles.map((roleId) => new ObjectId(roleId)), | ||
ldapDn: domainObject.ldapDn, | ||
externalId: domainObject.externalId, | ||
language: domainObject.language, | ||
forcePasswordChange: domainObject.forcePasswordChange, | ||
preferences: domainObject.preferences, | ||
lastLoginSystemChange: domainObject.lastLoginSystemChange, | ||
outdatedSince: domainObject.outdatedSince, | ||
previousExternalId: domainObject.previousExternalId, | ||
}); | ||
} | ||
|
||
static mapToDOs(entities: UserEntity[]): User[] { | ||
return entities.map((entity) => this.mapToDO(entity)); | ||
} | ||
|
||
static mapToEntities(domainObjects: User[]): UserEntity[] { | ||
return domainObjects.map((domainObject) => this.mapToEntity(domainObject)); | ||
} | ||
} |
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,134 @@ | ||
import { Collection, Entity, Index, ManyToMany, ManyToOne, Property } from '@mikro-orm/core'; | ||
import { IEntityWithSchool } from '../interface'; | ||
import { BaseEntityWithTimestamps } from './base.entity'; | ||
import { Role } from './role.entity'; | ||
import type { School } from './school.entity'; | ||
|
||
export enum LanguageType { | ||
DE = 'de', | ||
EN = 'en', | ||
ES = 'es', | ||
UK = 'uk', | ||
} | ||
|
||
export interface IUserProperties { | ||
email: string; | ||
firstName: string; | ||
lastName: string; | ||
school: School; | ||
roles: Role[]; | ||
ldapDn?: string; | ||
externalId?: string; | ||
language?: LanguageType; | ||
forcePasswordChange?: boolean; | ||
preferences?: Record<string, unknown>; | ||
deletedAt?: Date; | ||
lastLoginSystemChange?: Date; | ||
outdatedSince?: Date; | ||
previousExternalId?: string; | ||
} | ||
|
||
@Entity({ tableName: 'users' }) | ||
@Index({ properties: ['id', 'email'] }) | ||
@Index({ properties: ['firstName', 'lastName'] }) | ||
@Index({ properties: ['externalId', 'school'] }) | ||
@Index({ properties: ['school', 'ldapDn'] }) | ||
@Index({ properties: ['school', 'roles'] }) | ||
export class User extends BaseEntityWithTimestamps implements IEntityWithSchool { | ||
@Property() | ||
@Index() | ||
// @Unique() | ||
email: string; | ||
|
||
@Property() | ||
firstName: string; | ||
|
||
@Property() | ||
lastName: string; | ||
|
||
@Index() | ||
@ManyToMany({ fieldName: 'roles', entity: () => Role }) | ||
roles = new Collection<Role>(this); | ||
|
||
@Index() | ||
@ManyToOne('School', { fieldName: 'schoolId' }) | ||
school: School; | ||
|
||
@Property({ nullable: true }) | ||
@Index() | ||
ldapDn?: string; | ||
|
||
@Property({ nullable: true, fieldName: 'ldapId' }) | ||
externalId?: string; | ||
|
||
@Property({ nullable: true }) | ||
previousExternalId?: string; | ||
|
||
@Property({ nullable: true }) | ||
@Index() | ||
importHash?: string; | ||
|
||
@Property({ nullable: true }) | ||
firstNameSearchValues?: string[]; | ||
|
||
@Property({ nullable: true }) | ||
lastNameSearchValues?: string[]; | ||
|
||
@Property({ nullable: true }) | ||
emailSearchValues?: string[]; | ||
|
||
@Property({ nullable: true }) | ||
language?: LanguageType; | ||
|
||
@Property({ nullable: true }) | ||
forcePasswordChange?: boolean; | ||
|
||
@Property({ nullable: true }) | ||
preferences?: Record<string, unknown>; | ||
|
||
@Property({ nullable: true }) | ||
@Index() | ||
deletedAt?: Date; | ||
|
||
@Property({ nullable: true }) | ||
lastLoginSystemChange?: Date; | ||
|
||
@Property({ nullable: true }) | ||
outdatedSince?: Date; | ||
|
||
constructor(props: IUserProperties) { | ||
super(); | ||
this.firstName = props.firstName; | ||
this.lastName = props.lastName; | ||
this.email = props.email; | ||
this.school = props.school; | ||
this.roles.set(props.roles); | ||
this.ldapDn = props.ldapDn; | ||
this.externalId = props.externalId; | ||
this.forcePasswordChange = props.forcePasswordChange; | ||
this.language = props.language; | ||
this.preferences = props.preferences ?? {}; | ||
this.deletedAt = props.deletedAt; | ||
this.lastLoginSystemChange = props.lastLoginSystemChange; | ||
this.outdatedSince = props.outdatedSince; | ||
this.previousExternalId = props.previousExternalId; | ||
} | ||
|
||
public resolvePermissions(): string[] { | ||
if (!this.roles.isInitialized(true)) { | ||
throw new Error('Roles items are not loaded.'); | ||
} | ||
|
||
let permissions: string[] = []; | ||
|
||
const roles = this.roles.getItems(); | ||
roles.forEach((role) => { | ||
const rolePermissions = role.resolvePermissions(); | ||
permissions = [...permissions, ...rolePermissions]; | ||
}); | ||
|
||
const uniquePermissions = [...new Set(permissions)]; | ||
|
||
return uniquePermissions; | ||
} | ||
} |
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,19 @@ | ||
import { EntityManager, ObjectId } from '@mikro-orm/mongodb'; | ||
import { Injectable } from '@nestjs/common'; | ||
import { EntityId, User as UserEntity } from '@shared/domain'; | ||
import { User } from '../domain'; | ||
import { UserMapper } from './mapper'; | ||
|
||
@Injectable() | ||
export class UserRepo { | ||
constructor(private readonly em: EntityManager) {} | ||
|
||
async findById(userId: EntityId): Promise<User> { | ||
const user = await this.em.findOneOrFail( | ||
UserEntity, | ||
{ _id: new ObjectId(userId) }, | ||
{ populate: ['school', 'roles'] } | ||
); | ||
return UserMapper.mapToDO(user); | ||
} | ||
} |