From 4357c7fc597dc03eb2596af07f8c5779af475077 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Wed, 6 Oct 2021 14:19:10 +0300 Subject: [PATCH] update user service, name pipe, initials avatars --- .../user-profile-screen.component.ts | 6 +- .../reset-password.component.ts | 4 +- .../user-details/user-details.component.ts | 10 +-- .../confirm-delete-users-dialog.component.ts | 12 +-- .../screens/audit/audit-screen.component.html | 6 +- ...er-templates-listing-screen.component.html | 2 +- .../screens/trash/trash-screen.component.html | 2 +- .../user-listing-screen.component.html | 2 +- .../user-listing-screen.component.ts | 24 +++--- .../team-members-manager.component.html | 4 +- .../dossier-details.component.html | 2 +- .../dossier-details.component.ts | 4 +- .../table-item/table-item.component.html | 2 +- .../dossier-overview-screen.component.html | 2 +- .../table-item/table-item.component.html | 2 +- .../file-preview-screen.component.html | 4 +- .../assign-user-dropdown.component.html | 2 +- .../user-button/user-button.component.html | 2 +- .../initials-avatar.component.html | 8 +- .../initials-avatar.component.ts | 78 ++++++----------- .../team-members/team-members.component.html | 2 +- .../src/app/modules/shared/pipes/name.pipe.ts | 53 +++++++++++- apps/red-ui/src/app/services/user.service.ts | 86 +++++++++++-------- apps/red-ui/src/app/state/app-state.guard.ts | 4 +- libs/common-ui | 2 +- libs/red-ui-http/src/lib/api.module.ts | 2 - 26 files changed, 179 insertions(+), 148 deletions(-) diff --git a/apps/red-ui/src/app/components/user-profile/user-profile-screen.component.ts b/apps/red-ui/src/app/components/user-profile/user-profile-screen.component.ts index 56e9cf409..c7d14e425 100644 --- a/apps/red-ui/src/app/components/user-profile/user-profile-screen.component.ts +++ b/apps/red-ui/src/app/components/user-profile/user-profile-screen.component.ts @@ -4,7 +4,6 @@ import { ProfileModel, UserService } from '@services/user.service'; import { PermissionsService } from '@services/permissions.service'; import { LanguageService } from '@i18n/language.service'; import { TranslateService } from '@ngx-translate/core'; -import { UserControllerService } from '@redaction/red-ui-http'; import { ConfigService } from '@services/config.service'; import { DomSanitizer } from '@angular/platform-browser'; import { languagesTranslations } from '../../translations/languages-translations'; @@ -27,7 +26,6 @@ export class UserProfileScreenComponent implements OnInit { private readonly _formBuilder: FormBuilder, private readonly _userService: UserService, private readonly _configService: ConfigService, - private readonly _userControllerService: UserControllerService, private readonly _languageService: LanguageService, private readonly _domSanitizer: DomSanitizer, private readonly _translateService: TranslateService, @@ -82,14 +80,14 @@ export class UserProfileScreenComponent implements OnInit { const value = this.formGroup.value as ProfileModel; delete value.language; - await this._userControllerService + await this._userService .updateMyProfile({ ...value, }) .toPromise(); await this._userService.loadCurrentUser(); - await this._userService.loadAllUsers(); + await this._userService.loadAll().toPromise(); } this._initializeForm(); diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts index a27419d23..0740d4ad1 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/reset-password/reset-password.component.ts @@ -1,6 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; -import { UserControllerService } from '@redaction/red-ui-http'; import { UserService } from '@services/user.service'; import { LoadingService } from '@iqser/common-ui'; import { User } from '@models/user'; @@ -19,14 +18,13 @@ export class ResetPasswordComponent { constructor( private readonly _formBuilder: FormBuilder, - private readonly _userControllerService: UserControllerService, private readonly _userService: UserService, private readonly _loadingService: LoadingService, ) {} async save() { this._loadingService.start(); - await this._userControllerService + await this._userService .resetPassword( { password: this.passwordForm.get('temporaryPassword').value, diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts index 8a779d360..899bae8de 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-user-dialog/user-details/user-details.component.ts @@ -1,11 +1,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { UserControllerService } from '@redaction/red-ui-http'; import { AdminDialogService } from '../../../services/admin-dialog.service'; import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; import { rolesTranslations } from '../../../../../translations/roles-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { User } from '@models/user'; +import { UserService } from '@services/user.service'; @Component({ selector: 'redaction-user-details', @@ -29,7 +29,7 @@ export class UserDetailsComponent implements OnInit { private readonly _toaster: Toaster, private readonly _dialogService: AdminDialogService, private readonly _loadingService: LoadingService, - private readonly _userControllerService: UserControllerService, + private readonly _userService: UserService, ) {} get changed(): boolean { @@ -102,8 +102,8 @@ export class UserDetailsComponent implements OnInit { const userData = { ...this.userForm.getRawValue(), roles: this.activeRoles }; if (!this.user) { - await this._userControllerService - .createUser(userData) + await this._userService + .create(userData) .toPromise() .then(() => { this.closeDialog.emit(true); @@ -117,7 +117,7 @@ export class UserDetailsComponent implements OnInit { this._loadingService.stop(); }); } else { - await this._userControllerService.updateProfile(userData, this.user.id).toPromise(); + await this._userService.updateProfile(userData, this.user.id).toPromise(); this.closeDialog.emit(true); } } diff --git a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts index 984effd5f..0d07e6cc4 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component.ts @@ -1,10 +1,10 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { UserControllerService } from '@redaction/red-ui-http'; -import { LoadingService } from '@iqser/common-ui'; +import { List, LoadingService } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { User } from '@models/user'; import { DossiersService } from '../../../dossier/services/dossiers.service'; +import { UserService } from '@services/user.service'; @Component({ selector: 'redaction-confirm-delete-users-dialog', @@ -20,11 +20,11 @@ export class ConfirmDeleteUsersDialogComponent { dossiersCount: number; constructor( - private readonly _dossiersService: DossiersService, + private readonly _userService: UserService, private readonly _loadingService: LoadingService, - private readonly _userControllerService: UserControllerService, + private readonly _dossiersService: DossiersService, + @Inject(MAT_DIALOG_DATA) readonly users: List, readonly dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) readonly users: User[], ) { this.dossiersCount = this._dossiersService.all.filter(dw => { for (const user of this.users) { @@ -43,7 +43,7 @@ export class ConfirmDeleteUsersDialogComponent { async deleteUser() { if (this.valid) { this._loadingService.start(); - await this._userControllerService.deleteUsers(this.users.map(u => u.id)).toPromise(); + await this._userService.delete(this.users.map(u => u.id)).toPromise(); this.dialogRef.close(true); } else { this.showToast = true; diff --git a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html index bcebedeab..aef887f5f 100644 --- a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html @@ -57,7 +57,7 @@ @@ -66,7 +66,7 @@ @@ -108,7 +108,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html index 84aba15e9..e77956dfd 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.html @@ -76,7 +76,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html index f4d327ede..2b2573d95 100644 --- a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html @@ -63,7 +63,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html index 4a52d84ad..6a76d1768 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html @@ -68,7 +68,7 @@
- +
{{ user.email || '-' }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts index 63bcb3642..bb1715711 100644 --- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts @@ -1,19 +1,18 @@ -import { Component, forwardRef, Injector, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { Component, forwardRef, Injector, OnInit } from '@angular/core'; import { UserService } from '@services/user.service'; -import { UserControllerService } from '@redaction/red-ui-http'; import { AdminDialogService } from '../../services/admin-dialog.service'; import { TranslateService } from '@ngx-translate/core'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { TranslateChartService } from '@services/translate-chart.service'; import { CircleButtonTypes, - DefaultListingServices, + DefaultListingServicesTmp, + EntitiesService, IconButtonTypes, ListingComponent, LoadingService, TableColumnConfig, } from '@iqser/common-ui'; -import { InitialsAvatarComponent } from '@shared/components/initials-avatar/initials-avatar.component'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { rolesTranslations } from '../../../../translations/roles-translations'; @@ -23,7 +22,14 @@ import { User } from '@models/user'; @Component({ templateUrl: './user-listing-screen.component.html', styleUrls: ['./user-listing-screen.component.scss'], - providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => UserListingScreenComponent) }], + providers: [ + ...DefaultListingServicesTmp, + { provide: EntitiesService, useExisting: UserService }, + { + provide: ListingComponent, + useExisting: forwardRef(() => UserListingScreenComponent), + }, + ], }) export class UserListingScreenComponent extends ListingComponent implements OnInit { readonly translations = rolesTranslations; @@ -40,8 +46,6 @@ export class UserListingScreenComponent extends ListingComponent implement ]; collapsedDetails = false; chartData: DoughnutChartConfig[] = []; - @ViewChildren(InitialsAvatarComponent) - private readonly _avatars: QueryList; constructor( readonly userService: UserService, @@ -49,7 +53,6 @@ export class UserListingScreenComponent extends ListingComponent implement private readonly _loadingService: LoadingService, private readonly _dialogService: AdminDialogService, private readonly _translateService: TranslateService, - private readonly _userControllerService: UserControllerService, private readonly _translateChartService: TranslateChartService, ) { super(_injector); @@ -87,9 +90,8 @@ export class UserListingScreenComponent extends ListingComponent implement async toggleActive(user: User) { this._loadingService.start(); const requestBody = { ...user, roles: user.isActive ? [] : ['RED_USER'] }; - await this._userControllerService.updateProfile(requestBody, user.id).toPromise(); + await this.userService.updateProfile(requestBody, user.id).toPromise(); await this._loadData(); - this._avatars.find(item => item.userId === user.id).detectChanges(); } bulkDelete() { @@ -97,7 +99,7 @@ export class UserListingScreenComponent extends ListingComponent implement } private async _loadData() { - this.entitiesService.setEntities(await this.userService.loadAllUsers()); + await this.userService.loadAll().toPromise(); this._computeStats(); this._loadingService.stop(); } diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.html b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.html index 6802347a2..c2fa279d7 100644 --- a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.html @@ -36,8 +36,8 @@

 
     
-            
+            
             
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html index 0444ba767..ee2d64bf2 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html @@ -15,7 +15,7 @@
- + { this.calculateChartConfig(); @@ -75,7 +75,7 @@ export class DossierDetailsComponent implements OnInit { } async assignOwner(user: User | string) { - this.owner = typeof user === 'string' ? this._userService.getRedUserById(user) : user; + this.owner = typeof user === 'string' ? this._userService.find(user) : user; const activeDossier = this.dossiersService.activeDossier; const dossierRequest: DossierRequest = { ...activeDossier, dossierId: activeDossier.dossierId, ownerId: this.owner.id }; await this.dossiersService.createOrUpdate(dossierRequest).toPromise(); diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html index 0901befe5..ccb7f4a9a 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html @@ -34,7 +34,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html index d8fddddee..69bf6ca42 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html @@ -131,7 +131,7 @@
- +
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index ef520987f..259a60597 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -42,7 +42,7 @@ @@ -83,7 +83,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.html b/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.html index 78afc5948..d4c0d2907 100644 --- a/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.html +++ b/apps/red-ui/src/app/modules/shared/components/assign-user-dropdown/assign-user-dropdown.component.html @@ -27,5 +27,5 @@
- + diff --git a/apps/red-ui/src/app/modules/shared/components/buttons/user-button/user-button.component.html b/apps/red-ui/src/app/modules/shared/components/buttons/user-button/user-button.component.html index 205781407..82028be44 100644 --- a/apps/red-ui/src/app/modules/shared/components/buttons/user-button/user-button.component.html +++ b/apps/red-ui/src/app/modules/shared/components/buttons/user-button/user-button.component.html @@ -1,5 +1,5 @@
diff --git a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.html b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.html index 0db9c6c2b..b2f2ed660 100644 --- a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.html +++ b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.html @@ -1,12 +1,12 @@ -
+
- {{ initials }} + {{ _user | name: { showInitials: true, defaultValue: ('initials-avatar.unassigned' | translate) } }}
- {{ displayName || ('initials-avatar.unassigned' | translate) }} + {{ userName }}
diff --git a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts index fa46e8c97..efe4e086b 100644 --- a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts @@ -1,8 +1,9 @@ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges, OnDestroy } from '@angular/core'; import { UserService } from '@services/user.service'; -import { TranslateService } from '@ngx-translate/core'; import { AutoUnsubscribe } from '@iqser/common-ui'; import { User } from '@models/user'; +import { TranslateService } from '@ngx-translate/core'; +import { NamePipeOptions } from '@shared/pipes/name.pipe'; @Component({ selector: 'redaction-initials-avatar', @@ -11,39 +12,47 @@ import { User } from '@models/user'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChanges, OnDestroy { - @Input() userId: string; @Input() color = 'lightgray'; @Input() size: 'small' | 'large' = 'small'; @Input() withName = false; @Input() showYou = false; @Input() tooltipPosition: 'below' | 'above' = 'above'; - - displayName: string; - initials: string; colorClass: string; - user: User; - constructor( - private readonly _userService: UserService, - private readonly _translateService: TranslateService, - private readonly _changeDetectorRef: ChangeDetectorRef, - ) { + readonly namePipeOptions: NamePipeOptions = { + showYou: this.showYou, + defaultValue: this._translateService.instant('initials-avatar.unassigned'), + }; + + constructor(private readonly _userService: UserService, private readonly _translateService: TranslateService) { super(); - this.addSubscription = _userService.usersReloaded$.subscribe(() => { - this.detectChanges(); - }); + } + + _user: User; + + @Input() + set user(user: User | string) { + if (typeof user === 'string') { + this._user = this._userService.find(user); + } else { + this._user = user; + } } get hasBorder(): boolean { - return !!this.user && !this._isCurrentUser && this.user.isManager; + return !!this._user && !this.isCurrentUser && this._user.isManager; } get disabled(): boolean { - return this.user && !this.user.isActive; + return this._user && !this._user.isActive; + } + + get isCurrentUser(): boolean { + return this._userService.currentUser.id === this._user?.id; } private get _colorClass() { - if (this._isCurrentUser) { + if (this.isCurrentUser) { return 'primary-white'; } if (this.disabled) { @@ -56,44 +65,13 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange return `${this.color}-dark`; } - private get _isCurrentUser(): boolean { - return this._userService.currentUser.id === this.user?.id; - } - ngOnChanges(): void { - const isSystemUser = this.userId?.toLowerCase() === 'system'; + const isSystemUser = this._user?.id?.toLowerCase() === 'system'; if (isSystemUser) { - this.displayName = 'System'; - this.initials = 'SY'; this.colorClass = 'primary-white primary'; return; } - this.user = this._userService.getUserById(this.userId); - this.displayName = this._userService.getNameForId(this.userId); - - this.initials = this._getInitials(); this.colorClass = this._colorClass; - - if (this.showYou && this._isCurrentUser) { - this.displayName += ` (${this._translateService.instant('initials-avatar.you')})`; - } - } - - detectChanges(): void { - this.ngOnChanges(); - this._changeDetectorRef.detectChanges(); - } - - private _getInitials(): string { - if (!this.displayName) { - return '?'; - } - - return this.displayName - .split(' ') - .filter((value, idx) => idx < 2 && value !== ' ') - .map(str => str[0]) - .join(''); } } diff --git a/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html index 08e777a4a..61d9f63e8 100644 --- a/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html +++ b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html @@ -6,7 +6,7 @@ [class.large-spacing]="largeSpacing" class="member" > - +
diff --git a/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts b/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts index 9b1da8a12..13da6ecb4 100644 --- a/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts +++ b/apps/red-ui/src/app/modules/shared/pipes/name.pipe.ts @@ -3,16 +3,61 @@ import { UserService } from '@services/user.service'; import { TranslateService } from '@ngx-translate/core'; import { User } from '@models/user'; +function getInitials(name: string) { + if (name.toLowerCase() === 'system') { + return 'SY'; + } + + const splittedName = name.split(' ').filter(value => value !== ' ' && value !== ''); + return splittedName + .filter((value, index) => index < 2) + .map(str => str[0]) + .join(''); +} + +function isSystemUser(user: User | string) { + const userId = typeof user === 'string' ? user : user.id; + return userId.toLowerCase() === 'system'; +} + +export interface NamePipeOptions { + showYou?: boolean; + showInitials?: boolean; + defaultValue?: string; +} + @Pipe({ name: 'name', }) export class NamePipe implements PipeTransform { + private readonly _defaultOptions: NamePipeOptions = { defaultValue: this._translateService.instant('unknown') }; + constructor(private readonly _userService: UserService, private readonly _translateService: TranslateService) {} - transform(value: User | string): string { - if (typeof value === 'string') { - return this._userService.getNameForId(value) || this._translateService.instant('unknown'); + transform(value?: User | string, options = this._defaultOptions): string { + let name; + if (!value || !isSystemUser(value)) { + name = this._getName(value) || options?.defaultValue; + } else { + name = 'System'; } - return value.name; + + if (options?.showYou && this._isCurrentUser(value)) { + name = `${name} (${this._translateService.instant('initials-avatar.you')})`; + } + + return options?.showInitials ? getInitials(name) : name; + } + + private _isCurrentUser(user: User | string): boolean { + const userId = typeof user === 'string' ? user : user.id; + return this._userService.currentUser.id === userId; + } + + private _getName(user: User | string): string | undefined { + if (!user) { + return undefined; + } + return typeof user === 'string' ? this._userService.getNameForId(user) : user.name; } } diff --git a/apps/red-ui/src/app/services/user.service.ts b/apps/red-ui/src/app/services/user.service.ts index 608030d7f..fa84aec68 100644 --- a/apps/red-ui/src/app/services/user.service.ts +++ b/apps/red-ui/src/app/services/user.service.ts @@ -1,11 +1,13 @@ -import { Inject, Injectable } from '@angular/core'; +import { Inject, Injectable, Injector } from '@angular/core'; import { KeycloakService } from 'keycloak-angular'; import jwt_decode from 'jwt-decode'; -import { IUser, UserControllerService } from '@redaction/red-ui-http'; +import { CreateUserRequest, IUser, ResetPasswordRequest, UpdateMyProfileRequest, UpdateProfileRequest } from '@redaction/red-ui-http'; import { wipeCaches } from '@redaction/red-cache'; import { BASE_HREF } from '../tokens'; -import { Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { User } from '@models/user'; +import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; +import { tap } from 'rxjs/operators'; export interface ProfileModel { username?: string; @@ -18,16 +20,14 @@ export interface ProfileModel { @Injectable({ providedIn: 'root', }) -export class UserService { - usersReloaded$ = new Subject(); - private _allUsers: User[]; - private _allRedUsers: User[]; - +export class UserService extends EntitiesService { constructor( + protected readonly _injector: Injector, @Inject(BASE_HREF) private readonly _baseHref: string, private readonly _keycloakService: KeycloakService, - private readonly _userControllerService: UserControllerService, - ) {} + ) { + super(_injector, User, 'user'); + } private _currentUser: User; @@ -36,11 +36,11 @@ export class UserService { } get managerUsers(): User[] { - return this._allRedUsers.filter(user => user.isManager); + return this.all.filter(user => user.isManager); } get eligibleUsers(): User[] { - return this._allRedUsers.filter(user => user.isUser || user.isManager); + return this.all.filter(user => user.isUser || user.isManager); } logout() { @@ -48,23 +48,13 @@ export class UserService { this._keycloakService.logout(window.location.origin + this._baseHref).then(); } - async loadUsersIfNecessary() { - if (!this._allRedUsers) { - await this.loadAllUsers(); - } - } + loadAll() { + const all$ = this._currentUser.isUserAdmin ? this.getUsers() : this.getUsers(true); - async loadAllUsers() { - let allUsers: IUser[]; - if (this._currentUser.isUserAdmin) { - allUsers = await this._userControllerService.getAllUsers().toPromise(); - } else { - allUsers = await this._userControllerService.getUsers().toPromise(); - } - this._allUsers = allUsers.map(user => new User(user, user.roles, user.userId)); - this._allRedUsers = this._allUsers.filter(user => user.hasAnyREDRoles); - this.usersReloaded$.next(); - return this._allUsers; + return all$.pipe( + mapEach(user => new User(user, user.roles, user.userId)), + tap(users => this.setEntities(users)), + ); } async loadCurrentUser() { @@ -74,16 +64,8 @@ export class UserService { this._currentUser = new User(await this._keycloakService.loadUserProfile(true), this._keycloakService.getUserRoles(true), userId); } - getRedUserById(id: string) { - return this._allRedUsers.find(u => u.id === id); - } - - getUserById(id: string) { - return this._allUsers ? this._allUsers.find(u => u.id === id) : this.getRedUserById(id); - } - getNameForId(userId: string): string | undefined { - return this.getUserById(userId)?.name; + return this.find(userId)?.name; } hasAnyRole(requiredRoles: string[], user = this._currentUser): boolean { @@ -99,4 +81,34 @@ export class UserService { return true; } + + getUsers(onlyRed = false, refreshCache = false): Observable { + const url = onlyRed ? `${this._defaultModelPath}/red` : this._defaultModelPath; + return super.getAll(url, [{ key: 'refreshCache', value: refreshCache }]); + } + + @Validate() + updateProfile(@RequiredParam() body: UpdateProfileRequest, @RequiredParam() userId: string) { + return this._post(body, `${this._defaultModelPath}/profile/${userId}`); + } + + @Validate() + updateMyProfile(@RequiredParam() body: UpdateMyProfileRequest) { + return this._post(body, `${this._defaultModelPath}/my-profile`); + } + + @Validate() + resetPassword(@RequiredParam() body: ResetPasswordRequest, @RequiredParam() userId: string) { + return this._post(body, `${this._defaultModelPath}/${userId}/reset-password`); + } + + @Validate() + create(@RequiredParam() body: CreateUserRequest) { + return this._post(body); + } + + delete(userIds: List) { + const queryParams = userIds.map(userId => ({ key: 'userId', value: userId })); + return super.delete(userIds, this._defaultModelPath, queryParams); + } } diff --git a/apps/red-ui/src/app/state/app-state.guard.ts b/apps/red-ui/src/app/state/app-state.guard.ts index 0a302acad..f2913b3bd 100644 --- a/apps/red-ui/src/app/state/app-state.guard.ts +++ b/apps/red-ui/src/app/state/app-state.guard.ts @@ -19,11 +19,11 @@ export class AppStateGuard implements CanActivate { async canActivate(route: ActivatedRouteSnapshot): Promise { if (this._userService.currentUser.isUserAdmin) { - await this._userService.loadUsersIfNecessary(); + await this._userService.loadAllIfEmpty(); } if (this._userService.currentUser.isUser || this._userService.currentUser.isAdmin) { - await this._userService.loadUsersIfNecessary(); + await this._userService.loadAllIfEmpty(); await this._dossierTemplatesService.loadAllIfEmpty(); await this._appStateService.loadDictionaryDataIfNecessary(); } diff --git a/libs/common-ui b/libs/common-ui index 56ef15eec..eca1fd1b9 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 56ef15eecb738262b6bae51c15e0f4726d8af7e4 +Subproject commit eca1fd1b9cf14febef7583e69501b4ab85342dba diff --git a/libs/red-ui-http/src/lib/api.module.ts b/libs/red-ui-http/src/lib/api.module.ts index f117465ec..4d14cc212 100644 --- a/libs/red-ui-http/src/lib/api.module.ts +++ b/libs/red-ui-http/src/lib/api.module.ts @@ -19,7 +19,6 @@ import { ReportTemplateControllerService } from './api/reportTemplateController. import { RulesControllerService } from './api/rulesController.service'; import { SmtpConfigurationControllerService } from './api/smtpConfigurationController.service'; import { UploadControllerService } from './api/uploadController.service'; -import { UserControllerService } from './api/userController.service'; import { VersionsControllerService } from './api/versionsController.service'; import { ViewedPagesControllerService } from './api/viewedPagesController.service'; import { WatermarkControllerService } from './api/watermarkController.service'; @@ -49,7 +48,6 @@ import { StatusReportControllerService } from './api/statusReportController.serv RulesControllerService, SmtpConfigurationControllerService, UploadControllerService, - UserControllerService, VersionsControllerService, ViewedPagesControllerService, WatermarkControllerService,