diff --git a/projects/admin/src/app/app.module.ts b/projects/admin/src/app/app.module.ts index 24f3b4aff..89480a2ff 100644 --- a/projects/admin/src/app/app.module.ts +++ b/projects/admin/src/app/app.module.ts @@ -101,6 +101,7 @@ import { RemoteAutocompleteInputTypeComponent } from './record/editor/remote-aut import { ItemAvailabilityComponent } from './record/item-availability/item-availability.component'; import { AppConfigService } from './service/app-config.service'; import { TranslateLoader } from './translate/loader/translate-loader'; +import { ErrorPageComponent } from './error/error-page/error-page.component'; @NgModule({ declarations: [ @@ -170,7 +171,8 @@ import { TranslateLoader } from './translate/loader/translate-loader'; FrontpageBoardComponent, RelatedResourceComponent, ResourceComponent, - ItemRequestComponent + ItemRequestComponent, + ErrorPageComponent ], imports: [ AppRoutingModule, @@ -256,7 +258,8 @@ import { TranslateLoader } from './translate/loader/translate-loader'; BudgetsBriefViewComponent, BudgetDetailViewComponent, OrganisationDetailViewComponent, - ItemRequestComponent + ItemRequestComponent, + ErrorPageComponent ], bootstrap: [AppComponent] }) diff --git a/projects/admin/src/app/error/error-page/error-page.component.ts b/projects/admin/src/app/error/error-page/error-page.component.ts new file mode 100644 index 000000000..456224754 --- /dev/null +++ b/projects/admin/src/app/error/error-page/error-page.component.ts @@ -0,0 +1,70 @@ +import { ActivatedRoute } from '@angular/router'; +import { Component, OnInit } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { marker } from '@biesbjerg/ngx-translate-extract-marker'; + +export function _(str) { + return marker(str); +} + +@Component({ + selector: 'admin-error-page', + template: ` +
+

{{ statusCode }} - {{ messages[statusCode].title }}

+
{{ text }}
+
+

For any information please contact system administrator

+
+ ` +}) + +export class ErrorPageComponent implements OnInit { + + /** the status code to display. By default 404 : Page not found */ + statusCode = 404; + /** All messages ablt to be managed by this component. Availables for each error are : + * - title : the error title + * - description : A human readable description of this error as Array. Each array + * element will be a separate line. + * - level: the boostrap alert look-and-feel level to use for the error. 'danger' by default. + */ + messages = { + 401: { + title: _('Unauthorized'), + description: [_('Access denied due to invalid credentials.')], + level: 'warning' + }, + 403: { + title: _('Forbidden access'), + description: [_('You don\'t have permission to access this page.')], + level: 'warning' + }, + 404: { + title: _('Page not found'), + description: [_('Woops. Looks like this page doesn\'t exists')] + }, + 418: { + title: _('I\'m a teapot'), + description: [ + _('The requested entity body is short and stout'), + _('Tip me over and pour me out') + ], + level: 'success' + }, + 500: { + title: _('Internal server error'), + desctiption: [_('Oops, Something went wrong !')] + } + }; + + constructor(private _route: ActivatedRoute) { } + + ngOnInit() { + this._route.params.pipe( + map(params => params.status_code || 404), // check for status_code parameter from ActivatedRoute + map(code => /^\d+$/.test(code) ? parseInt(code, 10) : 404), // try to parse status code to integer + map(code => code in this.messages ? code : 404) // check if http code definition exists + ).subscribe(code => this.statusCode = code ); + } +} diff --git a/projects/admin/src/app/guard/can-update.guard.ts b/projects/admin/src/app/guard/can-update.guard.ts new file mode 100644 index 000000000..8d09bfa5e --- /dev/null +++ b/projects/admin/src/app/guard/can-update.guard.ts @@ -0,0 +1,46 @@ +import { + CanActivate, + ActivatedRouteSnapshot, + Router, + RouterStateSnapshot, + UrlTree, + NavigationError +} from '@angular/router'; +import { Injectable } from '@angular/core'; +import {Observable, throwError} from 'rxjs'; +import { RecordPermission, RecordPermissionService } from '../service/record-permission.service'; +import { ToastrService } from 'ngx-toastr'; +import { TranslateService } from '@ngx-translate/core'; + + +@Injectable({ + providedIn: 'root' +}) +export class CanUpdateGuard implements CanActivate { + + constructor( + private _permissionService: RecordPermissionService, + private _toastrService: ToastrService, + private _translateService: TranslateService, + private _router: Router) { + } + + /** + * Check if the current logged user can update a resource + * @param next - ActivatedRouteSnapshot + * @param state - RouterStateSnapshot + */ + canActivate(next: ActivatedRouteSnapshot, + state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { + + this._permissionService.getPermission(next.params.type, next.params.pid).subscribe( + (permission: RecordPermission) => { + if (!permission.update.can) { + this._router.navigate(['/errors/403']); + } + } + ); + return true; + } + +} diff --git a/projects/admin/src/app/routes/acquisition-accounts-route.ts b/projects/admin/src/app/routes/acquisition-accounts-route.ts index 9818f6d89..9c8409ba5 100644 --- a/projects/admin/src/app/routes/acquisition-accounts-route.ts +++ b/projects/admin/src/app/routes/acquisition-accounts-route.ts @@ -14,8 +14,9 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, EditorComponent, extractIdOnRef } from '@rero/ng-core'; import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; +import { RouteInterface, EditorComponent, extractIdOnRef } from '@rero/ng-core'; import { of } from 'rxjs'; export class AcquisitionAccountsRoute extends BaseRoute implements RouteInterface { @@ -31,7 +32,7 @@ export class AcquisitionAccountsRoute extends BaseRoute implements RouteInterfac return { matcher: (url: any) => this.routeMatcher(url, this.name), children: [ - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/acquisition-order-lines-route.ts b/projects/admin/src/app/routes/acquisition-order-lines-route.ts index ec0b5e0c7..e9d277135 100644 --- a/projects/admin/src/app/routes/acquisition-order-lines-route.ts +++ b/projects/admin/src/app/routes/acquisition-order-lines-route.ts @@ -14,13 +14,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { DetailComponent, EditorComponent, extractIdOnRef, RecordService, RouteInterface} from '@rero/ng-core'; -import { BaseRoute } from './Base-route'; -import { FormlyFieldConfig } from '@ngx-formly/core'; -import { JSONSchema7 } from 'json-schema'; import { AcquisitionOrderLineDetailViewComponent } from '../record/detail-view/acquisition-order-line-detail-view/acquisition-order-line-detail-view.component'; +import { CanUpdateGuard } from '../guard/can-update.guard'; +import { BaseRoute } from './Base-route'; +import { DetailComponent, EditorComponent, extractIdOnRef, RecordService, RouteInterface} from '@rero/ng-core'; +import { FormlyFieldConfig } from '@ngx-formly/core'; +import { JSONSchema7 } from 'json-schema'; import { of } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -41,7 +42,7 @@ export class AcquisitionOrderLinesRoute extends BaseRoute implements RouteInterf matcher: (url: any) => this.routeMatcher(url, this.name), children: [ { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/acquisition-orders-route.ts b/projects/admin/src/app/routes/acquisition-orders-route.ts index f021ea99f..6195fdf38 100644 --- a/projects/admin/src/app/routes/acquisition-orders-route.ts +++ b/projects/admin/src/app/routes/acquisition-orders-route.ts @@ -14,13 +14,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { BaseRoute } from './Base-route'; -import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; -import { formatDate } from '@angular/common'; import { AcquisitionOrderBriefViewComponent } from '../record/brief-view/acquisition-order-brief-view.component'; import { AcquisitionOrderDetailViewComponent } from '../record/detail-view/acquisition-order-detail-view/acquisition-order-detail-view.component'; +import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; +import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; +import { formatDate } from '@angular/common'; export class AcquisitionOrdersRoute extends BaseRoute implements RouteInterface { @@ -40,7 +41,7 @@ export class AcquisitionOrdersRoute extends BaseRoute implements RouteInterface children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/budgets-route.ts b/projects/admin/src/app/routes/budgets-route.ts index e5039f266..d4b250337 100644 --- a/projects/admin/src/app/routes/budgets-route.ts +++ b/projects/admin/src/app/routes/budgets-route.ts @@ -14,10 +14,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; import { BaseRoute } from './Base-route'; import { BudgetsBriefViewComponent } from '../record/brief-view/budgets-brief-view.component'; import { BudgetDetailViewComponent } from '../record/detail-view/budget-detail-view/budget-detail-view.component'; +import { CanUpdateGuard } from '../guard/can-update.guard'; +import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; + export class BudgetsRoute extends BaseRoute implements RouteInterface { @@ -37,7 +39,7 @@ export class BudgetsRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/circulation-policies-route.ts b/projects/admin/src/app/routes/circulation-policies-route.ts index e5eaaf272..955f0c46b 100644 --- a/projects/admin/src/app/routes/circulation-policies-route.ts +++ b/projects/admin/src/app/routes/circulation-policies-route.ts @@ -15,10 +15,11 @@ * along with this program. If not, see . */ import { BaseRoute } from './Base-route'; -import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { CirculationPolicyComponent } from '../record/custom-editor/circulation-settings/circulation-policy/circulation-policy.component'; import { CircPoliciesBriefViewComponent } from '../record/brief-view/circ-policies-brief-view.component'; import { CircPolicyDetailViewComponent } from '../record/detail-view/circ-policy-detail-view/circ-policy-detail-view.component'; +import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core'; export class CirculationPoliciesRoute extends BaseRoute implements RouteInterface { @@ -38,7 +39,7 @@ export class CirculationPoliciesRoute extends BaseRoute implements RouteInterfac children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: CirculationPolicyComponent }, + { path: 'edit/:pid', component: CirculationPolicyComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: CirculationPolicyComponent } ], data: { diff --git a/projects/admin/src/app/routes/documents-route.ts b/projects/admin/src/app/routes/documents-route.ts index b2d862ab6..ca6cfd304 100644 --- a/projects/admin/src/app/routes/documents-route.ts +++ b/projects/admin/src/app/routes/documents-route.ts @@ -14,11 +14,13 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core'; -import { DocumentEditorComponent } from '../record/custom-editor/document-editor/document-editor.component'; + +import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { DocumentsBriefViewComponent } from '../record/brief-view/documents-brief-view/documents-brief-view.component'; import { DocumentDetailViewComponent } from '../record/detail-view/document-detail-view/document-detail-view.component'; -import { BaseRoute } from './Base-route'; +import { DocumentEditorComponent } from '../record/custom-editor/document-editor/document-editor.component'; +import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core'; export class DocumentsRoute extends BaseRoute implements RouteInterface { @@ -38,7 +40,7 @@ export class DocumentsRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: DocumentEditorComponent }, + { path: 'edit/:pid', component: DocumentEditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: DocumentEditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/item-types-route.ts b/projects/admin/src/app/routes/item-types-route.ts index 57ad70b7c..1aaf5717d 100644 --- a/projects/admin/src/app/routes/item-types-route.ts +++ b/projects/admin/src/app/routes/item-types-route.ts @@ -14,10 +14,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; +import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { ItemTypesBriefViewComponent } from '../record/brief-view/item-types-brief-view.component'; import { ItemTypeDetailViewComponent } from '../record/detail-view/item-type-detail-view.component'; -import { BaseRoute } from './Base-route'; +import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; + export class ItemTypesRoute extends BaseRoute implements RouteInterface { @@ -37,7 +39,7 @@ export class ItemTypesRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/libraries-route.ts b/projects/admin/src/app/routes/libraries-route.ts index 42e8075f4..ac47c005d 100644 --- a/projects/admin/src/app/routes/libraries-route.ts +++ b/projects/admin/src/app/routes/libraries-route.ts @@ -14,11 +14,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, RecordSearchComponent, DetailComponent } from '@rero/ng-core'; +import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; +import { DetailComponent, RecordSearchComponent, RouteInterface } from '@rero/ng-core'; import { LibraryComponent } from '../record/custom-editor/libraries/library.component'; import { LibrariesBriefViewComponent } from '../record/brief-view/libraries-brief-view/libraries-brief-view.component'; import { LibraryDetailViewComponent } from '../record/detail-view/library-detail-view/library-detail-view.component'; -import { BaseRoute } from './Base-route'; + + export class LibrariesRoute extends BaseRoute implements RouteInterface { @@ -38,7 +41,7 @@ export class LibrariesRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: LibraryComponent }, + { path: 'edit/:pid', component: LibraryComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: LibraryComponent } ], data: { diff --git a/projects/admin/src/app/routes/locations-route.ts b/projects/admin/src/app/routes/locations-route.ts index 6e63d6f40..10eb9750b 100644 --- a/projects/admin/src/app/routes/locations-route.ts +++ b/projects/admin/src/app/routes/locations-route.ts @@ -15,6 +15,7 @@ * along with this program. If not, see . */ import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core'; import { LocationDetailViewComponent } from '../record/detail-view/location-detail-view/location-detail-view.component'; @@ -32,10 +33,10 @@ export class LocationsRoute extends BaseRoute implements RouteInterface { */ getConfiguration() { return { - matcher: (url: any) => this.routeMatcher(url, 'locations'), + matcher: (url: any) => this.routeMatcher(url, this.name), children: [ { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/organisations-route.ts b/projects/admin/src/app/routes/organisations-route.ts index 6ead74882..50ac6b850 100644 --- a/projects/admin/src/app/routes/organisations-route.ts +++ b/projects/admin/src/app/routes/organisations-route.ts @@ -14,9 +14,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core'; import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { OrganisationDetailViewComponent } from '../record/detail-view/organisation-detail-view/organisation-detail-view.component'; +import { RouteInterface, DetailComponent, EditorComponent } from '@rero/ng-core'; export class OrganisationsRoute extends BaseRoute implements RouteInterface { @@ -32,7 +33,7 @@ export class OrganisationsRoute extends BaseRoute implements RouteInterface { matcher: (url: any) => this.routeMatcher(url, this.name), children: [ { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent } + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] } ], data: { linkPrefix: 'records', diff --git a/projects/admin/src/app/routes/patron-types-route.ts b/projects/admin/src/app/routes/patron-types-route.ts index debdd8ad2..ad0fd391a 100644 --- a/projects/admin/src/app/routes/patron-types-route.ts +++ b/projects/admin/src/app/routes/patron-types-route.ts @@ -15,9 +15,10 @@ * along with this program. If not, see . */ import { BaseRoute } from './Base-route'; -import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { PatronTypesBriefViewComponent } from '../record/brief-view/patron-types-brief-view.component'; import { PatronTypesDetailViewComponent } from '../record/detail-view/patron-types-detail-view.component'; +import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; export class PatronTypesRoute extends BaseRoute implements RouteInterface { @@ -37,7 +38,7 @@ export class PatronTypesRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/patrons-route.ts b/projects/admin/src/app/routes/patrons-route.ts index bdc8b0b97..0a9429275 100644 --- a/projects/admin/src/app/routes/patrons-route.ts +++ b/projects/admin/src/app/routes/patrons-route.ts @@ -14,10 +14,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; +import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { PatronsBriefViewComponent } from '../record/brief-view/patrons-brief-view.component'; import { PatronDetailViewComponent } from '../record/detail-view/patron-detail-view/patron-detail-view.component'; -import { BaseRoute } from './Base-route'; +import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; + export class PatronsRoute extends BaseRoute implements RouteInterface { @@ -37,7 +39,7 @@ export class PatronsRoute extends BaseRoute implements RouteInterface { children: [ { path: '', component: RecordSearchComponent }, { path: 'detail/:pid', component: DetailComponent }, - { path: 'edit/:pid', component: EditorComponent }, + { path: 'edit/:pid', component: EditorComponent, canActivate: [ CanUpdateGuard ] }, { path: 'new', component: EditorComponent } ], data: { diff --git a/projects/admin/src/app/routes/route.service.ts b/projects/admin/src/app/routes/route.service.ts index 35cbc0e98..471cdc1cc 100644 --- a/projects/admin/src/app/routes/route.service.ts +++ b/projects/admin/src/app/routes/route.service.ts @@ -33,6 +33,7 @@ import { AcquisitionOrderLinesRoute } from './acquisition-order-lines-route'; import { OrganisationsRoute } from './organisations-route'; import { AcquisitionAccountsRoute } from './acquisition-accounts-route'; import { BudgetsRoute } from './budgets-route'; +import { ErrorPageComponent } from '../error/error-page/error-page.component'; @Injectable({ providedIn: 'root' @@ -72,9 +73,13 @@ export class RouteService { .addRoute(new PersonsRoute(this._routeToolService)) .addRoute(new VendorsRoute(this._routeToolService)) ; - this._routeCollectionService.getRoutes().map((route: any) => { this._router.config.push(route); }); + + this._router.config.push(...[ + {path: 'errors/:status_code', component: ErrorPageComponent}, + {path: '**', component: ErrorPageComponent} + ]); } } diff --git a/projects/admin/src/app/routes/vendors-route.ts b/projects/admin/src/app/routes/vendors-route.ts index 3c841c6d8..3104b8ec6 100644 --- a/projects/admin/src/app/routes/vendors-route.ts +++ b/projects/admin/src/app/routes/vendors-route.ts @@ -15,6 +15,7 @@ * along with this program. If not, see . */ import { BaseRoute } from './Base-route'; +import { CanUpdateGuard } from '../guard/can-update.guard'; import { RouteInterface, RecordSearchComponent, DetailComponent, EditorComponent } from '@rero/ng-core'; import { VendorBriefViewComponent } from '../record/brief-view/vendor-brief-view.component'; import { VendorDetailViewComponent } from '../record/detail-view/vendor-detail-view/vendor-detail-view.component';