From 5bf1122516a7d8ac3629984064ebe440f97cfda2 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Sun, 6 Nov 2022 09:55:46 +0200 Subject: [PATCH] RED-5482: wip permissions --- apps/red-ui/src/app/app.component.ts | 11 +-- .../base-screen/base-screen.component.html | 2 +- .../src/app/modules/admin/admin.module.ts | 2 + .../screens/audit/audit-screen.component.html | 2 +- .../screens/audit/audit-screen.component.ts | 8 ++- .../digital-signature-screen.component.html | 4 +- .../digital-signature-screen.component.ts | 44 ++++++------ ...ssier-states-listing-screen.component.html | 6 +- ...dossier-states-listing-screen.component.ts | 4 +- ...er-templates-listing-screen.component.html | 6 +- ...sier-templates-listing-screen.component.ts | 8 ++- .../dossier-templates-listing.module.ts | 10 ++- .../entities-listing-screen.component.html | 6 +- .../entities-listing-screen.component.ts | 2 + .../admin/screens/entities/entities.module.ts | 3 +- .../entity-info/entity-info.component.html | 2 +- .../entity-info/entity-info.component.ts | 2 + .../license-screen.component.html | 2 +- .../license-screen.component.ts | 8 +-- .../permissions-screen.component.html | 2 +- .../permissions-screen.component.ts | 16 +++-- .../src/app/modules/archive/archive.module.ts | 3 +- .../table-item/table-item.component.html | 11 ++- .../table-item/table-item.component.ts | 8 +-- .../dossier-details.component.html | 4 +- .../dossier-details.component.ts | 29 ++++---- ...sier-overview-screen-header.component.html | 2 +- .../dossier-overview/config.service.ts | 7 +- .../dossiers-listing-actions.component.html | 11 ++- .../dossiers-listing-actions.component.ts | 8 +-- .../dossiers-listing.module.ts | 2 + .../edit-dossier-dialog.component.ts | 9 +-- .../edit-dossier-team.component.ts | 6 +- .../team-members/team-members.component.html | 2 +- .../team-members/team-members.component.ts | 6 +- .../src/app/modules/shared/shared.module.ts | 10 ++- .../src/app/services/permissions.service.ts | 68 +++++++++++++------ apps/red-ui/src/app/users/roles.ts | 2 +- apps/red-ui/src/app/users/user.service.ts | 8 --- apps/red-ui/src/app/utils/filter-utils.ts | 2 - libs/red-domain/src/lib/users/user.model.ts | 1 - 41 files changed, 210 insertions(+), 139 deletions(-) diff --git a/apps/red-ui/src/app/app.component.ts b/apps/red-ui/src/app/app.component.ts index 76629a582..3329762aa 100644 --- a/apps/red-ui/src/app/app.component.ts +++ b/apps/red-ui/src/app/app.component.ts @@ -1,31 +1,32 @@ import { Component, Inject, Renderer2, ViewContainerRef } from '@angular/core'; import { RouterHistoryService } from '@services/router-history.service'; -import { UserService } from '@users/user.service'; import { REDDocumentViewer } from './modules/pdf-viewer/services/document-viewer.service'; import { DossiersChangesService } from '@services/dossiers/dossier-changes.service'; import { DOCUMENT } from '@angular/common'; import { UserPreferenceService } from '@users/user-preference.service'; +import { IqserPermissionsService } from '@iqser/common-ui'; +import { ROLES } from '@users/roles'; @Component({ selector: 'redaction-root', templateUrl: './app.component.html', }) export class AppComponent { - // ViewContainerRef needs to be injected for the color picker to work - // RouterHistoryService needs to be injected for last dossiers screen to be updated on first app load constructor( + /** ViewContainerRef needs to be injected for the color picker to work */ readonly viewContainerRef: ViewContainerRef, + /** RouterHistoryService needs to be injected for last dossiers screen to be updated on first app load */ private readonly _routerHistoryService: RouterHistoryService, - private readonly _userService: UserService, private readonly _userPreferenceService: UserPreferenceService, readonly documentViewer: REDDocumentViewer, private readonly _dossierChangesService: DossiersChangesService, @Inject(DOCUMENT) private readonly _document: Document, private readonly _renderer: Renderer2, + private readonly _permissionsService: IqserPermissionsService, ) { this._renderer.addClass(this._document.body, _userPreferenceService.getTheme()); // TODO: Find a better place to initialize dossiers refresh - if (_userService.currentUser?.isUser) { + if (_permissionsService.has(ROLES.dossiers.read)) { _dossierChangesService.initializeRefresh(); } } diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.html b/apps/red-ui/src/app/components/base-screen/base-screen.component.html index 1789ad6aa..2015dcee7 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.html +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.html @@ -2,7 +2,7 @@
- +
-
+
implements OnInit, OnDestroy { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; + readonly roles = ROLES; readonly tableHeaderLabel = _('dossier-states-listing.table-header.title'); readonly tableColumnConfigs: TableColumnConfig[] = [ { label: _('dossier-states-listing.table-col-names.name'), sortByKey: 'name', width: '3fr' }, @@ -39,7 +40,6 @@ export class DossierStatesListingScreenComponent extends ListingComponent { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser = inject(UserService).currentUser; + readonly roles = ROLES; readonly tableHeaderLabel = _('dossier-templates-listing.table-header.title'); readonly tableColumnConfigs: TableColumnConfig[] = [ { label: _('dossier-templates-listing.table-col-names.name'), sortByKey: 'searchKey', width: '3fr' }, @@ -45,6 +46,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent
@@ -109,7 +109,7 @@ > { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; + readonly roles = ROLES; readonly tableHeaderLabel = _('entities-listing.table-header.title'); readonly tableColumnConfigs: TableColumnConfig[] = [ { label: _('entities-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' }, diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/entities.module.ts b/apps/red-ui/src/app/modules/admin/screens/entities/entities.module.ts index 5f88a9aa8..7f874e8cc 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/entities.module.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities/entities.module.ts @@ -8,7 +8,7 @@ import { EntityInfoComponent } from './screens/entity-info/entity-info.component import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'; import { SharedAdminModule } from '../../shared/shared-admin.module'; import { TranslateModule } from '@ngx-translate/core'; -import { IqserHelpModeModule, IqserScrollbarModule } from '@iqser/common-ui'; +import { IqserHelpModeModule, IqserPermissionsModule, IqserScrollbarModule } from '@iqser/common-ui'; const routes: Routes = [ { path: '', redirectTo: 'info', pathMatch: 'full' }, @@ -45,6 +45,7 @@ const routes: Routes = [ TranslateModule, IqserScrollbarModule, IqserHelpModeModule, + IqserPermissionsModule, ], }) export class EntitiesModule {} diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.html b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.html index 652ed5e7e..ea792ffea 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.html @@ -17,7 +17,7 @@ >
-
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts index f4cc6c19d..d374e35f9 100644 --- a/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/entities/screens/entity-info/entity-info.component.ts @@ -7,6 +7,7 @@ import { PermissionsService } from '@services/permissions.service'; import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component'; import { IqserEventTarget } from '@iqser/common-ui'; import { Observable } from 'rxjs'; +import { ROLES } from '@users/roles'; @Component({ selector: 'redaction-entity-info', @@ -16,6 +17,7 @@ import { Observable } from 'rxjs'; }) export class EntityInfoComponent { readonly currentUser = getCurrentUser(); + readonly roles = ROLES; readonly entity$: Observable; readonly dossierTemplateId: string; @ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent; diff --git a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.html index e76d8daae..2df02a524 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.html @@ -4,7 +4,7 @@ (closeAction)="routerHistoryService.navigateToLastDossiersScreen()" [buttonConfigs]="buttonConfigs" [pageLabel]="'license-information' | translate" - [showCloseButton]="currentUser.isUser" + [showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" >
diff --git a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts index fd9b4fbe6..4481a06e8 100644 --- a/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/license/license-screen/license-screen.component.ts @@ -1,20 +1,20 @@ import { Component, OnInit } from '@angular/core'; import { ConfigService } from '@services/config.service'; import { TranslateService } from '@ngx-translate/core'; -import { ButtonConfig, IconButtonTypes, LoadingService } from '@iqser/common-ui'; +import { ButtonConfig, IconButtonTypes, IqserPermissionsService, LoadingService } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { UserService } from '@users/user.service'; import { RouterHistoryService } from '@services/router-history.service'; import { LicenseService } from '@services/license.service'; import { map } from 'rxjs/operators'; +import { ROLES } from '@users/roles'; @Component({ templateUrl: './license-screen.component.html', styleUrls: ['./license-screen.component.scss'], }) export class LicenseScreenComponent implements OnInit { + readonly roles = ROLES; readonly currentYear = new Date().getFullYear(); - readonly currentUser = this._userService.currentUser; readonly buttonConfigs: readonly ButtonConfig[] = [ { label: _('license-info-screen.email-report'), @@ -29,7 +29,7 @@ export class LicenseScreenComponent implements OnInit { constructor( readonly configService: ConfigService, readonly licenseService: LicenseService, - private readonly _userService: UserService, + readonly permissionsService: IqserPermissionsService, private readonly _loadingService: LoadingService, readonly routerHistoryService: RouterHistoryService, private readonly _translateService: TranslateService, diff --git a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.html index ec2828bec..6de22c773 100644 --- a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.html @@ -1,7 +1,7 @@ diff --git a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts index 823f78581..4c291f5cb 100644 --- a/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/permissions/permissions-screen/permissions-screen.component.ts @@ -1,5 +1,12 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { ListingComponent, listingProvidersFactory, LoadingService, SortingOrders, TableColumnConfig } from '@iqser/common-ui'; +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { + IqserPermissionsService, + ListingComponent, + listingProvidersFactory, + LoadingService, + SortingOrders, + TableColumnConfig, +} from '@iqser/common-ui'; import { PermissionsMapping } from '@red/domain'; import { ConfigService } from '../config.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -11,8 +18,8 @@ import { firstValueFrom } from 'rxjs'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { tap } from 'rxjs/operators'; import { permissionsTranslations } from '@translations/permissions-translations'; -import { UserService } from '@users/user.service'; import { RouterHistoryService } from '@services/router-history.service'; +import { ROLES } from '@users/roles'; @UntilDestroy() @Component({ @@ -22,7 +29,7 @@ import { RouterHistoryService } from '@services/router-history.service'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class PermissionsScreenComponent extends ListingComponent { - readonly currentUser = inject(UserService).currentUser; + readonly roles = ROLES; readonly translations = permissionsTranslations; readonly tableColumnConfigs: TableColumnConfig[]; readonly tableHeaderLabel = _('permissions-screen.table-header.title'); @@ -34,6 +41,7 @@ export class PermissionsScreenComponent extends ListingComponent
diff --git a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts index dc2b545ca..e819fb64e 100644 --- a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts +++ b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts @@ -3,9 +3,9 @@ import { Dossier, DossierStats } from '@red/domain'; import { BehaviorSubject, Observable } from 'rxjs'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { switchMap } from 'rxjs/operators'; -import { CircleButtonTypes, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; -import { UserService } from '@users/user.service'; +import { CircleButtonTypes, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; +import { ROLES } from '@users/roles'; @Component({ selector: 'redaction-table-item [dossier]', @@ -14,7 +14,7 @@ import { DossiersDialogService } from '../../../shared-dossiers/services/dossier }) export class TableItemComponent implements OnChanges { readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser = this._userService.currentUser; + readonly roles = ROLES; @Input() dossier!: Dossier; readonly stats$: Observable; @@ -22,8 +22,8 @@ export class TableItemComponent implements OnChanges { constructor( readonly dossierStatsService: DossierStatsService, + readonly permissionsService: IqserPermissionsService, private readonly _dialogService: DossiersDialogService, - private readonly _userService: UserService, ) { this.stats$ = this.#ngOnChanges$.pipe(switchMap(dossierId => this.dossierStatsService.watch$(dossierId))); } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.html index aa71f3d50..11611d062 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.html @@ -19,7 +19,7 @@
diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts index aa0eb4954..3a2292ba4 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts @@ -18,9 +18,10 @@ import { workflowFileStatusTranslations } from '@translations/file-status-transl import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { combineLatestWith, firstValueFrom, Observable } from 'rxjs'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; -import { map, tap } from 'rxjs/operators'; +import { map } from 'rxjs/operators'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { FilesMapService } from '@services/files/files-map.service'; +import { ROLES } from '@users/roles'; interface DossierDetailsContext { needsWorkFilters: INestedFilter[] | undefined; @@ -42,20 +43,18 @@ export class DossierDetailsComponent extends ContextComponent; readonly dossierStats$: Observable; readonly filesChanged$: Observable; readonly chartConfig$: Observable; readonly statusConfig$: Observable; - chartConfig: DonutChartConfig[] = []; + #currentChartSubtitleIndex = 0; + readonly #dossierId: string; constructor( private readonly _toaster: Toaster, @@ -78,6 +77,10 @@ export class DossierDetailsComponent extends ContextComponent this.#calculateStatusConfig(stats))); } + get managers() { + return this._userService.all.filter(u => u.has(ROLES.dossiers.write) || u.isManager).map(u => u.id); + } + ngOnInit() { super._initContext({ needsWorkFilters: this.needsWorkFilters$, @@ -89,10 +92,6 @@ export class DossierDetailsComponent extends ContextComponent manager.id); - } - async assignOwner(user: User | string, dossier: Dossier) { const owner = typeof user === 'string' ? this._userService.find(user) : user; const dossierRequest: IDossierRequest = { ...dossier, ownerId: owner.id }; @@ -103,6 +102,11 @@ export class DossierDetailsComponent extends ContextComponent ({ value: !this.#currentChartSubtitleIndex @@ -155,9 +159,4 @@ export class DossierDetailsComponent extends ContextComponent config.count > 0); } - - onSubtitleChanged(subtitleIndex: number) { - this.#currentChartSubtitleIndex = subtitleIndex; - this.#calculateChartConfig(this.dossierStatsService.get(this.#dossierId)); - } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html index 9713de260..3aeac614a 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html @@ -37,7 +37,7 @@ this._openEditDossierDialog($event, dossierId), icon: 'iqser:edit', - hide: !this._userService.currentUser.isManager, + hide: !this._iqserPermissionsService.has(ROLES.dossiers.edit), helpModeKey: 'edit_dossier_in_dossier', disabled$, }, diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html index 8b8d80850..9c064c31a 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html @@ -1,11 +1,16 @@
diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts index 9a3d4ef08..c4528f64d 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts @@ -1,7 +1,6 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; -import { CircleButtonTypes, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; -import { UserService } from '@users/user.service'; +import { CircleButtonTypes, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; import { Dossier, DossierStats, File } from '@red/domain'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; import { LongPressEvent } from '@shared/directives/long-press.directive'; @@ -9,6 +8,7 @@ import { UserPreferenceService } from '@users/user-preference.service'; import { FilesMapService } from '@services/files/files-map.service'; import { ReanalysisService } from '@services/reanalysis.service'; import { firstValueFrom } from 'rxjs'; +import { ROLES } from '@users/roles'; @Component({ selector: 'redaction-dossiers-listing-actions', @@ -17,7 +17,7 @@ import { firstValueFrom } from 'rxjs'; }) export class DossiersListingActionsComponent implements OnChanges { readonly circleButtonTypes = CircleButtonTypes; - readonly currentUser = this._userService.currentUser; + readonly roles = ROLES; analysisForced: boolean; files: File[]; @@ -28,8 +28,8 @@ export class DossiersListingActionsComponent implements OnChanges { constructor( private readonly _reanalysisService: ReanalysisService, - private readonly _userService: UserService, readonly permissionsService: PermissionsService, + readonly iqserPermissionsService: IqserPermissionsService, readonly filesMapService: FilesMapService, private readonly _dialogService: DossiersDialogService, private readonly _userPreferenceService: UserPreferenceService, diff --git a/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts b/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts index 40798365f..087ea8f0c 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/dossiers-listing.module.ts @@ -5,6 +5,7 @@ import { IqserHelpModeModule, IqserIconsModule, IqserListingModule, + IqserPermissionsModule, IqserScrollbarModule, IqserSharedModule, IqserUsersModule, @@ -56,6 +57,7 @@ const routes: Routes = [ IqserListingModule, IqserScrollbarModule, IqserSharedModule, + IqserPermissionsModule, ], }) export class DossiersListingModule {} diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts index 4e514741b..fc11418ed 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts @@ -4,7 +4,7 @@ import { Dossier } from '@red/domain'; import { EditDossierGeneralInfoComponent } from './general-info/edit-dossier-general-info.component'; import { EditDossierDownloadPackageComponent } from './download-package/edit-dossier-download-package.component'; import { EditDossierSectionInterface } from './edit-dossier-section.interface'; -import { BaseDialogComponent, ConfirmOptions, IconButtonTypes, SaveOptions } from '@iqser/common-ui'; +import { BaseDialogComponent, ConfirmOptions, IconButtonTypes, IqserPermissionsService, SaveOptions } from '@iqser/common-ui'; import { EditDossierDictionaryComponent } from './dictionary/edit-dossier-dictionary.component'; import { EditDossierAttributesComponent } from './attributes/edit-dossier-attributes.component'; @@ -13,9 +13,9 @@ import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { EditDossierTeamComponent } from './edit-dossier-team/edit-dossier-team.component'; import { PermissionsService } from '@services/permissions.service'; -import { getCurrentUser } from '@users/user.service'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider'; +import { ROLES } from '@users/roles'; type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes'; @@ -42,12 +42,12 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A @ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent; @ViewChild(EditDossierTeamComponent) membersComponent: EditDossierTeamComponent; @ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent; - readonly #currentUser = getCurrentUser(); private _dossier: Dossier; constructor( private readonly _dossiersService: DossiersService, private readonly _permissionsService: PermissionsService, + private readonly _iqserPermissionsService: IqserPermissionsService, protected readonly _dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) private readonly _data: { @@ -89,7 +89,8 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A get showActionButtons(): boolean { return ( - (['members'].includes(this.activeNav) && this.#currentUser.isManager) || this._permissionsService.canEditDossier(this._dossier) + (['members'].includes(this.activeNav) && this._iqserPermissionsService.has(ROLES.dossiers.edit)) || + this._permissionsService.canEditDossier(this._dossier) ); } diff --git a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.ts b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.ts index 2ebec35ef..813cbb526 100644 --- a/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.ts +++ b/apps/red-ui/src/app/modules/shared-dossiers/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.ts @@ -8,6 +8,7 @@ import { PermissionsService } from '@services/permissions.service'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { compareLists } from '@utils/functions'; import { FilesService } from '@services/files/files.service'; +import { ROLES } from '@users/roles'; @Component({ selector: 'redaction-edit-dossier-team', @@ -23,7 +24,7 @@ export class EditDossierTeamComponent implements EditDossierSectionInterface, On membersSelectOptions: string[] = []; - readonly ownersSelectOptions = this.userService.managerUsers.map(m => m.id); + readonly ownersSelectOptions = this.userService.all.filter(u => u.has(ROLES.dossiers.write) || u.isManager).map(m => m.id); readonly selectedReviewers$ = new BehaviorSubject([]); constructor( @@ -137,7 +138,8 @@ export class EditDossierTeamComponent implements EditDossierSectionInterface, On } setMembersSelectOptions(value = this.searchQuery): void { - this.membersSelectOptions = this.userService.eligibleUsers + const possibleMembers = this.userService.all.filter(user => user.has(ROLES.dossiers.read) || user.isUser || user.isManager); + this.membersSelectOptions = possibleMembers .filter(user => this.userService.getName(user.id).toLowerCase().includes(value.toLowerCase())) .filter(user => this.selectedOwnerId !== user.id) .map(user => user.id); 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 3dc59dd4f..f70356724 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 @@ -19,7 +19,7 @@ this._canDeleteEntity(_entity) && acc, true); - } - - canPerformDossierStatesActions(): boolean { - return this.isAdmin(); + return ( + entities.length && + this._iqserPermissionsService.has(ROLES.dictionaryTypes.delete) && + entities.reduce((acc, _entity) => this._canDeleteEntity(_entity) && acc, true) + ); } isAssigneeOrApprover(file: File, dossier: Dossier): boolean { @@ -38,11 +41,15 @@ export class PermissionsService { } displayReanalyseBtn(dossier: Dossier): boolean { - return this.isApprover(dossier) && !!this._filesMapService.get(dossier.id).find(f => f.analysisRequired); + return ( + this._iqserPermissionsService.has(ROLES.files.reanalyze) && + this.isApprover(dossier) && + !!this._filesMapService.get(dossier.id).find(f => f.analysisRequired) + ); } canUploadFiles(dossier: Dossier): boolean { - return dossier.isActive; + return this._iqserPermissionsService.has(ROLES.files.upload) && dossier.isActive; } canDownloadCsvReport(dossier: Dossier): boolean { @@ -68,7 +75,10 @@ export class PermissionsService { canReanalyseFile(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canReanalyseFile(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.files.reanalyze) && + files.reduce((acc, _file) => this._canReanalyseFile(_file, dossier) && acc, true) + ); } canEnableAutoAnalysis(files: File[], dossier: Dossier): boolean { @@ -85,7 +95,10 @@ export class PermissionsService { canSoftDeleteFile(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canSoftDeleteFile(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.files.delete) && + files.reduce((acc, _file) => this._canSoftDeleteFile(_file, dossier) && acc, true) + ); } canRestoreFile(file: File | File[], dossier: Dossier): boolean { @@ -95,27 +108,42 @@ export class PermissionsService { canHardDeleteFile(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canHardDeleteFile(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.files.delete) && + files.reduce((acc, _file) => this._canHardDeleteFile(_file, dossier) && acc, true) + ); } canOcrFile(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canOcrFile(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.files.reanalyze) && + files.reduce((acc, _file) => this._canOcrFile(_file, dossier) && acc, true) + ); } canAssignToSelf(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canAssignToSelf(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.setReviewer) && + files.reduce((acc, _file) => this._canAssignToSelf(_file, dossier) && acc, true) + ); } canAssignUser(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canAssignUser(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.setReviewer) && + files.reduce((acc, _file) => this._canAssignUser(_file, dossier) && acc, true) + ); } canUnassignUser(file: File | File[], dossier: Dossier): boolean { const files = file instanceof File ? [file] : file; - return files.reduce((acc, _file) => this._canUnassignUser(_file, dossier) && acc, true); + return ( + this._iqserPermissionsService.has(ROLES.setReviewer) && + files.reduce((acc, _file) => this._canUnassignUser(_file, dossier) && acc, true) + ); } canSetToNew(file: File | File[], dossier: Dossier): boolean { @@ -185,11 +213,11 @@ export class PermissionsService { } canSoftDeleteDossier(dossier: IDossier): boolean { - return this.isOwner(dossier) || (this.isManager() && this.isDossierMember(dossier)); + return this._iqserPermissionsService.has(ROLES.dossiers.delete) && (this.isOwner(dossier) || this.isDossierMember(dossier)); } canHardDeleteDossier(dossier: IDossier): boolean { - return this.isOwner(dossier); + return this.isOwner(dossier) && this._iqserPermissionsService.has(ROLES.dossiers.delete); } canRestoreDossier(dossier: IDossier): boolean { @@ -197,7 +225,7 @@ export class PermissionsService { } canCreateDossier(dossierTemplate: DossierTemplate | DashboardStats): boolean { - return dossierTemplate.isActive && this.isManager(); + return dossierTemplate.isActive && this._iqserPermissionsService.has(ROLES.dossiers.write); } canArchiveDossier(dossier: Dossier): boolean { @@ -205,7 +233,7 @@ export class PermissionsService { } canEditDossier(dossier: Dossier): boolean { - return this.isManager() && !!dossier?.ownerId; + return this._iqserPermissionsService.has(ROLES.dossiers.edit) && !!dossier?.ownerId; } canEditDossierDictionary(dossier: Dossier): boolean { @@ -217,7 +245,7 @@ export class PermissionsService { } canEditTeamMembers(): boolean { - return this.isManager(); + return this._iqserPermissionsService.has(ROLES.dossiers.edit); } isAdmin(): boolean { diff --git a/apps/red-ui/src/app/users/roles.ts b/apps/red-ui/src/app/users/roles.ts index b34e25361..5be57bcad 100644 --- a/apps/red-ui/src/app/users/roles.ts +++ b/apps/red-ui/src/app/users/roles.ts @@ -20,11 +20,11 @@ export const ROLES = { RED_REINDEX: 'red-reindex', RED_REQUEST_REDACTION: 'red-request-redaction', RED_ROTATE_PAGE: 'red-rotate-page', - RED_SET_REVIEWER: 'red-set-reviewer', RED_SET_STATUS_APPROVED: 'red-set-status-approved', RED_SET_STATUS_UNDER_APPROVAL: 'red-set-status-under-approval', RED_UPDATE_MY_PROFILE: 'red-update-my-profile', RED_WRITE_RULES: 'red-write-rules', + setReviewer: 'red-set-reviewer', readDownloadStatus: 'red-read-download-status', readRedactionLog: 'red-read-redaction-log', search: 'red-search', diff --git a/apps/red-ui/src/app/users/user.service.ts b/apps/red-ui/src/app/users/user.service.ts index e89bc91a0..1970b7f49 100644 --- a/apps/red-ui/src/app/users/user.service.ts +++ b/apps/red-ui/src/app/users/user.service.ts @@ -11,14 +11,6 @@ export class UserService extends IqserUserService { protected readonly _defaultModelPath = 'user'; protected readonly _entityClass = User; - get managerUsers(): User[] { - return this.all.filter(user => user.isManager); - } - - get eligibleUsers(): User[] { - return this.all.filter(user => user.isUser || user.isManager); - } - async loadCurrentUser(): Promise { const currentUser = await super.loadCurrentUser(); diff --git a/apps/red-ui/src/app/utils/filter-utils.ts b/apps/red-ui/src/app/utils/filter-utils.ts index a3dc0b848..c680682cf 100644 --- a/apps/red-ui/src/app/utils/filter-utils.ts +++ b/apps/red-ui/src/app/utils/filter-utils.ts @@ -87,8 +87,6 @@ export const dossierTemplateChecker = (dw: Dossier, filter: INestedFilter) => dw export const dossierStateChecker = (dw: Dossier, filter: INestedFilter) => dw.dossierStatusId === (filter.id === 'undefined' ? null : filter.id); -export const dossierApproverChecker = (dw: Dossier, filter: INestedFilter) => dw.approverIds.includes(filter.id); - export const userTypeFilters: { [key in UserType]: (user: User) => boolean } = { INACTIVE: (user: User) => !user.hasAnyRole, REGULAR: (user: User) => user.roles.length === 1 && user.roles[0] === 'RED_USER', diff --git a/libs/red-domain/src/lib/users/user.model.ts b/libs/red-domain/src/lib/users/user.model.ts index 5f70e50ea..e11761922 100644 --- a/libs/red-domain/src/lib/users/user.model.ts +++ b/libs/red-domain/src/lib/users/user.model.ts @@ -6,7 +6,6 @@ export class User extends IqserUser { readonly isUserAdmin = this.has('RED_USER_ADMIN'); readonly isUser = this.has('RED_USER'); readonly isAdmin = this.has('RED_ADMIN'); - readonly hasAnyREDRoles = this.isUser || this.isManager || this.isAdmin || this.isUserAdmin; constructor(user: KeycloakProfile | IIqserUser, readonly roles: List, readonly userId: string) { super(user, roles, userId);