diff --git a/api/mocks/repositories/user.repository.mock.ts b/api/mocks/repositories/user.repository.mock.ts index 4c8c03f..81975ef 100644 --- a/api/mocks/repositories/user.repository.mock.ts +++ b/api/mocks/repositories/user.repository.mock.ts @@ -4,7 +4,7 @@ import { IUser } from "src/model/interface"; export class MockUserRepository { - user: User = { + user: any = { firstName: null, lastName: null, id: 'mockId', @@ -20,7 +20,11 @@ export class MockUserRepository { isActive: false, role: null, systems: [], - deletedAt: null + deletedAt: null, + settings: { + id: 'id', + user: null + } } findByUsername = jest.fn().mockImplementation((username: string) => { @@ -28,7 +32,7 @@ export class MockUserRepository { }) createUser = jest.fn().mockImplementation((register: CreateUserDto) => { - const user: User = { + const user: any = { firstName: null, lastName: null, id: 'mockId', @@ -44,7 +48,11 @@ export class MockUserRepository { isActive: false, role: null, systems: [], - deletedAt: null + deletedAt: null, + settings: { + id: 'id', + user: null + } } return user; }) diff --git a/api/src/model/entitites/activity.entity.ts b/api/src/model/entitites/activity.entity.ts index b2b12c5..6730ac8 100644 --- a/api/src/model/entitites/activity.entity.ts +++ b/api/src/model/entitites/activity.entity.ts @@ -6,8 +6,8 @@ import { OneToMany, PrimaryGeneratedColumn, } from 'typeorm'; -import { User } from './user.entity'; import { KeySystem } from './system.entity'; +import { User } from './user'; @Entity() export class Activity { diff --git a/api/src/model/entitites/index.ts b/api/src/model/entitites/index.ts index 28c4a56..185ff2a 100644 --- a/api/src/model/entitites/index.ts +++ b/api/src/model/entitites/index.ts @@ -1,8 +1,7 @@ -export * from './sso.user.entity'; -export * from './user.entity'; export * from './role.entity'; export * from './cylinder.entity'; export * from './key.entity'; export * from './customer.entity'; export * from './key-handout.entity'; export * from './activity.entity'; +export * from './user'; diff --git a/api/src/model/entitites/key-handout.entity.ts b/api/src/model/entitites/key-handout.entity.ts index 32e1bb8..0828d4d 100644 --- a/api/src/model/entitites/key-handout.entity.ts +++ b/api/src/model/entitites/key-handout.entity.ts @@ -8,7 +8,7 @@ import { } from 'typeorm'; import { Key } from './key.entity'; import { Customer } from './customer.entity'; -import { User } from './user.entity'; +import { User } from './user'; @Entity() export class KeyHandout { diff --git a/api/src/model/entitites/log/email.log.entity.ts b/api/src/model/entitites/log/email.log.entity.ts index ac0db66..fecb27f 100644 --- a/api/src/model/entitites/log/email.log.entity.ts +++ b/api/src/model/entitites/log/email.log.entity.ts @@ -1,4 +1,5 @@ import { + AfterLoad, Column, CreateDateColumn, Entity, @@ -25,9 +26,16 @@ export class EmailLog { @Column({ name: 'type', type: 'text',}) type: EmailEvent; + eventName: string; + @ManyToOne(() => KeySystem, { nullable: true }) system: KeySystem; @Column({type: 'boolean'}) success: boolean; + + @AfterLoad() + setType() { + this.eventName = EmailEvent[this.type] + } } diff --git a/api/src/model/entitites/role.entity.ts b/api/src/model/entitites/role.entity.ts index 7333b69..5f7655d 100644 --- a/api/src/model/entitites/role.entity.ts +++ b/api/src/model/entitites/role.entity.ts @@ -4,7 +4,7 @@ import { OneToMany, PrimaryGeneratedColumn, } from 'typeorm'; -import { User } from './user.entity'; +import { User } from './user'; @Entity() export class Role { diff --git a/api/src/model/entitites/system.entity.ts b/api/src/model/entitites/system.entity.ts index a3f62d9..4d9fcda 100644 --- a/api/src/model/entitites/system.entity.ts +++ b/api/src/model/entitites/system.entity.ts @@ -9,8 +9,8 @@ import { UpdateDateColumn, } from 'typeorm'; import { IKeySystem } from '../interface'; -import { User } from './user.entity'; import { Cylinder } from './cylinder.entity'; +import { User } from './user'; @Entity() export class KeySystem implements IKeySystem { diff --git a/api/src/model/entitites/user/index.ts b/api/src/model/entitites/user/index.ts new file mode 100644 index 0000000..5965ca4 --- /dev/null +++ b/api/src/model/entitites/user/index.ts @@ -0,0 +1,2 @@ +export * from './sso.user.entity'; +export * from './user.entity'; diff --git a/api/src/model/entitites/sso.user.entity.ts b/api/src/model/entitites/user/sso.user.entity.ts similarity index 100% rename from api/src/model/entitites/sso.user.entity.ts rename to api/src/model/entitites/user/sso.user.entity.ts diff --git a/api/src/model/entitites/user.entity.ts b/api/src/model/entitites/user/user.entity.ts similarity index 72% rename from api/src/model/entitites/user.entity.ts rename to api/src/model/entitites/user/user.entity.ts index a94cbb8..e9a9875 100644 --- a/api/src/model/entitites/user.entity.ts +++ b/api/src/model/entitites/user/user.entity.ts @@ -1,5 +1,9 @@ import { Exclude, Transform } from 'class-transformer'; +import { IsEmail } from 'class-validator'; +import { IUser } from 'src/model/interface'; import { + BeforeInsert, + BeforeUpdate, Column, CreateDateColumn, DeleteDateColumn, @@ -10,11 +14,10 @@ import { OneToOne, PrimaryGeneratedColumn, } from 'typeorm'; -import { IUser } from '../interface'; +import { Role } from '../role.entity'; +import { KeySystem } from '../system.entity'; import { SSOUser } from './sso.user.entity'; -import { IsEmail } from 'class-validator'; -import { Role } from './role.entity'; -import { KeySystem } from './system.entity'; +import { UserSettings } from './user.settings.entity'; @Entity() export class User implements IUser { @@ -55,6 +58,18 @@ export class User implements IUser { @DeleteDateColumn() deletedAt: Date; + @OneToOne(() => UserSettings, (settings) => settings.user, { cascade: true }) + settings: UserSettings; + accessToken?: string; refreshToken?: string; + + @BeforeInsert() + @BeforeUpdate() + createSettings() { + if (this.settings == null) { + this.settings = {} as any; + } + } + } diff --git a/api/src/model/entitites/user/user.settings.entity.ts b/api/src/model/entitites/user/user.settings.entity.ts new file mode 100644 index 0000000..d021666 --- /dev/null +++ b/api/src/model/entitites/user/user.settings.entity.ts @@ -0,0 +1,25 @@ +import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm"; +import { User } from "./user.entity"; + +@Entity() +export class UserSettings { + @PrimaryGeneratedColumn('uuid') + id: string; + + @OneToOne(() => User, (user) => user.settings) + @JoinColumn() + user: User; + + @Column({ name: 'send_system_access_notification', default: true, type: 'boolean'}) + sendSystemAccessMails: boolean; + + @Column({ name: 'send_user_disabled_notification', default: true, type: 'boolean'}) + sendUserDisabledMails: boolean; + + + @Column({ name: 'send_system_update_notification', default: true, type: 'boolean'}) + sendSystemUpdateMails: boolean; + + + +} \ No newline at end of file diff --git a/api/src/model/interface/user.interface.ts b/api/src/model/interface/user.interface.ts index 82bcb1e..0f4561b 100644 --- a/api/src/model/interface/user.interface.ts +++ b/api/src/model/interface/user.interface.ts @@ -1,4 +1,5 @@ import { Role } from '../entitites'; +import { UserSettings } from '../entitites/user/user.settings.entity'; export interface IUser { id: string; @@ -13,4 +14,6 @@ export interface IUser { deletedAt?: Date; role?: string | Role; + + settings?: UserSettings; } diff --git a/api/src/model/repositories/index.ts b/api/src/model/repositories/index.ts index 9629f28..11bc00a 100644 --- a/api/src/model/repositories/index.ts +++ b/api/src/model/repositories/index.ts @@ -6,3 +6,4 @@ export * from './cylinder.repository'; export * from './key.repository'; export * from './customer.repository'; export * from './activity.repository'; +export * from './user.settings.repository'; diff --git a/api/src/model/repositories/user.settings.repository.ts b/api/src/model/repositories/user.settings.repository.ts new file mode 100644 index 0000000..f67f891 --- /dev/null +++ b/api/src/model/repositories/user.settings.repository.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@nestjs/common'; +import { Repository, DataSource } from 'typeorm'; +import { UserSettings } from '../entitites/user/user.settings.entity'; + +@Injectable() +export class UserSettingsRepository extends Repository { + constructor(dataSource: DataSource) { + super(UserSettings, dataSource.createEntityManager()); + } +} diff --git a/api/src/modules/log/log.service.ts b/api/src/modules/log/log.service.ts index bb2ce3f..d7b8eaa 100644 --- a/api/src/modules/log/log.service.ts +++ b/api/src/modules/log/log.service.ts @@ -3,7 +3,8 @@ import { EmailLogRepository } from 'src/model/repositories/log'; @Injectable() export class LogService { - constructor(private readonly emailLogRepo: EmailLogRepository) {} + constructor(private readonly emailLogRepo: EmailLogRepository) { + } @@ -16,7 +17,6 @@ export class LogService { private async logEmail(data: EmailLogDto) { const log = this.emailLogRepo.create(data); const logEntry = await this.emailLogRepo.save(log); - console.log(logEntry); } } diff --git a/api/src/modules/mail/mail.module.ts b/api/src/modules/mail/mail.module.ts index 67f385f..71f665a 100644 --- a/api/src/modules/mail/mail.module.ts +++ b/api/src/modules/mail/mail.module.ts @@ -40,6 +40,5 @@ import { LogModule } from '../log/log.module'; }) export class MailModule { constructor() { - console.log(join(__dirname, '../../../templates')) } } diff --git a/api/src/modules/system/system.service.ts b/api/src/modules/system/system.service.ts index 3ac55e1..7614122 100644 --- a/api/src/modules/system/system.service.ts +++ b/api/src/modules/system/system.service.ts @@ -82,7 +82,13 @@ export class SystemService { sys.managers = sys.managers.filter( m => m.username != manageObject.email); await this.systemRepo.save(sys); - this.mailService.sendAccessRemovedMail({to: manageObject.email, firstName: manageObject.email, systemName: sys.name}) + const user = await this.userRepo.findOne({ + where: { username: manageObject.email.trim() }, + relations: ['settings'] + }); + if (user.settings.sendSystemAccessMails) { + this.mailService.sendAccessRemovedMail({to: manageObject.email, firstName: manageObject.email, systemName: sys.name}) + } return sys.managers; } @@ -90,14 +96,19 @@ export class SystemService { return sys.managers; } - const user = await this.userRepo.findOneBy({ username: manageObject.email.trim() }); + const user = await this.userRepo.findOne({ + where: { username: manageObject.email.trim() }, + relations: ['settings'] + }); if (!user) { throw new HttpException('Es wurde kein User mit dieser Emailadresse gefunden. Bitte prüfe die Emailadresse und versuche es erneut.', HttpStatus.NOT_FOUND); } sys.managers.push(user); await this.systemRepo.save(sys); - this.mailService.sendAccessGrantedMail({to: user.username, firstName: user.firstName, systemName: sys.name}) + if (user.settings.sendSystemAccessMails) { + this.mailService.sendAccessGrantedMail({to: user.username, firstName: user.firstName, systemName: sys.name}) + } return sys.managers; } diff --git a/api/src/modules/user/user.service.ts b/api/src/modules/user/user.service.ts index e104a36..251076c 100644 --- a/api/src/modules/user/user.service.ts +++ b/api/src/modules/user/user.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { User } from 'src/model/entitites'; import { IUser } from 'src/model/interface'; -import { ActivityRepository, KeySystemRepository, RoleRepository, UserRepository } from 'src/model/repositories'; +import { ActivityRepository, KeySystemRepository, RoleRepository, UserRepository, UserSettingsRepository } from 'src/model/repositories'; import { HelperService } from 'src/shared/service/system.helper.service'; @Injectable() export class UserService { @@ -10,12 +10,15 @@ export class UserService { private readonly roleRepo: RoleRepository, private readonly systemRepo: KeySystemRepository, private readonly systemActivityRepo: ActivityRepository, + private readonly userSettingsRepository: UserSettingsRepository, private readonly helper: HelperService, - ) {} + ) { + } + getAllUsers(): Promise { return this.userRepo.find({ - relations: ['role'], + relations: ['role', 'settings'], where: [{ role: { name: 'user' } }, { role: { name: 'admin' } }], }); } diff --git a/api/src/shared/database/database.module.ts b/api/src/shared/database/database.module.ts index a9d5168..471bd9c 100644 --- a/api/src/shared/database/database.module.ts +++ b/api/src/shared/database/database.module.ts @@ -12,6 +12,7 @@ import { } from 'src/model/entitites'; import { EmailLog } from 'src/model/entitites/log'; import { KeySystem } from 'src/model/entitites/system.entity'; +import { UserSettings } from 'src/model/entitites/user/user.settings.entity'; import { ActivityRepository, CustomerRepository, @@ -21,6 +22,7 @@ import { RoleRepository, SsoUserRepository, UserRepository, + UserSettingsRepository, } from 'src/model/repositories'; import { KeyHandoutRepository } from 'src/model/repositories/key-handout.repository'; import { EmailLogRepository } from 'src/model/repositories/log'; @@ -36,6 +38,7 @@ const ENTITIES = [ KeyHandout, Activity, EmailLog, + UserSettings, ]; const REPOSITORIES = [ UserRepository, @@ -47,7 +50,8 @@ const REPOSITORIES = [ CustomerRepository, KeyHandoutRepository, ActivityRepository, - EmailLogRepository + EmailLogRepository, + UserSettingsRepository ]; @Module({ diff --git a/api/src/shared/service/shared.service.module.ts b/api/src/shared/service/shared.service.module.ts index b6875c7..c76b668 100644 --- a/api/src/shared/service/shared.service.module.ts +++ b/api/src/shared/service/shared.service.module.ts @@ -1,10 +1,7 @@ import { Module } from "@nestjs/common"; import { DatabaseModule } from "../database/database.module"; import { HelperService } from "./system.helper.service"; -import { CylinderRepository, KeySystemRepository } from "src/model/repositories"; -import { Cylinder, User } from "src/model/entitites"; import { ActivityHelperService } from "./activity.logger.service"; -import { CacheModule } from "@nestjs/cache-manager"; @Module({ imports: [ DatabaseModule ], diff --git a/api/src/templates/access-removed.hbs b/api/src/templates/access-removed.hbs index 78ad1d0..3551241 100644 --- a/api/src/templates/access-removed.hbs +++ b/api/src/templates/access-removed.hbs @@ -83,11 +83,11 @@

Hallo {{firstName}},

Du wurdest als Verwalter folgender Schließanlage entfernt:

diff --git a/api/src/templates/access.hbs b/api/src/templates/access.hbs index 41d369f..a7c38a2 100644 --- a/api/src/templates/access.hbs +++ b/api/src/templates/access.hbs @@ -83,11 +83,11 @@

Hallo {{firstName}},

Du wurdest als Verwalter zu folgender Schließanlage hinzugefügt:

diff --git a/client/src/app/modules/admin/all-users/all-users.component.ts b/client/src/app/modules/admin/all-users/all-users.component.ts index 6783f94..5603328 100644 --- a/client/src/app/modules/admin/all-users/all-users.component.ts +++ b/client/src/app/modules/admin/all-users/all-users.component.ts @@ -74,7 +74,16 @@ export class AllUsersComponent { this.deleteUser(event.data.id); } }, - } + }, + { + headerName: 'Benachrichtigungen', + children: [ + { columnGroupShow: "closed", width: 180 , cellRenderer: 'agCheckboxCellRenderer', valueGetter: (data: any) => { return Object.values(data.data.settings).filter(v => typeof v == 'boolean').some((x: any) => x)}, type: 'boolean' }, + { field: 'settings.sendSystemAccessMails', headerName: 'Schlüssesystemzugriff', editable: true, columnGroupShow: "open" }, + { field: 'settings.sendSystemUpdateMails', headerName: 'Schließsystemupdates', editable: true, columnGroupShow: "open" }, + { field: 'settings.sendUserDisabledMails', headerName: 'User deaktiviert', editable: true, columnGroupShow: "open" } + ] + }, ], loading: true, overlayLoadingTemplate: 'Lade Daten...' diff --git a/client/src/app/modules/keys/create/create.component.ts b/client/src/app/modules/keys/create/create.component.ts index 7f6e63c..27213e7 100644 --- a/client/src/app/modules/keys/create/create.component.ts +++ b/client/src/app/modules/keys/create/create.component.ts @@ -62,7 +62,6 @@ export class CreateKeyComponent { } save() { - console.log(this.createForm.value) this.api.createKey(this.createForm.value as any) .pipe( @@ -93,7 +92,6 @@ export class CreateKeyComponent { next: c => { if (c) { this.createForm.controls.cylinder.patchValue(c); - console.log(c); } } }) diff --git a/client/src/app/modules/keys/keys.component.ts b/client/src/app/modules/keys/keys.component.ts index f45f9ce..b5b08f4 100644 --- a/client/src/app/modules/keys/keys.component.ts +++ b/client/src/app/modules/keys/keys.component.ts @@ -195,7 +195,6 @@ export class KeysComponent { disableClose: true }).afterClosed().subscribe({ next: changed => { - console.log(changed) if (changed) { this.loadKeys(); }