From 0d576b72685265db3a890fa3409225c8c92ec26c Mon Sep 17 00:00:00 2001 From: Florian Hartwich Date: Thu, 8 Jun 2017 16:58:28 +0200 Subject: [PATCH] Adjust menu for different permissions --- static/src/app/app.component.html | 28 ++++++++-- static/src/app/app.module.ts | 6 ++- static/src/app/app.routing.ts | 12 ++--- static/src/app/login/login.component.ts | 4 +- static/src/app/login/login.guard.ts | 49 ++++++++++++++++-- .../services/login-service/login-service.ts | 5 ++ static/src/assets/opt-logo-klein.png | Bin 7787 -> 7847 bytes 7 files changed, 86 insertions(+), 18 deletions(-) diff --git a/static/src/app/app.component.html b/static/src/app/app.component.html index 5003f64..a0e53b5 100644 --- a/static/src/app/app.component.html +++ b/static/src/app/app.component.html @@ -21,23 +21,41 @@
  • Armeeübersicht
  • -
  • +
  • Teilnehmer
  • -
  • +
  • Squads
  • -
  • +
  • Auszeichnungen
  • -
  • +
  • Ränge
  • + diff --git a/static/src/app/app.module.ts b/static/src/app/app.module.ts index df9ba0f..f163179 100644 --- a/static/src/app/app.module.ts +++ b/static/src/app/app.module.ts @@ -22,7 +22,7 @@ import {RankStore} from "./services/stores/rank.store"; import {RankService} from "./services/rank-service/rank.service"; import {DecorationItemComponent} from "./decorations/decoration-list/decoration-item.component"; import {AppConfig} from "./app.config"; -import {LoginGuard} from "./login/login.guard"; +import {LoginGuardAdmin, LoginGuardHL, LoginGuardSQL} from "./login/login.guard"; import {AwardingService} from "./services/awarding-service/awarding.service"; import {HttpClient} from "./services/http-client"; import {ArmyService} from "./services/army-service/army.service"; @@ -33,7 +33,9 @@ import { ClipboardModule } from 'ngx-clipboard'; providers: [ HttpClient, LoginService, - LoginGuard, + LoginGuardSQL, + LoginGuardHL, + LoginGuardAdmin, ArmyService, UserService, UserStore, diff --git a/static/src/app/app.routing.ts b/static/src/app/app.routing.ts index a516844..f6ea582 100644 --- a/static/src/app/app.routing.ts +++ b/static/src/app/app.routing.ts @@ -1,7 +1,7 @@ import {Routes, RouterModule} from '@angular/router'; import {LoginComponent} from './login/index'; import {NotFoundComponent} from './not-found/not-found.component'; -import {LoginGuard} from './login/login.guard'; +import {LoginGuardHL} from './login/login.guard'; import {usersRoutes, usersRoutingComponents} from "./users/users.routing"; import {squadsRoutes, squadsRoutingComponents} from "./squads/squads.routing"; import {decorationsRoutes, decorationsRoutingComponents} from "./decorations/decoration.routing"; @@ -15,10 +15,10 @@ export const appRoutes: Routes = [ {path: '', redirectTo: '/cc-overview', pathMatch: 'full'}, {path: 'login', component: LoginComponent}, - {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuard]}, - {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuard]}, - {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuard]}, - {path: 'cc-ranks', children: ranksRoutes, canActivate: [LoginGuard]}, + {path: 'cc-users', children: usersRoutes, canActivate: [LoginGuardHL]}, + {path: 'cc-squads', children: squadsRoutes, canActivate: [LoginGuardHL]}, + {path: 'cc-decorations', children: decorationsRoutes, canActivate: [LoginGuardHL]}, + {path: 'cc-ranks', children: ranksRoutes, canActivate: [LoginGuardHL]}, /** Redirect Konfigurationen **/ {path: '404', component: NotFoundComponent}, @@ -30,4 +30,4 @@ export const appRouting = RouterModule.forRoot(appRoutes); export const routingComponents = [LoginComponent, ...armyRoutingComponents , NotFoundComponent, ...usersRoutingComponents, ...squadsRoutingComponents, ...decorationsRoutingComponents, ...ranksRoutingComponents]; -export const routingProviders = [LoginGuard]; +export const routingProviders = [LoginGuardHL]; diff --git a/static/src/app/login/login.component.ts b/static/src/app/login/login.component.ts index 18fbe45..7365886 100644 --- a/static/src/app/login/login.component.ts +++ b/static/src/app/login/login.component.ts @@ -25,8 +25,8 @@ export class LoginComponent implements OnInit { ngOnInit() { // reset login status this.loginService.logout(); - // redirect to user overview on success - this.returnUrl = '/cc-users' + // redirect on success + this.returnUrl = '/cc-overview' } login(username: string, password: string) { diff --git a/static/src/app/login/login.guard.ts b/static/src/app/login/login.guard.ts index 187ca03..1083734 100644 --- a/static/src/app/login/login.guard.ts +++ b/static/src/app/login/login.guard.ts @@ -2,14 +2,57 @@ import { Injectable } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() -export class LoginGuard implements CanActivate { +export class LoginGuardSQL implements CanActivate { constructor(private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if (localStorage.getItem('currentUser')) { - // logged in so return true - return true; + let currentUser = JSON.parse(localStorage.getItem('currentUser')); + if (currentUser.permission === 1) { + // logged and correct permission so return true + return true; + } + } + + // not logged in so redirect to login page with the return url + this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); + return false; + } +} + +@Injectable() +export class LoginGuardHL implements CanActivate { + + constructor(private router: Router) { } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + if (localStorage.getItem('currentUser')) { + let currentUser = JSON.parse(localStorage.getItem('currentUser')); + if (currentUser.permission >= 2) { + // logged and correct permission so return true + return true; + } + } + + // not logged in so redirect to login page with the return url + this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); + return false; + } +} + +@Injectable() +export class LoginGuardAdmin implements CanActivate { + + constructor(private router: Router) { } + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + if (localStorage.getItem('currentUser')) { + let currentUser = JSON.parse(localStorage.getItem('currentUser')); + if (currentUser.permission === 4) { + // logged and correct permission so return true + return true; + } } // not logged in so redirect to login page with the return url diff --git a/static/src/app/services/login-service/login-service.ts b/static/src/app/services/login-service/login-service.ts index e7884e1..e7264de 100644 --- a/static/src/app/services/login-service/login-service.ts +++ b/static/src/app/services/login-service/login-service.ts @@ -33,4 +33,9 @@ export class LoginService { return !this.authEnabled || localStorage.getItem('currentUser') != null; } + hasPermission(level : number) { + let currentUser = JSON.parse(localStorage.getItem('currentUser')); + return this.isLoggedIn() && currentUser.permission >= level; + } + } diff --git a/static/src/assets/opt-logo-klein.png b/static/src/assets/opt-logo-klein.png index 1bd3696630b589f81032d287fa5ae701d224089f..41f597d2641149b0b43a1504fe73572b1f6e6568 100644 GIT binary patch literal 7847 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

    jAjLta*X2$0Ky0X>KY^xpDrazK0YH@1 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�=Zx;h;8rVkmC?-WJR4dBT0&#&_yKD7VFv12ms@Oae^3dc-4 zRa<)^Q;PW0qocI36$h&l=iPeO69ol@Uje8mglGVSBuVPqwQE=SoR7IUb`vgQFviHv zoja*cr_*fxbjz%|x+CifN9V)|Jk`pIf{KIH%Gfc(ot>S&c0ps>xb3s;ZH(r}F_{b*`Zf_9=t z6!3>PKB<54#r5;=x#!MxcDtEoWDNag|NdPIR;^n5@SAVGaxEdD>7h^rf*|zWfBzHf z;^PzOx!1D7=PtX3DWz?c(!;VWw~QY@K729A`%jwu^D6M^r=JQdR;-w%s{VHX#>uiQ zYPBLb%3;bCS8b(~b8Xu6VaeRNx7|8*>U2g3A=~wmr@#NYiskKH<1@Jesb@jmzS3dE|)8P|NcEU z0VFyuEZPuB*6LAxLb z(EtPhp+_Ehc*ueU3!76@Qxh0t-w{F@&dD~)%gcE|5C%T~{1ae zRaHU=@k)}^Wipw1&*ui0$p4X-f&KgU3tq36XfzsCk|e6pXkv^;qe2Mj898!f|8C7SQ}V@E^~TH@h(Lm!bdw002ovPDHLk FV1o8&D((OP literal 7787 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