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