RED-5482: wip permissions

This commit is contained in:
Dan Percic 2022-11-13 00:30:14 +02:00
parent 0d2b816263
commit 0b4de15f07
53 changed files with 227 additions and 121 deletions

View File

@ -27,6 +27,15 @@ import { ROLES } from '@users/roles';
const dossierTemplateIdRoutes: IqserRoutes = [ const dossierTemplateIdRoutes: IqserRoutes = [
{ {
path: `${DOSSIERS_ROUTE}`, path: `${DOSSIERS_ROUTE}`,
canActivate: [CompositeRouteGuard, IqserPermissionsGuard],
data: {
routeGuards: [DossiersGuard],
dossiersService: ACTIVE_DOSSIERS_SERVICE,
permissions: {
allow: [ROLES.files.readStatus],
redirectTo: '/auth-error',
},
},
children: [ children: [
{ {
path: `:${DOSSIER_ID}`, path: `:${DOSSIER_ID}`,
@ -65,15 +74,6 @@ const dossierTemplateIdRoutes: IqserRoutes = [
}, },
}, },
], ],
canActivate: [CompositeRouteGuard, IqserPermissionsGuard],
data: {
routeGuards: [DossiersGuard],
dossiersService: ACTIVE_DOSSIERS_SERVICE,
permissions: {
allow: [ROLES.files.readStatus],
redirectTo: '/auth-error',
},
},
}, },
{ {
path: `${ARCHIVE_ROUTE}`, path: `${ARCHIVE_ROUTE}`,

View File

@ -112,14 +112,14 @@ export const appModuleFactory = (config: AppConfig) => {
features: { features: {
ANNOTATIONS: { ANNOTATIONS: {
color: 'aqua', color: 'aqua',
enabled: true, enabled: false,
level: NgxLoggerLevel.DEBUG, level: NgxLoggerLevel.DEBUG,
}, },
FILTERS: { FILTERS: {
enabled: false, enabled: false,
}, },
PDF: { PDF: {
enabled: true, enabled: false,
}, },
FILE: { FILE: {
enabled: false, enabled: false,

View File

@ -5,7 +5,7 @@
<div class="menu-placeholder"></div> <div class="menu-placeholder"></div>
</ng-template> </ng-template>
<div *allow="roles.templates.read; else menuPlaceholder" class="flex-2 visible-lg breadcrumbs-container"> <div *allow="roles.templates.read; if: currentUser.isUser; else: menuPlaceholder" class="flex-2 visible-lg breadcrumbs-container">
<redaction-breadcrumbs></redaction-breadcrumbs> <redaction-breadcrumbs></redaction-breadcrumbs>
</div> </div>
@ -21,7 +21,7 @@
<div class="actions flex-2"> <div class="actions flex-2">
<div class="buttons"> <div class="buttons">
<redaction-spotlight-search <redaction-spotlight-search
*allow="roles.search; if: (isSearchScreen$ | async) === false" *allow="roles.search; if: (isSearchScreen$ | async) === false && (currentUser.isUser || currentUser.isManager)"
[actions]="searchActions" [actions]="searchActions"
[iqserHelpMode]="'search_in_entire_application'" [iqserHelpMode]="'search_in_entire_application'"
[placeholder]="'search.placeholder' | translate" [placeholder]="'search.placeholder' | translate"

View File

@ -43,19 +43,19 @@ export class BaseScreenComponent {
id: 'admin', id: 'admin',
name: _('top-bar.navigation-items.my-account.children.admin'), name: _('top-bar.navigation-items.my-account.children.admin'),
routerLink: '/main/admin', routerLink: '/main/admin',
show: this._permissionsService.has([ROLES.templates.read]), show: (this.currentUser.isManager || this.currentUser.isUserAdmin) && this._permissionsService.has([ROLES.templates.read]),
}, },
{ {
id: 'downloads', id: 'downloads',
name: _('top-bar.navigation-items.my-account.children.downloads'), name: _('top-bar.navigation-items.my-account.children.downloads'),
routerLink: '/main/downloads', routerLink: '/main/downloads',
show: this._permissionsService.has(ROLES.readDownloadStatus), show: this.currentUser.isUser && this._permissionsService.has(ROLES.readDownloadStatus),
}, },
{ {
id: 'trash', id: 'trash',
name: _('top-bar.navigation-items.my-account.children.trash'), name: _('top-bar.navigation-items.my-account.children.trash'),
routerLink: '/main/trash', routerLink: '/main/trash',
show: this._permissionsService.has([ROLES.dossiers.read, ROLES.files.readStatus]), show: this.currentUser.isUser && this._permissionsService.has([ROLES.dossiers.read, ROLES.files.readStatus]),
}, },
]; ];
readonly searchActions: readonly SpotlightSearchAction[] = [ readonly searchActions: readonly SpotlightSearchAction[] = [

View File

@ -54,7 +54,7 @@ export class AnnotationWrapper implements IListable, Record<string, unknown> {
imported?: boolean; imported?: boolean;
image?: boolean; image?: boolean;
manual?: boolean; manual?: boolean;
pending?: boolean; pending = false;
hintDictionary?: boolean; hintDictionary?: boolean;
textAfter?: string; textAfter?: string;
textBefore?: string; textBefore?: string;

View File

@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { UserPreferenceService } from '@users/user-preference.service'; import { UserPreferenceService } from '@users/user-preference.service';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { BaseFormComponent } from '@iqser/common-ui'; import { BaseFormComponent, IqserPermissionsService } from '@iqser/common-ui';
import { ROLES } from '@users/roles';
interface PreferencesForm { interface PreferencesForm {
autoExpandFiltersOnActions: boolean; autoExpandFiltersOnActions: boolean;
@ -22,12 +23,21 @@ export class PreferencesComponent extends BaseFormComponent {
readonly form: FormGroup<AsControl<PreferencesForm>>; readonly form: FormGroup<AsControl<PreferencesForm>>;
initialFormValue: PreferencesForm; initialFormValue: PreferencesForm;
constructor(readonly userPreferenceService: UserPreferenceService, private readonly _formBuilder: FormBuilder) { constructor(
readonly userPreferenceService: UserPreferenceService,
private readonly _formBuilder: FormBuilder,
private readonly _permissionsService: IqserPermissionsService,
) {
super(); super();
this.form = this._formBuilder.group({ this.form = this._formBuilder.group({
autoExpandFiltersOnActions: [this.userPreferenceService.getAutoExpandFiltersOnActions()], autoExpandFiltersOnActions: [this.userPreferenceService.getAutoExpandFiltersOnActions()],
showSuggestionsInPreview: [this.userPreferenceService.getShowSuggestionsInPreview()], showSuggestionsInPreview: [this.userPreferenceService.getShowSuggestionsInPreview()],
}); });
if (!this._permissionsService.has(ROLES.managePreferences)) {
this.form.disable();
}
this.initialFormValue = this.form.getRawValue(); this.initialFormValue = this.form.getRawValue();
} }

View File

@ -2,14 +2,14 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { BaseFormComponent, LanguageService, LoadingService } from '@iqser/common-ui'; import { BaseFormComponent, IqserPermissionsService, LanguageService, LoadingService } from '@iqser/common-ui';
import { IProfile } from '@red/domain'; import { IProfile } from '@red/domain';
import { languagesTranslations } from '@translations/languages-translations'; import { languagesTranslations } from '@translations/languages-translations';
import { PermissionsService } from '@services/permissions.service';
import { UserService } from '@users/user.service'; import { UserService } from '@users/user.service';
import { ConfigService } from '@services/config.service'; import { ConfigService } from '@services/config.service';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { UserPreferenceService } from '@users/user-preference.service'; import { UserPreferenceService } from '@users/user-preference.service';
import { ROLES } from '@users/roles';
@Component({ @Component({
selector: 'redaction-user-profile-screen', selector: 'redaction-user-profile-screen',
@ -28,12 +28,12 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
domSanitizer: DomSanitizer, domSanitizer: DomSanitizer,
configService: ConfigService, configService: ConfigService,
private readonly _userService: UserService, private readonly _userService: UserService,
readonly permissionsService: PermissionsService,
readonly userPreferences: UserPreferenceService, readonly userPreferences: UserPreferenceService,
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
private readonly _formBuilder: UntypedFormBuilder, private readonly _formBuilder: UntypedFormBuilder,
private readonly _languageService: LanguageService, private readonly _languageService: LanguageService,
protected readonly _translateService: TranslateService, protected readonly _translateService: TranslateService,
private readonly _permissionsService: IqserPermissionsService,
protected readonly _userPreferenceService: UserPreferenceService, protected readonly _userPreferenceService: UserPreferenceService,
) { ) {
super(); super();
@ -112,6 +112,9 @@ export class UserProfileScreenComponent extends BaseFormComponent implements OnI
private _initializeForm(): void { private _initializeForm(): void {
try { try {
this.form = this._getForm(); this.form = this._getForm();
if (!this._permissionsService.has(ROLES.updateMyProfile)) {
this.form.disable();
}
this.#profileModel = { this.#profileModel = {
email: this._userService.currentUser.email ?? '', email: this._userService.currentUser.email ?? '',
firstName: this._userService.currentUser.firstName ?? '', firstName: this._userService.currentUser.firstName ?? '',

View File

@ -162,10 +162,13 @@ const routes: IqserRoutes = [
component: UserListingScreenComponent, component: UserListingScreenComponent,
}, },
], ],
canActivate: [CompositeRouteGuard], canActivate: [CompositeRouteGuard, IqserPermissionsGuard],
data: { data: {
routeGuards: [IqserAuthGuard, RedRoleGuard], routeGuards: [IqserAuthGuard, RedRoleGuard],
requiredRoles: ['RED_USER_ADMIN'], permissions: {
allow: [ROLES.users.read],
redirectTo: '/',
},
}, },
}, },
{ {

View File

@ -4,9 +4,9 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { adminSideNavTranslations } from '@translations/admin-side-nav-translations'; import { adminSideNavTranslations } from '@translations/admin-side-nav-translations';
import { UserService } from '@users/user.service'; import { UserService } from '@users/user.service';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { AdminSideNavType, AdminSideNavTypes, ENTITY_TYPE } from '@red/domain'; import { AdminSideNavType, AdminSideNavTypes, ENTITY_TYPE, User } from '@red/domain';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
import { IqserPermissionsService } from '@iqser/common-ui'; import { getCurrentUser, IqserPermissionsService } from '@iqser/common-ui';
interface NavItem { interface NavItem {
readonly label: string; readonly label: string;
@ -24,6 +24,7 @@ export class AdminSideNavComponent implements OnInit {
@Input() type: AdminSideNavType; @Input() type: AdminSideNavType;
@Input() disabledItems: string[] = []; @Input() disabledItems: string[] = [];
readonly translations = adminSideNavTranslations; readonly translations = adminSideNavTranslations;
readonly currentUser = getCurrentUser<User>();
readonly roles = ROLES; readonly roles = ROLES;
prefix: string; prefix: string;
@ -32,7 +33,7 @@ export class AdminSideNavComponent implements OnInit {
{ {
screen: 'dossier-templates', screen: 'dossier-templates',
label: _('admin-side-nav.dossier-templates'), label: _('admin-side-nav.dossier-templates'),
hideIf: !this._permissionsService.has(ROLES.templates.read), hideIf: !this.currentUser.isManager && !this.currentUser.isAdmin && !this._permissionsService.has(ROLES.templates.read),
helpModeKey: 'dossier_templates', helpModeKey: 'dossier_templates',
}, },
{ {
@ -56,7 +57,7 @@ export class AdminSideNavComponent implements OnInit {
{ {
screen: 'users', screen: 'users',
label: _('admin-side-nav.user-management'), label: _('admin-side-nav.user-management'),
hideIf: !this._userService.currentUser.isUserAdmin, hideIf: !this._permissionsService.has(ROLES.users.read) && !this._userService.currentUser.isUserAdmin,
helpModeKey: 'user_management', helpModeKey: 'user_management',
}, },
{ {

View File

@ -1,7 +1,7 @@
<iqser-page-header <iqser-page-header
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
[pageLabel]="'audit' | translate" [pageLabel]="'audit' | translate"
[showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" [showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
></iqser-page-header> ></iqser-page-header>
<iqser-table <iqser-table

View File

@ -1,10 +1,17 @@
import { Component, inject, OnDestroy, OnInit } from '@angular/core'; import { Component, inject, OnDestroy, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { applyIntervalConstraints } from '@utils/date-inputs-utils'; import { applyIntervalConstraints } from '@utils/date-inputs-utils';
import { IqserPermissionsService, ListingComponent, listingProvidersFactory, LoadingService, TableColumnConfig } from '@iqser/common-ui'; import {
getCurrentUser,
IqserPermissionsService,
ListingComponent,
listingProvidersFactory,
LoadingService,
TableColumnConfig,
} from '@iqser/common-ui';
import { auditCategoriesTranslations } from '@translations/audit-categories-translations'; import { auditCategoriesTranslations } from '@translations/audit-categories-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { Audit, IAudit, IAuditResponse, IAuditSearchRequest } from '@red/domain'; import { Audit, IAudit, IAuditResponse, IAuditSearchRequest, User } from '@red/domain';
import { AuditService } from '../../services/audit.service'; import { AuditService } from '../../services/audit.service';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { Dayjs } from 'dayjs'; import { Dayjs } from 'dayjs';
@ -26,6 +33,7 @@ export class AuditScreenComponent extends ListingComponent<Audit> implements OnI
readonly routerHistoryService = inject(RouterHistoryService); readonly routerHistoryService = inject(RouterHistoryService);
readonly permissionsService = inject(IqserPermissionsService); readonly permissionsService = inject(IqserPermissionsService);
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
categories: string[] = []; categories: string[] = [];
userIds: Set<string>; userIds: Set<string>;

View File

@ -1,7 +1,7 @@
<iqser-page-header <iqser-page-header
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
[pageLabel]="'digital-signature' | translate" [pageLabel]="'digital-signature' | translate"
[showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" [showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
></iqser-page-header> ></iqser-page-header>
<div class="content-container"> <div class="content-container">

View File

@ -1,5 +1,5 @@
import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core'; import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui'; import { getCurrentUser, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { RouterHistoryService } from '@services/router-history.service'; import { RouterHistoryService } from '@services/router-history.service';
import { DigitalSignatureService } from '../../services/digital-signature.service'; import { DigitalSignatureService } from '../../services/digital-signature.service';
@ -7,7 +7,7 @@ import { firstValueFrom } from 'rxjs';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { PkcsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/pkcs-signature-configuration/pkcs-signature-configuration.component'; import { PkcsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/pkcs-signature-configuration/pkcs-signature-configuration.component';
import { KmsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component'; import { KmsSignatureConfigurationComponent } from '../../dialogs/configure-digital-signature-dialog/form/kms-signature-configuration/kms-signature-configuration.component';
import { DigitalSignatureOptions, IKmsDigitalSignatureRequest, IPkcsDigitalSignatureRequest } from '@red/domain'; import { DigitalSignatureOptions, IKmsDigitalSignatureRequest, IPkcsDigitalSignatureRequest, User } from '@red/domain';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
@Component({ @Component({
@ -22,6 +22,7 @@ export class DigitalSignatureScreenComponent implements OnInit {
readonly certificateType = DigitalSignatureOptions; readonly certificateType = DigitalSignatureOptions;
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
digitalSignature: IPkcsDigitalSignatureRequest | IKmsDigitalSignatureRequest; digitalSignature: IPkcsDigitalSignatureRequest | IKmsDigitalSignatureRequest;

View File

@ -53,7 +53,7 @@
<iqser-icon-button <iqser-icon-button
(action)="openAddEditStateDialog($event)" (action)="openAddEditStateDialog($event)"
*allow="roles.states.write" *ngIf="permissionsService.canPerformDossierStatesActions()"
[iqserHelpMode]="'create_new_dossier_state'" [iqserHelpMode]="'create_new_dossier_state'"
[label]="'dossier-states-listing.add-new' | translate" [label]="'dossier-states-listing.add-new' | translate"
[type]="iconButtonTypes.primary" [type]="iconButtonTypes.primary"
@ -80,7 +80,7 @@
</div> </div>
<div class="cell"> <div class="cell">
<div *allow="roles.states.write" class="action-buttons"> <div *ngIf="permissionsService.canPerformDossierStatesActions()" class="action-buttons">
<div [iqserHelpMode]="'edit_delete_dossier_state'"> <div [iqserHelpMode]="'edit_delete_dossier_state'">
<iqser-circle-button <iqser-circle-button
(action)="openAddEditStateDialog($event, state)" (action)="openAddEditStateDialog($event, state)"

View File

@ -15,7 +15,7 @@ import { AdminDialogService } from '../../services/admin-dialog.service';
import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service';
import { map, tap } from 'rxjs/operators'; import { map, tap } from 'rxjs/operators';
import { DossierStatesService } from '@services/entity-services/dossier-states.service'; import { DossierStatesService } from '@services/entity-services/dossier-states.service';
import { ROLES } from '@users/roles'; import { PermissionsService } from '@services/permissions.service';
@Component({ @Component({
templateUrl: './dossier-states-listing-screen.component.html', templateUrl: './dossier-states-listing-screen.component.html',
@ -26,7 +26,6 @@ import { ROLES } from '@users/roles';
export class DossierStatesListingScreenComponent extends ListingComponent<DossierState> implements OnInit, OnDestroy { export class DossierStatesListingScreenComponent extends ListingComponent<DossierState> implements OnInit, OnDestroy {
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES;
readonly tableHeaderLabel = _('dossier-states-listing.table-header.title'); readonly tableHeaderLabel = _('dossier-states-listing.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<DossierState>[] = [ readonly tableColumnConfigs: TableColumnConfig<DossierState>[] = [
{ label: _('dossier-states-listing.table-col-names.name'), sortByKey: 'name', width: '3fr' }, { label: _('dossier-states-listing.table-col-names.name'), sortByKey: 'name', width: '3fr' },
@ -40,6 +39,7 @@ export class DossierStatesListingScreenComponent extends ListingComponent<Dossie
private readonly _dialogService: AdminDialogService, private readonly _dialogService: AdminDialogService,
private readonly _dossierStatesMapService: DossierStatesMapService, private readonly _dossierStatesMapService: DossierStatesMapService,
private readonly _dossierStatesService: DossierStatesService, private readonly _dossierStatesService: DossierStatesService,
readonly permissionsService: PermissionsService,
) { ) {
super(); super();
this.chartConfig$ = this._dossierStatesMapService.get$(this.#dossierTemplateId).pipe( this.chartConfig$ = this._dossierStatesMapService.get$(this.#dossierTemplateId).pipe(

View File

@ -2,7 +2,7 @@
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
[hideResetButton]="true" [hideResetButton]="true"
[pageLabel]="'dossier-templates.label' | translate" [pageLabel]="'dossier-templates.label' | translate"
[showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" [showCloseButton]="currentUser.isUser && (permissionsService.has$(roles.dossiers.read) | async)"
></iqser-page-header> ></iqser-page-header>
<iqser-table <iqser-table
@ -19,7 +19,7 @@
<ng-template #bulkActions> <ng-template #bulkActions>
<iqser-circle-button <iqser-circle-button
(action)="openBulkDeleteTemplatesDialog($event)" (action)="openBulkDeleteTemplatesDialog($event)"
*allow="roles.templates.write; if: listingService.areSomeSelected$ | async" *allow="roles.templates.write; if: currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
[icon]="'iqser:trash'" [icon]="'iqser:trash'"
[tooltip]="'dossier-templates-listing.bulk.delete' | translate" [tooltip]="'dossier-templates-listing.bulk.delete' | translate"
[type]="circleButtonTypes.dark" [type]="circleButtonTypes.dark"
@ -35,7 +35,7 @@
<iqser-icon-button <iqser-icon-button
(action)="openAddDossierTemplateDialog()" (action)="openAddDossierTemplateDialog()"
*allow="roles.templates.write; if: userPreferenceService.areDevFeaturesEnabled" *allow="roles.templates.write; if: currentUser.isAdmin && userPreferenceService.areDevFeaturesEnabled"
[icon]="'iqser:plus'" [icon]="'iqser:plus'"
[label]="'dossier-templates-listing.add-new' | translate" [label]="'dossier-templates-listing.add-new' | translate"
[type]="iconButtonTypes.primary" [type]="iconButtonTypes.primary"

View File

@ -1,9 +1,10 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { UserPreferenceService } from '@users/user-preference.service'; import { UserPreferenceService } from '@users/user-preference.service';
import { AdminDialogService } from '../../../services/admin-dialog.service'; import { AdminDialogService } from '../../../services/admin-dialog.service';
import { DossierTemplate } from '@red/domain'; import { DossierTemplate, User } from '@red/domain';
import { import {
CircleButtonTypes, CircleButtonTypes,
getCurrentUser,
IconButtonTypes, IconButtonTypes,
IqserPermissionsService, IqserPermissionsService,
ListingComponent, ListingComponent,
@ -30,6 +31,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent<Dos
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
readonly tableHeaderLabel = _('dossier-templates-listing.table-header.title'); readonly tableHeaderLabel = _('dossier-templates-listing.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<DossierTemplate>[] = [ readonly tableColumnConfigs: TableColumnConfig<DossierTemplate>[] = [
{ label: _('dossier-templates-listing.table-col-names.name'), sortByKey: 'searchKey', width: '3fr' }, { label: _('dossier-templates-listing.table-col-names.name'), sortByKey: 'searchKey', width: '3fr' },

View File

@ -57,7 +57,7 @@
<div class="actions"> <div class="actions">
<iqser-icon-button <iqser-icon-button
(action)="openAddEntityDialog()" (action)="openAddEntityDialog()"
*allow="roles.dictionaryTypes.write" *ngIf="permissionsService.canEditEntities()"
[iqserHelpMode]="'create_new_entity'" [iqserHelpMode]="'create_new_entity'"
[label]="'entities-listing.add-new' | translate" [label]="'entities-listing.add-new' | translate"
[type]="iconButtonTypes.primary" [type]="iconButtonTypes.primary"
@ -109,7 +109,7 @@
></iqser-circle-button> ></iqser-circle-button>
<iqser-circle-button <iqser-circle-button
*allow="roles.dictionaryTypes.write" *ngIf="permissionsService.canEditEntities()"
[routerLink]="dict.routerLink" [routerLink]="dict.routerLink"
[tooltip]="'entities-listing.action.edit' | translate" [tooltip]="'entities-listing.action.edit' | translate"
[type]="circleButtonTypes.dark" [type]="circleButtonTypes.dark"

View File

@ -17,7 +17,6 @@ import { DossierTemplateStatsService } from '@services/entity-services/dossier-t
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { ROLES } from '@users/roles';
@Component({ @Component({
templateUrl: './entities-listing-screen.component.html', templateUrl: './entities-listing-screen.component.html',
@ -27,7 +26,6 @@ import { ROLES } from '@users/roles';
export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> { export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> {
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES;
readonly tableHeaderLabel = _('entities-listing.table-header.title'); readonly tableHeaderLabel = _('entities-listing.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [ readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [
{ label: _('entities-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' }, { label: _('entities-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },

View File

@ -17,7 +17,7 @@
></redaction-add-edit-entity> ></redaction-add-edit-entity>
</div> </div>
<div *allow="roles.dictionaryTypes.write" class="dialog-actions"> <div *ngIf="permissionsService.canEditEntities()" class="dialog-actions">
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button> <button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
{{ 'entity.info.actions.save' | translate }} {{ 'entity.info.actions.save' | translate }}
</button> </button>

View File

@ -7,7 +7,6 @@ import { PermissionsService } from '@services/permissions.service';
import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component'; import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component';
import { IqserEventTarget } from '@iqser/common-ui'; import { IqserEventTarget } from '@iqser/common-ui';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ROLES } from '@users/roles';
@Component({ @Component({
selector: 'redaction-entity-info', selector: 'redaction-entity-info',
@ -17,7 +16,6 @@ import { ROLES } from '@users/roles';
}) })
export class EntityInfoComponent { export class EntityInfoComponent {
readonly currentUser = getCurrentUser(); readonly currentUser = getCurrentUser();
readonly roles = ROLES;
readonly entity$: Observable<Dictionary>; readonly entity$: Observable<Dictionary>;
readonly dossierTemplateId: string; readonly dossierTemplateId: string;
@ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent; @ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent;

View File

@ -2,7 +2,7 @@
<div class="heading-l" translate="general-config-screen.general.title"></div> <div class="heading-l" translate="general-config-screen.general.title"></div>
<div translate="general-config-screen.general.subtitle"></div> <div translate="general-config-screen.general.subtitle"></div>
</div> </div>
<form (submit)="save()" [formGroup]="form" *ngIf="form"> <form (submit)="save()" *ngIf="form" [formGroup]="form">
<div class="dialog-content"> <div class="dialog-content">
<div class="dialog-content-left"> <div class="dialog-content-left">
<div class="iqser-input-group"> <div class="iqser-input-group">
@ -22,13 +22,14 @@
</div> </div>
</div> </div>
</div> </div>
<div class="dialog-actions"> <div class="dialog-actions">
<button <button
[disabled]="form?.invalid || !changed" [disabled]="form?.invalid || !changed"
[iqserHelpMode]="'general_configurations'"
color="primary" color="primary"
mat-flat-button mat-flat-button
type="submit" type="submit"
[iqserHelpMode]="'general_configurations'"
> >
{{ 'general-config-screen.actions.save' | translate }} {{ 'general-config-screen.actions.save' | translate }}
</button> </button>

View File

@ -1,10 +1,11 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { BaseFormComponent, LoadingService } from '@iqser/common-ui'; import { BaseFormComponent, IqserPermissionsService, LoadingService } from '@iqser/common-ui';
import { GeneralSettingsService } from '@services/general-settings.service'; import { GeneralSettingsService } from '@services/general-settings.service';
import { IGeneralConfiguration } from '@red/domain'; import { IGeneralConfiguration } from '@red/domain';
import { ConfigService } from '@services/config.service'; import { ConfigService } from '@services/config.service';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { ROLES } from '@users/roles';
@Component({ @Component({
selector: 'redaction-general-config-form', selector: 'redaction-general-config-form',
@ -18,9 +19,13 @@ export class GeneralConfigFormComponent extends BaseFormComponent implements OnI
private readonly _generalSettingsService: GeneralSettingsService, private readonly _generalSettingsService: GeneralSettingsService,
private readonly _configService: ConfigService, private readonly _configService: ConfigService,
private readonly _formBuilder: UntypedFormBuilder, private readonly _formBuilder: UntypedFormBuilder,
private readonly _permissionsService: IqserPermissionsService,
) { ) {
super(); super();
this.form = this._getForm(); this.form = this._getForm();
if (!_permissionsService.has(ROLES.generalConfiguration.write)) {
this.form.disable();
}
} }
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {

View File

@ -1,11 +1,12 @@
import { Component, OnDestroy, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { ISmtpConfiguration } from '@red/domain'; import { ISmtpConfiguration } from '@red/domain';
import { BaseFormComponent, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; import { BaseFormComponent, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui';
import { AdminDialogService } from '../../../services/admin-dialog.service'; import { AdminDialogService } from '../../../services/admin-dialog.service';
import { SmtpConfigService } from '../../../services/smtp-config.service'; import { SmtpConfigService } from '../../../services/smtp-config.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { ROLES } from '@users/roles';
@Component({ @Component({
selector: 'redaction-smtp-form', selector: 'redaction-smtp-form',
@ -21,9 +22,13 @@ export class SmtpFormComponent extends BaseFormComponent implements OnInit {
private readonly _smtpConfigService: SmtpConfigService, private readonly _smtpConfigService: SmtpConfigService,
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
private readonly _toaster: Toaster, private readonly _toaster: Toaster,
private readonly _permissionsService: IqserPermissionsService,
) { ) {
super(); super();
this.form = this._getForm(); this.form = this._getForm();
if (!_permissionsService.has(ROLES.smtp.write)) {
this.form.disable();
}
} }
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {

View File

@ -1,10 +1,11 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { SystemPreferences } from '@red/domain'; import { SystemPreferences } from '@red/domain';
import { BaseFormComponent, KeysOf, LoadingService } from '@iqser/common-ui'; import { BaseFormComponent, IqserPermissionsService, KeysOf, LoadingService } from '@iqser/common-ui';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { SystemPreferencesService } from '@services/system-preferences.service'; import { SystemPreferencesService } from '@services/system-preferences.service';
import { systemPreferencesTranslations } from '@translations/system-preferences-translations'; import { systemPreferencesTranslations } from '@translations/system-preferences-translations';
import { ROLES } from '@users/roles';
export type ValueType = 'number' | 'string' | 'boolean'; export type ValueType = 'number' | 'string' | 'boolean';
@ -25,10 +26,14 @@ export class SystemPreferencesFormComponent extends BaseFormComponent {
private readonly _loadingService: LoadingService, private readonly _loadingService: LoadingService,
private readonly _systemPreferencesService: SystemPreferencesService, private readonly _systemPreferencesService: SystemPreferencesService,
private readonly _formBuilder: UntypedFormBuilder, private readonly _formBuilder: UntypedFormBuilder,
private readonly _permissionsService: IqserPermissionsService,
) { ) {
super(); super();
this.form = this._getForm(); this.form = this._getForm();
this._loadData(); this._loadData();
if (!_permissionsService.has(ROLES.appConfiguration.write)) {
this.form.disable();
}
} }
async save(): Promise<void> { async save(): Promise<void> {

View File

@ -4,7 +4,7 @@
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
[buttonConfigs]="buttonConfigs" [buttonConfigs]="buttonConfigs"
[pageLabel]="'license-information' | translate" [pageLabel]="'license-information' | translate"
[showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" [showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
></iqser-page-header> ></iqser-page-header>
<div class="content-inner"> <div class="content-inner">

View File

@ -1,12 +1,13 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ConfigService } from '@services/config.service'; import { ConfigService } from '@services/config.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { ButtonConfig, IconButtonTypes, IqserPermissionsService, LoadingService } from '@iqser/common-ui'; import { ButtonConfig, getCurrentUser, IconButtonTypes, IqserPermissionsService, LoadingService } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { RouterHistoryService } from '@services/router-history.service'; import { RouterHistoryService } from '@services/router-history.service';
import { LicenseService } from '@services/license.service'; import { LicenseService } from '@services/license.service';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
import { User } from '@red/domain';
@Component({ @Component({
templateUrl: './license-screen.component.html', templateUrl: './license-screen.component.html',
@ -14,6 +15,7 @@ import { ROLES } from '@users/roles';
}) })
export class LicenseScreenComponent implements OnInit { export class LicenseScreenComponent implements OnInit {
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
readonly currentYear = new Date().getFullYear(); readonly currentYear = new Date().getFullYear();
readonly buttonConfigs: readonly ButtonConfig[] = [ readonly buttonConfigs: readonly ButtonConfig[] = [
{ {

View File

@ -1,7 +1,7 @@
<iqser-page-header <iqser-page-header
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
[pageLabel]="'permissions-screen.label' | translate: { targetObject: this.targetObject }" [pageLabel]="'permissions-screen.label' | translate: { targetObject: this.targetObject }"
[showCloseButton]="permissionsService.has$(roles.dossiers.read) | async" [showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
></iqser-page-header> ></iqser-page-header>
<iqser-table [itemSize]="80" [tableColumnConfigs]="tableColumnConfigs"></iqser-table> <iqser-table [itemSize]="80" [tableColumnConfigs]="tableColumnConfigs"></iqser-table>

View File

@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { import {
getCurrentUser,
IqserPermissionsService, IqserPermissionsService,
ListingComponent, ListingComponent,
listingProvidersFactory, listingProvidersFactory,
@ -7,7 +8,7 @@ import {
SortingOrders, SortingOrders,
TableColumnConfig, TableColumnConfig,
} from '@iqser/common-ui'; } from '@iqser/common-ui';
import { PermissionsMapping } from '@red/domain'; import { PermissionsMapping, User } from '@red/domain';
import { ConfigService } from '../config.service'; import { ConfigService } from '../config.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EntityPermissionsService } from '@services/entity-permissions/entity-permissions.service'; import { EntityPermissionsService } from '@services/entity-permissions/entity-permissions.service';
@ -30,6 +31,7 @@ import { ROLES } from '@users/roles';
}) })
export class PermissionsScreenComponent extends ListingComponent<PermissionsMapping> { export class PermissionsScreenComponent extends ListingComponent<PermissionsMapping> {
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
readonly translations = permissionsTranslations; readonly translations = permissionsTranslations;
readonly tableColumnConfigs: TableColumnConfig<PermissionsMapping>[]; readonly tableColumnConfigs: TableColumnConfig<PermissionsMapping>[];
readonly tableHeaderLabel = _('permissions-screen.table-header.title'); readonly tableHeaderLabel = _('permissions-screen.table-header.title');

View File

@ -59,14 +59,14 @@
></mat-slide-toggle> ></mat-slide-toggle>
</div> </div>
<div class="cell" [ngClass]="!user.hasAnyRole && 'no-role-alignment'"> <div [ngClass]="!user.hasAnyRole && 'no-role-alignment'" class="cell">
<mat-icon *ngIf="!user.hasAnyRole" [svgIcon]="'red:alert-circle'" class="icon"></mat-icon> <mat-icon *ngIf="!user.hasAnyRole" [svgIcon]="'red:alert-circle'" class="icon"></mat-icon>
<span class="small-label opacity-1">{{ getDisplayRoles(user) }}</span> <span class="small-label opacity-1">{{ getDisplayRoles(user) }}</span>
</div> </div>
<div class="cell"> <div class="cell">
<div class="action-buttons"> <div class="action-buttons">
<div [iqserHelpMode]="'edit_delete_user'"> <div *allow="roles.users.write" [iqserHelpMode]="'edit_delete_user'">
<iqser-circle-button <iqser-circle-button
(action)="openAddEditUserDialog($event, user)" (action)="openAddEditUserDialog($event, user)"
[tooltip]="'user-listing.action.edit' | translate" [tooltip]="'user-listing.action.edit' | translate"

View File

@ -21,6 +21,7 @@ import { rolesTranslations } from '@translations/roles-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { userTypeChecker, userTypeFilters } from '../../../../utils'; import { userTypeChecker, userTypeFilters } from '../../../../utils';
import { RouterHistoryService } from '@services/router-history.service'; import { RouterHistoryService } from '@services/router-history.service';
import { ROLES } from '@users/roles';
function configToFilter({ key, label }: DonutChartConfig) { function configToFilter({ key, label }: DonutChartConfig) {
return new NestedFilter({ return new NestedFilter({
@ -43,6 +44,7 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
readonly translations = rolesTranslations; readonly translations = rolesTranslations;
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES;
readonly currentUser = this._userService.currentUser; readonly currentUser = this._userService.currentUser;
readonly canDeleteSelected$ = this.#canDeleteSelected$; readonly canDeleteSelected$ = this.#canDeleteSelected$;
readonly tableHeaderLabel = _('user-listing.table-header.title'); readonly tableHeaderLabel = _('user-listing.table-header.title');
@ -101,11 +103,9 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
} }
getDisplayRoles(user: User) { getDisplayRoles(user: User) {
const separator = ', '; const oldRedRoles = user.roles.filter(role => role.startsWith('RED_'));
return ( const translatedRoles = oldRedRoles.map(role => this._translateService.instant(this.translations[role]));
user.roles.map(role => this._translateService.instant(this.translations[role])).join(separator) || return translatedRoles.join(', ') || this._translateService.instant(this.translations['NO_ROLE']);
this._translateService.instant(this.translations['NO_ROLE'])
);
} }
async toggleActive(user: User) { async toggleActive(user: User) {

View File

@ -16,12 +16,12 @@
<div class="action-buttons"> <div class="action-buttons">
<iqser-circle-button <iqser-circle-button
(action)="openEditDossierDialog($event, dossier.id)" (action)="openEditDossierDialog($event, dossier.id)"
*allow="roles.dossiers.read" *allow="roles.dossiers.read; if: currentUser.isUser"
[icon]="(permissionsService.has$(roles.dossiers.edit) | async) ? 'iqser:edit' : 'red:info'" [icon]="(permissionsService.has$(roles.dossiers.edit) | async) && currentUser.isManager ? 'iqser:edit' : 'red:info'"
[iqserHelpMode]="'edit_dossier_dossier_info'" [iqserHelpMode]="'edit_dossier_dossier_info'"
[scrollableParentView]="scrollableParentView" [scrollableParentView]="scrollableParentView"
[tooltip]=" [tooltip]="
((permissionsService.has$(roles.dossiers.edit) | async) ((permissionsService.has$(roles.dossiers.edit) | async) && currentUser.isManager
? 'dossier-listing.edit.action' ? 'dossier-listing.edit.action'
: 'dossier-listing.dossier-info.action' : 'dossier-listing.dossier-info.action'
) | translate ) | translate

View File

@ -1,9 +1,9 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { Dossier, DossierStats } from '@red/domain'; import { Dossier, DossierStats, User } from '@red/domain';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service';
import { switchMap } from 'rxjs/operators'; import { switchMap } from 'rxjs/operators';
import { CircleButtonTypes, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; import { CircleButtonTypes, getCurrentUser, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui';
import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
@ -15,6 +15,7 @@ import { ROLES } from '@users/roles';
export class TableItemComponent implements OnChanges { export class TableItemComponent implements OnChanges {
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
@Input() dossier!: Dossier; @Input() dossier!: Dossier;
readonly stats$: Observable<DossierStats>; readonly stats$: Observable<DossierStats>;

View File

@ -71,7 +71,7 @@
<iqser-icon-button <iqser-icon-button
(action)="newDossier()" (action)="newDossier()"
*allow="roles.dossiers.write; if: dossierTemplate.isEmpty" *ngIf="permissionsService.canCreateDossier(dossierTemplate)"
[iqserHelpMode]="'new_dossier_button'" [iqserHelpMode]="'new_dossier_button'"
[label]="'dashboard.empty-template.new-dossier' | translate" [label]="'dashboard.empty-template.new-dossier' | translate"
[type]="iconButtonTypes.primary" [type]="iconButtonTypes.primary"

View File

@ -4,6 +4,7 @@ import { IconButtonTypes } from '@iqser/common-ui';
import { TranslateChartService } from '@services/translate-chart.service'; import { TranslateChartService } from '@services/translate-chart.service';
import { SharedDialogService } from '@shared/services/dialog.service'; import { SharedDialogService } from '@shared/services/dialog.service';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
import { PermissionsService } from '@services/permissions.service';
@Component({ @Component({
selector: 'redaction-template-stats [stats]', selector: 'redaction-template-stats [stats]',
@ -17,7 +18,11 @@ export class TemplateStatsComponent {
@Input() stats: DashboardStats; @Input() stats: DashboardStats;
constructor(private readonly _dialogService: SharedDialogService, readonly translateChartService: TranslateChartService) {} constructor(
private readonly _dialogService: SharedDialogService,
readonly translateChartService: TranslateChartService,
readonly permissionsService: PermissionsService,
) {}
newDossier(): void { newDossier(): void {
this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.stats.dossierTemplateId }); this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.stats.dossierTemplateId });

View File

@ -19,7 +19,7 @@
<iqser-circle-button <iqser-circle-button
(action)="editingOwner = true" (action)="editingOwner = true"
*allow="roles.dossiers.edit" *allow="roles.dossiers.edit; if: currentUser.isManager"
[icon]="'iqser:edit'" [icon]="'iqser:edit'"
[iqserHelpMode]="'dashboard_in_dossier'" [iqserHelpMode]="'dashboard_in_dossier'"
[tooltipPosition]="'below'" [tooltipPosition]="'below'"

View File

@ -13,7 +13,16 @@ import {
} from '@red/domain'; } from '@red/domain';
import { TranslateChartService } from '@services/translate-chart.service'; import { TranslateChartService } from '@services/translate-chart.service';
import { UserService } from '@users/user.service'; import { UserService } from '@users/user.service';
import { ContextComponent, FilterService, getParam, INestedFilter, ProgressBarConfigModel, shareLast, Toaster } from '@iqser/common-ui'; import {
ContextComponent,
FilterService,
getCurrentUser,
getParam,
INestedFilter,
ProgressBarConfigModel,
shareLast,
Toaster,
} from '@iqser/common-ui';
import { workflowFileStatusTranslations } from '@translations/file-status-translations'; import { workflowFileStatusTranslations } from '@translations/file-status-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { combineLatestWith, firstValueFrom, Observable } from 'rxjs'; import { combineLatestWith, firstValueFrom, Observable } from 'rxjs';
@ -44,6 +53,7 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
editingOwner = false; editingOwner = false;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
readonly collapseTooltip = _('dossier-details.collapse'); readonly collapseTooltip = _('dossier-details.collapse');
readonly expandTooltip = _('dossier-details.expand'); readonly expandTooltip = _('dossier-details.expand');
readonly needsWorkFilters$ = this.filterService.getFilterModels$('needsWorkFilters'); readonly needsWorkFilters$ = this.filterService.getFilterModels$('needsWorkFilters');
@ -78,7 +88,7 @@ export class DossierDetailsComponent extends ContextComponent<DossierDetailsCont
} }
get managers() { get managers() {
return this._userService.all.filter(u => u.has(ROLES.dossiers.write) || u.isManager).map(u => u.id); return this._userService.all.filter(u => u.isManager).map(u => u.id);
} }
ngOnInit() { ngOnInit() {

View File

@ -1,6 +1,7 @@
import { Injectable, TemplateRef } from '@angular/core'; import { Injectable, TemplateRef } from '@angular/core';
import { import {
ActionConfig, ActionConfig,
getCurrentUser,
getParam, getParam,
IFilterGroup, IFilterGroup,
INestedFilter, INestedFilter,
@ -22,6 +23,7 @@ import {
IFileAttributeConfig, IFileAttributeConfig,
ProcessingType, ProcessingType,
StatusSorter, StatusSorter,
User,
WorkflowFileStatus, WorkflowFileStatus,
WorkflowFileStatuses, WorkflowFileStatuses,
} from '@red/domain'; } from '@red/domain';
@ -48,6 +50,7 @@ import { ROLES } from '@users/roles';
export class ConfigService { export class ConfigService {
readonly listingMode$: Observable<ListingMode>; readonly listingMode$: Observable<ListingMode>;
readonly dossierId = getParam(DOSSIER_ID); readonly dossierId = getParam(DOSSIER_ID);
readonly currentUser = getCurrentUser<User>();
private readonly _listingMode$ = new BehaviorSubject<ListingMode>(ListingModes.table); private readonly _listingMode$ = new BehaviorSubject<ListingMode>(ListingModes.table);
constructor( constructor(
@ -155,7 +158,7 @@ export class ConfigService {
label: this._translateService.instant('dossier-overview.header-actions.edit'), label: this._translateService.instant('dossier-overview.header-actions.edit'),
action: $event => this._openEditDossierDialog($event, dossierId), action: $event => this._openEditDossierDialog($event, dossierId),
icon: 'iqser:edit', icon: 'iqser:edit',
hide: !this._iqserPermissionsService.has(ROLES.dossiers.edit), hide: !this.currentUser.isManager && !this._iqserPermissionsService.has(ROLES.dossiers.edit),
helpModeKey: 'edit_dossier_in_dossier', helpModeKey: 'edit_dossier_in_dossier',
disabled$, disabled$,
}, },

View File

@ -1,12 +1,12 @@
<div (longPress)="forceReanalysisAction($event)" class="action-buttons" redactionLongPress> <div (longPress)="forceReanalysisAction($event)" class="action-buttons" redactionLongPress>
<iqser-circle-button <iqser-circle-button
(action)="openEditDossierDialog($event, dossier.id)" (action)="openEditDossierDialog($event, dossier.id)"
*allow="roles.dossiers.read" *allow="roles.dossiers.read; if: currentUser.isUser"
[icon]="(iqserPermissionsService.has$(roles.dossiers.edit) | async) ? 'iqser:edit' : 'red:info'" [icon]="(iqserPermissionsService.has$(roles.dossiers.edit) | async) && currentUser.isManager ? 'iqser:edit' : 'red:info'"
[iqserHelpMode]="'edit_dossier_dossier_info'" [iqserHelpMode]="'edit_dossier_dossier_info'"
[scrollableParentView]="scrollableParentView" [scrollableParentView]="scrollableParentView"
[tooltip]=" [tooltip]="
((iqserPermissionsService.has$(roles.dossiers.edit) | async) ((iqserPermissionsService.has$(roles.dossiers.edit) | async) && currentUser.isManager
? 'dossier-listing.edit.action' ? 'dossier-listing.edit.action'
: 'dossier-listing.dossier-info.action' : 'dossier-listing.dossier-info.action'
) | translate ) | translate

View File

@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { CircleButtonTypes, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui'; import { CircleButtonTypes, getCurrentUser, IqserPermissionsService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui';
import { Dossier, DossierStats, File } from '@red/domain'; import { Dossier, DossierStats, File, User } from '@red/domain';
import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service';
import { LongPressEvent } from '@shared/directives/long-press.directive'; import { LongPressEvent } from '@shared/directives/long-press.directive';
import { UserPreferenceService } from '@users/user-preference.service'; import { UserPreferenceService } from '@users/user-preference.service';
@ -18,6 +18,7 @@ import { ROLES } from '@users/roles';
export class DossiersListingActionsComponent implements OnChanges { export class DossiersListingActionsComponent implements OnChanges {
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
analysisForced: boolean; analysisForced: boolean;
files: File[]; files: File[];

View File

@ -9,6 +9,7 @@ import {
IqserScrollbarModule, IqserScrollbarModule,
IqserSharedModule, IqserSharedModule,
IqserUsersModule, IqserUsersModule,
LogPipe,
} from '@iqser/common-ui'; } from '@iqser/common-ui';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { DossiersListingScreenComponent } from './screen/dossiers-listing-screen.component'; import { DossiersListingScreenComponent } from './screen/dossiers-listing-screen.component';
@ -58,6 +59,7 @@ const routes: Routes = [
IqserScrollbarModule, IqserScrollbarModule,
IqserSharedModule, IqserSharedModule,
IqserPermissionsModule, IqserPermissionsModule,
LogPipe,
], ],
}) })
export class DossiersListingModule {} export class DossiersListingModule {}

View File

@ -82,7 +82,7 @@
<iqser-circle-button <iqser-circle-button
(action)="annotationActionsService.undoDirectAction($event, annotations)" (action)="annotationActionsService.undoDirectAction($event, annotations)"
*ngIf="annotationPermissions.canUndo" *allow="roles.redactions.deleteManual; if: annotationPermissions.canUndo"
[tooltipPosition]="tooltipPosition" [tooltipPosition]="tooltipPosition"
[tooltip]="'annotation-actions.undo' | translate" [tooltip]="'annotation-actions.undo' | translate"
[type]="buttonType" [type]="buttonType"

View File

@ -9,6 +9,7 @@ import { FilePreviewStateService } from '../../services/file-preview-state.servi
import { HelpModeService } from '@iqser/common-ui'; import { HelpModeService } from '@iqser/common-ui';
import { ViewModeService } from '../../services/view-mode.service'; import { ViewModeService } from '../../services/view-mode.service';
import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service'; import { REDAnnotationManager } from '../../../pdf-viewer/services/annotation-manager.service';
import { ROLES } from '@users/roles';
export const AnnotationButtonTypes = { export const AnnotationButtonTypes = {
dark: 'dark', dark: 'dark',
@ -29,6 +30,7 @@ export class AnnotationActionsComponent implements OnChanges {
@Input() canPerformAnnotationActions: boolean; @Input() canPerformAnnotationActions: boolean;
@Input() alwaysVisible: boolean; @Input() alwaysVisible: boolean;
annotationPermissions: AnnotationPermissions; annotationPermissions: AnnotationPermissions;
readonly roles = ROLES;
constructor( constructor(
readonly viewModeService: ViewModeService, readonly viewModeService: ViewModeService,

View File

@ -11,7 +11,7 @@ import type {
ManualRedactionActions, ManualRedactionActions,
} from '@red/domain'; } from '@red/domain';
import { type AnnotationWrapper } from '@models/file/annotation.wrapper'; import { type AnnotationWrapper } from '@models/file/annotation.wrapper';
import { GenericService, List, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; import { GenericService, IqserPermissionsService, List, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { map, tap } from 'rxjs/operators'; import { map, tap } from 'rxjs/operators';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { dictionaryActionsTranslations, manualRedactionActionsTranslations } from '@translations/annotation-actions-translations'; import { dictionaryActionsTranslations, manualRedactionActionsTranslations } from '@translations/annotation-actions-translations';
@ -20,6 +20,8 @@ import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { type ManualRedactionEntryType } from '@models/file/manual-redaction-entry.wrapper'; import { type ManualRedactionEntryType } from '@models/file/manual-redaction-entry.wrapper';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { ROLES } from '@users/roles';
import { of } from 'rxjs';
function getResponseType(error: boolean, isConflict: boolean) { function getResponseType(error: boolean, isConflict: boolean) {
const isConflictError = isConflict ? 'conflictError' : 'error'; const isConflictError = isConflict ? 'conflictError' : 'error';
@ -45,6 +47,7 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
private readonly _toaster: Toaster, private readonly _toaster: Toaster,
private readonly _logger: NGXLogger, private readonly _logger: NGXLogger,
private readonly _permissionsService: PermissionsService, private readonly _permissionsService: PermissionsService,
private readonly _iqaerPermissionsService: IqserPermissionsService,
private readonly _activeDossiersService: ActiveDossiersService, private readonly _activeDossiersService: ActiveDossiersService,
) { ) {
super(); super();
@ -93,11 +96,17 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
addAnnotation(requests: List<IAddRedactionRequest>, dossierId: string, fileId: string, dictionaryLabel?: string) { addAnnotation(requests: List<IAddRedactionRequest>, dossierId: string, fileId: string, dictionaryLabel?: string) {
const toast = requests[0].addToDictionary ? this.#showAddToDictionaryToast(requests, dictionaryLabel) : this.#showToast('add'); const toast = requests[0].addToDictionary ? this.#showAddToDictionaryToast(requests, dictionaryLabel) : this.#showToast('add');
if (this._permissionsService.isApprover(this.#dossier(dossierId))) { const canAddRedaction = this._iqaerPermissionsService.has(ROLES.redactions.write);
if (canAddRedaction && this._permissionsService.isApprover(this.#dossier(dossierId))) {
return this.add(requests, dossierId, fileId).pipe(toast); return this.add(requests, dossierId, fileId).pipe(toast);
} }
return this.requestAdd(requests, dossierId, fileId).pipe(toast); const canRequestRedaction = this._iqaerPermissionsService.has(ROLES.redactions.request);
if (canRequestRedaction) {
return this.requestAdd(requests, dossierId, fileId).pipe(toast);
}
return of(undefined);
} }
bulkForce(requests: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) { bulkForce(requests: List<ILegalBasisChangeRequest>, dossierId: string, fileId: string) {

View File

@ -5,9 +5,10 @@ import { PermissionsService } from '../../../services/permissions.service';
import { FilePreviewStateService } from './file-preview-state.service'; import { FilePreviewStateService } from './file-preview-state.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { AnnotationActionsService } from './annotation-actions.service'; import { AnnotationActionsService } from './annotation-actions.service';
import { BASE_HREF_FN } from '@iqser/common-ui'; import { BASE_HREF_FN, IqserPermissionsService } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { IHeaderElement } from '@red/domain'; import { IHeaderElement } from '@red/domain';
import { ROLES } from '@users/roles';
@Injectable() @Injectable()
export class PdfAnnotationActionsService { export class PdfAnnotationActionsService {
@ -17,6 +18,7 @@ export class PdfAnnotationActionsService {
readonly #ngZone = inject(NgZone); readonly #ngZone = inject(NgZone);
readonly #convertPath = inject(BASE_HREF_FN); readonly #convertPath = inject(BASE_HREF_FN);
readonly #annotationActionsService = inject(AnnotationActionsService); readonly #annotationActionsService = inject(AnnotationActionsService);
readonly #iqserPermissionsService = inject(IqserPermissionsService);
get(annotations: AnnotationWrapper[]): IHeaderElement[] { get(annotations: AnnotationWrapper[]): IHeaderElement[] {
const availableActions: IHeaderElement[] = []; const availableActions: IHeaderElement[] = [];
@ -152,7 +154,9 @@ export class PdfAnnotationActionsService {
), ),
canAcceptRecommendation: permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true), canAcceptRecommendation: permissions.reduce((acc, next) => acc && next.canAcceptRecommendation, true),
canAcceptSuggestion: permissions.reduce((acc, next) => acc && next.canAcceptSuggestion, true), canAcceptSuggestion: permissions.reduce((acc, next) => acc && next.canAcceptSuggestion, true),
canUndo: permissions.reduce((acc, next) => acc && next.canUndo, true), canUndo:
this.#iqserPermissionsService.has(ROLES.redactions.deleteManual) &&
permissions.reduce((acc, next) => acc && next.canUndo, true),
canMarkAsFalsePositive: permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true), canMarkAsFalsePositive: permissions.reduce((acc, next) => acc && next.canMarkAsFalsePositive, true),
canForceRedaction: permissions.reduce((acc, next) => acc && next.canForceRedaction, true), canForceRedaction: permissions.reduce((acc, next) => acc && next.canForceRedaction, true),
canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true), canForceHint: permissions.reduce((acc, next) => acc && next.canForceHint, true),

View File

@ -9,7 +9,7 @@ import {
} from '@models/file/manual-redaction-entry.wrapper'; } from '@models/file/manual-redaction-entry.wrapper';
import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service'; import { AnnotationDrawService } from '../../pdf-viewer/services/annotation-draw.service';
import { UserPreferenceService } from '@users/user-preference.service'; import { UserPreferenceService } from '@users/user-preference.service';
import { BASE_HREF_FN, BaseHrefFn, shareDistinctLast } from '@iqser/common-ui'; import { BASE_HREF_FN, BaseHrefFn, IqserPermissionsService, shareDistinctLast } from '@iqser/common-ui';
import { toPosition } from '../utils/pdf-calculation.utils'; import { toPosition } from '../utils/pdf-calculation.utils';
import { MultiSelectService } from './multi-select.service'; import { MultiSelectService } from './multi-select.service';
import { FilePreviewStateService } from './file-preview-state.service'; import { FilePreviewStateService } from './file-preview-state.service';
@ -28,6 +28,7 @@ import { PermissionsService } from '@services/permissions.service';
import { AnnotationsListingService } from './annotations-listing.service'; import { AnnotationsListingService } from './annotations-listing.service';
import { PdfAnnotationActionsService } from './pdf-annotation-actions.service'; import { PdfAnnotationActionsService } from './pdf-annotation-actions.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { ROLES } from '@users/roles';
import Annotation = Core.Annotations.Annotation; import Annotation = Core.Annotations.Annotation;
import Quad = Core.Math.Quad; import Quad = Core.Math.Quad;
@ -70,6 +71,7 @@ export class PdfProxyService {
private readonly _listingService: AnnotationsListingService, private readonly _listingService: AnnotationsListingService,
private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _dictionariesMapService: DictionariesMapService, private readonly _dictionariesMapService: DictionariesMapService,
private readonly _iqserPermissionsService: IqserPermissionsService,
) { ) {
this.canPerformAnnotationActions$ = this.#canPerformAnnotationActions$; this.canPerformAnnotationActions$ = this.#canPerformAnnotationActions$;
} }
@ -240,20 +242,23 @@ export class PdfProxyService {
}); });
} }
popups.push({ if (this._iqserPermissionsService.has(ROLES.redactions.write) || this._iqserPermissionsService.has(ROLES.redactions.request)) {
type: 'actionButton', popups.push({
dataElement: TextPopups.ADD_REDACTION, type: 'actionButton',
img: this.#addRedactionIcon, dataElement: TextPopups.ADD_REDACTION,
title: this.#getTitle(ManualRedactionEntryTypes.REDACTION), img: this.#addRedactionIcon,
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION), title: this.#getTitle(ManualRedactionEntryTypes.REDACTION),
}); onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.REDACTION),
popups.push({ });
type: 'actionButton',
dataElement: TextPopups.ADD_DICTIONARY, popups.push({
img: this.#addDictIcon, type: 'actionButton',
title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY), dataElement: TextPopups.ADD_DICTIONARY,
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY), img: this.#addDictIcon,
}); title: this.#getTitle(ManualRedactionEntryTypes.DICTIONARY),
onClick: () => this._addManualRedactionOfType(ManualRedactionEntryTypes.DICTIONARY),
});
}
this._pdf.configureTextPopups(popups); this._pdf.configureTextPopups(popups);

View File

@ -1,10 +1,17 @@
import { AfterViewInit, Component, Inject, ViewChild } from '@angular/core'; import { AfterViewInit, Component, Inject, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Dossier } from '@red/domain'; import { Dossier, User } from '@red/domain';
import { EditDossierGeneralInfoComponent } from './general-info/edit-dossier-general-info.component'; import { EditDossierGeneralInfoComponent } from './general-info/edit-dossier-general-info.component';
import { EditDossierDownloadPackageComponent } from './download-package/edit-dossier-download-package.component'; import { EditDossierDownloadPackageComponent } from './download-package/edit-dossier-download-package.component';
import { EditDossierSectionInterface } from './edit-dossier-section.interface'; import { EditDossierSectionInterface } from './edit-dossier-section.interface';
import { BaseDialogComponent, ConfirmOptions, IconButtonTypes, IqserPermissionsService, SaveOptions } from '@iqser/common-ui'; import {
BaseDialogComponent,
ConfirmOptions,
getCurrentUser,
IconButtonTypes,
IqserPermissionsService,
SaveOptions,
} from '@iqser/common-ui';
import { EditDossierDictionaryComponent } from './dictionary/edit-dossier-dictionary.component'; import { EditDossierDictionaryComponent } from './dictionary/edit-dossier-dictionary.component';
import { EditDossierAttributesComponent } from './attributes/edit-dossier-attributes.component'; import { EditDossierAttributesComponent } from './attributes/edit-dossier-attributes.component';
@ -42,6 +49,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A
@ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent; @ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent;
@ViewChild(EditDossierTeamComponent) membersComponent: EditDossierTeamComponent; @ViewChild(EditDossierTeamComponent) membersComponent: EditDossierTeamComponent;
@ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent; @ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent;
readonly #currentUser = getCurrentUser<User>();
private _dossier: Dossier; private _dossier: Dossier;
constructor( constructor(
@ -89,7 +97,9 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A
get showActionButtons(): boolean { get showActionButtons(): boolean {
return ( return (
(['members'].includes(this.activeNav) && this._iqserPermissionsService.has(ROLES.dossiers.edit)) || (['members'].includes(this.activeNav) &&
this.#currentUser.isManager &&
this._iqserPermissionsService.has(ROLES.dossiers.edit)) ||
this._permissionsService.canEditDossier(this._dossier) this._permissionsService.canEditDossier(this._dossier)
); );
} }

View File

@ -1,14 +1,14 @@
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
import { UserService } from '@users/user.service'; import { UserService } from '@users/user.service';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Dossier, IDossierRequest } from '@red/domain'; import { Dossier, IDossierRequest, User } from '@red/domain';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface'; import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { BehaviorSubject, firstValueFrom } from 'rxjs'; import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { DossiersService } from '@services/dossiers/dossiers.service'; import { DossiersService } from '@services/dossiers/dossiers.service';
import { compareLists } from '@utils/functions'; import { compareLists } from '@utils/functions';
import { FilesService } from '@services/files/files.service'; import { FilesService } from '@services/files/files.service';
import { ROLES } from '@users/roles'; import { getCurrentUser } from '@iqser/common-ui';
@Component({ @Component({
selector: 'redaction-edit-dossier-team', selector: 'redaction-edit-dossier-team',
@ -23,9 +23,9 @@ export class EditDossierTeamComponent implements EditDossierSectionInterface, On
@Input() dossier: Dossier; @Input() dossier: Dossier;
membersSelectOptions: string[] = []; membersSelectOptions: string[] = [];
readonly ownersSelectOptions = this.userService.all.filter(u => u.isManager).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<string[]>([]); readonly selectedReviewers$ = new BehaviorSubject<string[]>([]);
readonly #currentUser = getCurrentUser<User>();
constructor( constructor(
readonly userService: UserService, readonly userService: UserService,
@ -138,7 +138,7 @@ export class EditDossierTeamComponent implements EditDossierSectionInterface, On
} }
setMembersSelectOptions(value = this.searchQuery): void { setMembersSelectOptions(value = this.searchQuery): void {
const possibleMembers = this.userService.all.filter(user => user.has(ROLES.dossiers.read) || user.isUser || user.isManager); const possibleMembers = this.userService.all.filter(user => user.isUser || user.isManager);
this.membersSelectOptions = possibleMembers this.membersSelectOptions = possibleMembers
.filter(user => this.userService.getName(user.id).toLowerCase().includes(value.toLowerCase())) .filter(user => this.userService.getName(user.id).toLowerCase().includes(value.toLowerCase()))
.filter(user => this.selectedOwnerId !== user.id) .filter(user => this.selectedOwnerId !== user.id)

View File

@ -19,7 +19,7 @@
<iqser-circle-button <iqser-circle-button
(action)="openEditDossierDialog()" (action)="openEditDossierDialog()"
*allow="roles.dossiers.edit; if: canAdd" *allow="roles.dossiers.edit; if: currentUser.isManager && canAdd"
[class.large-spacing]="largeSpacing" [class.large-spacing]="largeSpacing"
[icon]="'iqser:plus'" [icon]="'iqser:plus'"
[iqserHelpMode]="'edit_dossier_members'" [iqserHelpMode]="'edit_dossier_members'"

View File

@ -1,7 +1,8 @@
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { CircleButtonTypes, List } from '@iqser/common-ui'; import { CircleButtonTypes, getCurrentUser, List } from '@iqser/common-ui';
import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service'; import { DossiersDialogService } from '../../../shared-dossiers/services/dossiers-dialog.service';
import { ROLES } from '@users/roles'; import { ROLES } from '@users/roles';
import { User } from '@red/domain';
@Component({ @Component({
selector: 'redaction-team-members', selector: 'redaction-team-members',
@ -11,6 +12,7 @@ import { ROLES } from '@users/roles';
export class TeamMembersComponent { export class TeamMembersComponent {
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly roles = ROLES; readonly roles = ROLES;
readonly currentUser = getCurrentUser<User>();
@Input() memberIds: List; @Input() memberIds: List;
@Input() perLine: number; @Input() perLine: number;

View File

@ -23,14 +23,19 @@ export class PermissionsService {
return this.isAdmin() || this.isManager(); return this.isAdmin() || this.isManager();
} }
canPerformDossierStatesActions() {
return this.isAdmin() && this._iqserPermissionsService.has(ROLES.states.write);
}
canEditEntities(): boolean { canEditEntities(): boolean {
return this._iqserPermissionsService.has(ROLES.dictionaryTypes.write); return this._iqserPermissionsService.has(ROLES.dictionaryTypes.write) && this.isAdmin();
} }
canDeleteEntities(entity: Dictionary | Dictionary[]): boolean { canDeleteEntities(entity: Dictionary | Dictionary[]): boolean {
const entities = entity instanceof Dictionary ? [entity] : entity; const entities = entity instanceof Dictionary ? [entity] : entity;
return ( return (
entities.length && entities.length &&
this.isAdmin() &&
this._iqserPermissionsService.has(ROLES.dictionaryTypes.delete) && this._iqserPermissionsService.has(ROLES.dictionaryTypes.delete) &&
entities.reduce((acc, _entity) => this._canDeleteEntity(_entity) && acc, true) entities.reduce((acc, _entity) => this._canDeleteEntity(_entity) && acc, true)
); );
@ -239,7 +244,10 @@ export class PermissionsService {
} }
canSoftDeleteDossier(dossier: IDossier): boolean { canSoftDeleteDossier(dossier: IDossier): boolean {
return this._iqserPermissionsService.has(ROLES.dossiers.delete) && (this.isOwner(dossier) || this.isDossierMember(dossier)); return (
this._iqserPermissionsService.has(ROLES.dossiers.delete) &&
(this.isOwner(dossier) || (this.isManager() && this.isDossierMember(dossier)))
);
} }
canHardDeleteDossier(dossier: IDossier): boolean { canHardDeleteDossier(dossier: IDossier): boolean {
@ -251,7 +259,7 @@ export class PermissionsService {
} }
canCreateDossier(dossierTemplate: DossierTemplate | DashboardStats): boolean { canCreateDossier(dossierTemplate: DossierTemplate | DashboardStats): boolean {
return this._iqserPermissionsService.has(ROLES.dossiers.write) && dossierTemplate.isActive; return this._iqserPermissionsService.has(ROLES.dossiers.write) && this.isManager() && dossierTemplate.isActive;
} }
canArchiveDossier(dossier: Dossier): boolean { canArchiveDossier(dossier: Dossier): boolean {
@ -264,7 +272,7 @@ export class PermissionsService {
} }
canEditDossier(dossier: Dossier): boolean { canEditDossier(dossier: Dossier): boolean {
return this._iqserPermissionsService.has(ROLES.dossiers.edit) && !!dossier?.ownerId; return this._iqserPermissionsService.has(ROLES.dossiers.edit) && this.isManager() && !!dossier?.ownerId;
} }
canEditDossierDictionary(dossier: Dossier): boolean { canEditDossierDictionary(dossier: Dossier): boolean {
@ -276,7 +284,7 @@ export class PermissionsService {
} }
canEditTeamMembers(): boolean { canEditTeamMembers(): boolean {
return this._iqserPermissionsService.has(ROLES.dossiers.edit); return this._iqserPermissionsService.has(ROLES.dossiers.edit) && this.isManager();
} }
isAdmin(): boolean { isAdmin(): boolean {

View File

@ -2,15 +2,15 @@ export const ROLES = {
RED_CREATE_TENANT: 'red-create-tenant', RED_CREATE_TENANT: 'red-create-tenant',
RED_DEPLOYMENT_INFO: 'red-deployment-info', RED_DEPLOYMENT_INFO: 'red-deployment-info',
RED_GET_TENANTS: 'red-get-tenants', RED_GET_TENANTS: 'red-get-tenants',
RED_MANAGE_USER_PREFERENCES: 'red-manage-user-preferences',
RED_PROCESS_DOWNLOAD: 'red-process-download', RED_PROCESS_DOWNLOAD: 'red-process-download',
RED_PROCESS_MANUAL_REDACTION_REQUEST: 'red-process-manual-redaction-request', RED_PROCESS_MANUAL_REDACTION_REQUEST: 'red-process-manual-redaction-request',
RED_READ_RULES: 'red-read-rules', RED_READ_RULES: 'red-read-rules',
RED_READ_VERSIONS: 'red-read-versions', RED_READ_VERSIONS: 'red-read-versions',
RED_REINDEX: 'red-reindex', RED_REINDEX: 'red-reindex',
RED_ROTATE_PAGE: 'red-rotate-page', RED_ROTATE_PAGE: 'red-rotate-page',
RED_UPDATE_MY_PROFILE: 'red-update-my-profile',
RED_WRITE_RULES: 'red-write-rules', RED_WRITE_RULES: 'red-write-rules',
managePreferences: 'red-manage-user-preferences',
updateMyProfile: 'red-update-my-profile',
getRss: 'red-get-rss', getRss: 'red-get-rss',
excludeIncludeFile: 'red-exclude-include-file', excludeIncludeFile: 'red-exclude-include-file',
excludeIncludePages: 'red-exclude-include-pages', excludeIncludePages: 'red-exclude-include-pages',

View File

@ -17,7 +17,7 @@ export class UserService extends IqserUserService<IIqserUser, User> {
this._permissionsService.add({ this._permissionsService.add({
[ROLES.any]: (permission, all) => { [ROLES.any]: (permission, all) => {
console.log('all roles: ', Object.keys(all)); console.log('all roles: ', Object.keys(all));
return Object.keys(all).some(key => key.startsWith('red-')); return Object.keys(all).some(key => key.startsWith('red-') || key.startsWith('RED_'));
}, },
}); });