From 61a01c466524841779c105a6d2fe9356482a259c Mon Sep 17 00:00:00 2001 From: Florent POITTEVIN <poittevin.florent@gmail.com> Date: Thu, 4 Feb 2021 11:35:46 +0100 Subject: [PATCH] feat: 231 deposit redirect to deposit lists with an error message if we try to access a deposit we are not allowed to see --- .../deposit-detail/deposit-detail.routable.ts | 3 +- .../deposit/deposit-routing.module.ts | 4 +- src/app/shared/enums/label-translate.enum.ts | 1 + .../guards/deposit-detail-guard.service.ts | 92 +++++++++++++++++++ .../deposit-detail-tab-guard.service.ts | 0 .../deposit-role-guard-detail.service.ts | 48 ---------- .../guards/deposit-role-guard-edit.service.ts | 33 ------- ...ational-unit-compute-is-manager.service.ts | 53 ----------- .../organizational-unit-role-guard.service.ts | 52 ----------- src/assets/i18n/de.json | 3 +- src/assets/i18n/en.json | 3 +- src/assets/i18n/fr.json | 3 +- 12 files changed, 104 insertions(+), 191 deletions(-) create mode 100644 src/app/shared/guards/deposit-detail-guard.service.ts delete mode 100644 src/app/shared/guards/deposit-detail-tab-guard.service.ts delete mode 100644 src/app/shared/guards/deposit-role-guard-detail.service.ts delete mode 100644 src/app/shared/guards/deposit-role-guard-edit.service.ts delete mode 100644 src/app/shared/guards/organizational-unit-compute-is-manager.service.ts delete mode 100644 src/app/shared/guards/organizational-unit-role-guard.service.ts diff --git a/src/app/features/deposit/components/routables/deposit-detail/deposit-detail.routable.ts b/src/app/features/deposit/components/routables/deposit-detail/deposit-detail.routable.ts index e2673d23a..b843c5868 100644 --- a/src/app/features/deposit/components/routables/deposit-detail/deposit-detail.routable.ts +++ b/src/app/features/deposit/components/routables/deposit-detail/deposit-detail.routable.ts @@ -134,7 +134,8 @@ export class DepositDetailRoutable extends AbstractRoutable implements OnInit, O this.getSubResourceWithParentId(this._resId); this._store.dispatch(new DepositDocumentFileAction.GetAll(this._resId)); this._store.dispatch(new DepositAction.LoadResource(false)); - if (!this.isEdit) { + const currentDepositInState = MemoizedUtil.currentSnapshot(this._store, DepositState); + if (!this.isEdit && currentDepositInState?.resId !== this._resId) { this._store.dispatch(new DepositAction.GetById(this._resId)); } } diff --git a/src/app/features/deposit/deposit-routing.module.ts b/src/app/features/deposit/deposit-routing.module.ts index f029462c3..7a507ad0f 100644 --- a/src/app/features/deposit/deposit-routing.module.ts +++ b/src/app/features/deposit/deposit-routing.module.ts @@ -7,16 +7,17 @@ import { DepositListTabEnum, } from "@app/features/deposit/components/routables/deposit-list/deposit-list.routable"; import {DepositState} from "@app/features/deposit/stores/deposit.state"; +import {Enums} from "@enums"; import {LabelTranslateEnum} from "@shared/enums/label-translate.enum"; import { AppRoutesEnum, DepositRoutesEnum, } from "@shared/enums/routes.enum"; +import {DepositDetailGuardService} from "@shared/guards/deposit-detail-guard.service"; import { SOLIDIFY_CONSTANTS, SolidifyRoutes, } from "solidify-frontend"; -import {Enums} from "@enums"; const separator: string = SOLIDIFY_CONSTANTS.URL_SEPARATOR; @@ -40,6 +41,7 @@ const routes: SolidifyRoutes = [ data: { breadcrumbMemoizedSelector: DepositState.currentTitle, }, + canActivate: [DepositDetailGuardService], children: [ { path: DepositRoutesEnum.edit, diff --git a/src/app/shared/enums/label-translate.enum.ts b/src/app/shared/enums/label-translate.enum.ts index 749890c8d..e50b4b044 100644 --- a/src/app/shared/enums/label-translate.enum.ts +++ b/src/app/shared/enums/label-translate.enum.ts @@ -520,6 +520,7 @@ export class LabelTranslateEnum { static featureDisabled: string = MARK_AS_TRANSLATABLE("general.notification.featureDisabled"); static depositSubmitted: string = MARK_AS_TRANSLATABLE("general.notification.depositSubmitted"); static unableToSubmitDeposit: string = MARK_AS_TRANSLATABLE("general.notification.unableToSubmitDeposit"); + static youHaveNoRightToAccessRequestedResource: string = MARK_AS_TRANSLATABLE("general.notification.youHaveNoRightToAccessRequestedResource"); static dataTableAllElementSearchedSelected: string = MARK_AS_TRANSLATABLE("general.dataTable.allElementSearchedSelected"); static dataTableCleanAllFilter: string = MARK_AS_TRANSLATABLE("general.dataTable.cleanAllFilter"); diff --git a/src/app/shared/guards/deposit-detail-guard.service.ts b/src/app/shared/guards/deposit-detail-guard.service.ts new file mode 100644 index 000000000..a09f63215 --- /dev/null +++ b/src/app/shared/guards/deposit-detail-guard.service.ts @@ -0,0 +1,92 @@ +import {Injectable} from "@angular/core"; +import { + ActivatedRouteSnapshot, + CanActivate, + Router, +} from "@angular/router"; +import {DepositAction} from "@app/features/deposit/stores/deposit.action"; +import {DepositState} from "@app/features/deposit/stores/deposit.state"; +import {AppState} from "@app/stores/app.state"; +import {Navigate} from "@ngxs/router-plugin"; +import { + Actions, + ofActionCompleted, + Store, +} from "@ngxs/store"; +import {LabelTranslateEnum} from "@shared/enums/label-translate.enum"; +import { + AppRoutesEnum, + RoutesEnum, +} from "@shared/enums/routes.enum"; +import {TourRouteIdEnum} from "@shared/enums/tour-route-id.enum"; +import { + Observable, + of, +} from "rxjs"; +import {map} from "rxjs/operators"; +import { + ApiService, + isFalse, + isTrue, + MemoizedUtil, + NotificationService, + StoreUtil, +} from "solidify-frontend"; + +@Injectable({ + providedIn: "root", +}) +export class DepositDetailGuardService implements CanActivate { + constructor(public router: Router, + public apiService: ApiService, + private readonly _notificationService: NotificationService, + private readonly _store: Store, + protected actions$: Actions) { + } + + canActivate(route: ActivatedRouteSnapshot): Observable<boolean> { + const depositId: string = route.params[AppRoutesEnum.paramIdWithoutPrefixParam]; + const isInTourMode = MemoizedUtil.selectSnapshot(this._store, AppState, state => state.isInTourMode); + const isDepositIdForTour = depositId === TourRouteIdEnum.tourDepositId; + if (isDepositIdForTour || isInTourMode) { + const isAuthorizedToDisplayTour = isDepositIdForTour && isInTourMode; + if (!isAuthorizedToDisplayTour) { + this._store.dispatch(new Navigate([RoutesEnum.deposit])); + } + return of(isAuthorizedToDisplayTour); + } + + return StoreUtil.dispatchSequentialActionAndWaitForSubActionsCompletion(this._store, [ + { + action: new DepositAction.GetById(depositId), + subActionCompletions: [ + this.actions$.pipe(ofActionCompleted(DepositAction.GetByIdSuccess)), + this.actions$.pipe(ofActionCompleted(DepositAction.GetByIdFail)), + ], + }, + ]).pipe( + map(result => { + if (isFalse(result)) { + return false; + } + const deposit = MemoizedUtil.currentSnapshot(this._store, DepositState); + return deposit?.resId === depositId; + }), + map(result => { + if (isTrue(result)) { + return true; + } + + let redirectRoute: string[]; + if (route.url.length > 0 && route.url[0].path === AppRoutesEnum.depositToValidate) { + redirectRoute = [RoutesEnum.depositToValidate]; + } else { + redirectRoute = [RoutesEnum.deposit]; + } + this._store.dispatch(new Navigate(redirectRoute)); + this._notificationService.showError(LabelTranslateEnum.youHaveNoRightToAccessRequestedResource); + return false; + }), + ); + } +} diff --git a/src/app/shared/guards/deposit-detail-tab-guard.service.ts b/src/app/shared/guards/deposit-detail-tab-guard.service.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/app/shared/guards/deposit-role-guard-detail.service.ts b/src/app/shared/guards/deposit-role-guard-detail.service.ts deleted file mode 100644 index 2b92d6993..000000000 --- a/src/app/shared/guards/deposit-role-guard-detail.service.ts +++ /dev/null @@ -1,48 +0,0 @@ -import {Injectable} from "@angular/core"; -import { - ActivatedRouteSnapshot, - CanActivate, - Router, -} from "@angular/router"; -import {AppState} from "@app/stores/app.state"; -import {Navigate} from "@ngxs/router-plugin"; -import {Store} from "@ngxs/store"; -import { - AppRoutesEnum, - RoutesEnum, -} from "@shared/enums/routes.enum"; -import {TourRouteIdEnum} from "@shared/enums/tour-route-id.enum"; -import {SecurityService} from "@shared/services/security.service"; -import { - Observable, - of, -} from "rxjs"; -import { - ApiService, - MemoizedUtil, -} from "solidify-frontend"; - -@Injectable({ - providedIn: "root", -}) -export class DepositRoleGuardDetailService implements CanActivate { - constructor(public router: Router, - public store: Store, - public apiService: ApiService, - private readonly _securityService: SecurityService) { - } - - canActivate(route: ActivatedRouteSnapshot): Observable<boolean> { - const depositId: string = route.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - const isInTourMode = MemoizedUtil.selectSnapshot(this.store, AppState, state => state.isInTourMode); - const isDepositIdForTour = depositId === TourRouteIdEnum.tourDepositId; - if (isDepositIdForTour || isInTourMode) { - const isAuthorizedToDisplayTour = isDepositIdForTour && isInTourMode; - if (!isAuthorizedToDisplayTour) { - this.store.dispatch(new Navigate([RoutesEnum.deposit])); - } - return of(isAuthorizedToDisplayTour); - } - return this._securityService.canSeeDetailDepositById(depositId); - } -} diff --git a/src/app/shared/guards/deposit-role-guard-edit.service.ts b/src/app/shared/guards/deposit-role-guard-edit.service.ts deleted file mode 100644 index 5a30d75b2..000000000 --- a/src/app/shared/guards/deposit-role-guard-edit.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {Injectable} from "@angular/core"; -import { - ActivatedRouteSnapshot, - CanActivate, - Router, -} from "@angular/router"; -import {Store} from "@ngxs/store"; -import {AppRoutesEnum} from "@shared/enums/routes.enum"; -import {SecurityService} from "@shared/services/security.service"; -import {Observable} from "rxjs"; -import { - ApiService, - isNullOrUndefined, -} from "solidify-frontend"; - -@Injectable({ - providedIn: "root", -}) -export class DepositRoleGuardEditService implements CanActivate { - constructor(public router: Router, - public store: Store, - public apiService: ApiService, - private readonly _securityService: SecurityService) { - } - - canActivate(route: ActivatedRouteSnapshot): Observable<boolean> { - let depositId: string = route.parent.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - if (isNullOrUndefined(depositId)) { - depositId = route.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - } - return this._securityService.canEditDepositById(depositId); - } -} diff --git a/src/app/shared/guards/organizational-unit-compute-is-manager.service.ts b/src/app/shared/guards/organizational-unit-compute-is-manager.service.ts deleted file mode 100644 index 6688d96e9..000000000 --- a/src/app/shared/guards/organizational-unit-compute-is-manager.service.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {Injectable} from "@angular/core"; -import { - ActivatedRouteSnapshot, - CanActivate, - Router, -} from "@angular/router"; -import {PreservationSpaceOrganizationalUnitAction} from "@app/features/preservation-space/organizational-unit/stores/preservation-space-organizational-unit.action"; -import {AppState} from "@app/stores/app.state"; -import {Navigate} from "@ngxs/router-plugin"; -import { - Actions, - Store, -} from "@ngxs/store"; -import { - AppRoutesEnum, - RoutesEnum, -} from "@shared/enums/routes.enum"; -import {TourRouteIdEnum} from "@shared/enums/tour-route-id.enum"; -import {SecurityService} from "@shared/services/security.service"; -import { - ApiService, - MemoizedUtil, - NotificationService, -} from "solidify-frontend"; - -@Injectable({ - providedIn: "root", -}) -export class OrganizationalUnitComputeIsManagerGuardService implements CanActivate { - constructor(public router: Router, - public store: Store, - public apiService: ApiService, - private readonly _securityService: SecurityService, - private readonly _notificationService: NotificationService, - private readonly _actions$: Actions) { - } - - canActivate(route: ActivatedRouteSnapshot): boolean { - const orgUnitId = route.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - const isInTourMode = MemoizedUtil.selectSnapshot(this.store, AppState, state => state.isInTourMode); - const isOrgUnitIdForTour = orgUnitId === TourRouteIdEnum.tourOrgUnitId; - if (isOrgUnitIdForTour || isInTourMode) { - const isAuthorizedToDisplayTour = isOrgUnitIdForTour && isInTourMode; - if (!isAuthorizedToDisplayTour) { - this.store.dispatch(new Navigate([RoutesEnum.preservationSpaceOrganizationalUnit])); - } - return isAuthorizedToDisplayTour; - } - const authorized = this._securityService.isManagerOfOrgUnit(orgUnitId); - this.store.dispatch(new PreservationSpaceOrganizationalUnitAction.SaveCurrentUserIsManager(authorized)); - return true; - } -} diff --git a/src/app/shared/guards/organizational-unit-role-guard.service.ts b/src/app/shared/guards/organizational-unit-role-guard.service.ts deleted file mode 100644 index b9452f16c..000000000 --- a/src/app/shared/guards/organizational-unit-role-guard.service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {Injectable} from "@angular/core"; -import { - ActivatedRouteSnapshot, - CanActivate, - Router, -} from "@angular/router"; -import {Store} from "@ngxs/store"; -import {AppRoutesEnum} from "@shared/enums/routes.enum"; -import {AouData} from "@shared/models/aou-route.model"; -import {SecurityService} from "@shared/services/security.service"; -import { - ApiService, - isNullOrUndefined, - MARK_AS_TRANSLATABLE, - NotificationService, -} from "solidify-frontend"; - -@Injectable({ - providedIn: "root", -}) -export class OrganizationalUnitRoleGuardService implements CanActivate { - constructor(public router: Router, - public store: Store, - public apiService: ApiService, - private readonly _securityService: SecurityService, - private readonly _notificationService: NotificationService) { - } - - canActivate(route: ActivatedRouteSnapshot): boolean { - const data = route.data as AouData; - const orgUnitPermissionNeed = isNullOrUndefined(data) ? [] : data.orgUnitPermissionNeed; - let orgUnitId = route.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - if (isNullOrUndefined(orgUnitId)) { - orgUnitId = route.parent.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam]; - } - if (isNullOrUndefined(orgUnitId)) { - console.warn("Unable to extract orgUnitId from url"); - return false; - } - if (orgUnitPermissionNeed.length === 0) { - return true; - } - if (this._securityService.isRootOrAdmin()) { - return true; - } - const authorized = orgUnitPermissionNeed.indexOf(this._securityService.getRoleEnumInOrgUnit(orgUnitId)) !== -1; - if (authorized === false) { - this._notificationService.showWarning(MARK_AS_TRANSLATABLE("organizationalUnit.security.notification.noRightForThisAction")); - } - return authorized; - } -} diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 6772173ac..42410d324 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -940,7 +940,8 @@ "objectUpdated": "Objekt aktualisiert", "resourceResumed": "Ressource wieder aufgenommen", "unableResumedResource": "Die Ressource konnte nicht wieder aufgenommen werden", - "unableToSubmitDeposit": "general.notification.unableToSubmitDeposit" + "unableToSubmitDeposit": "general.notification.unableToSubmitDeposit", + "youHaveNoRightToAccessRequestedResource": "general.notification.youHaveNoRightToAccessRequestedResource" }, "status": { "cleaning": "general.status.cleaning", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index eb3d4f876..b0b664cd3 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -940,7 +940,8 @@ "objectUpdated": "Object updated", "resourceResumed": "Resource resumed", "unableResumedResource": "Unable to resume", - "unableToSubmitDeposit": "Unable to submit deposit" + "unableToSubmitDeposit": "Unable to submit deposit", + "youHaveNoRightToAccessRequestedResource": "You do not have the right to access the requested resource" }, "status": { "cleaning": "Cleaning", diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index f5f3d6f82..793ef4a5d 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -940,7 +940,8 @@ "objectUpdated": "Objet mis à jour", "resourceResumed": "Relancement de la ressource", "unableResumedResource": "Impossible de relancer la ressource", - "unableToSubmitDeposit": "Impossible de soumettre le dépôt" + "unableToSubmitDeposit": "Impossible de soumettre le dépôt", + "youHaveNoRightToAccessRequestedResource": "Vous n'avez pas le droit d'accèder à la resource demandé" }, "status": { "cleaning": "Nettoyage", -- GitLab