diff options
Diffstat (limited to 'client/src/app/core')
-rw-r--r-- | client/src/app/core/auth/auth-user.model.ts | 11 | ||||
-rw-r--r-- | client/src/app/core/auth/auth.service.ts | 8 | ||||
-rw-r--r-- | client/src/app/core/auth/index.ts | 2 | ||||
-rw-r--r-- | client/src/app/core/core.module.ts | 6 | ||||
-rw-r--r-- | client/src/app/core/menu/menu-admin.component.html | 10 | ||||
-rw-r--r-- | client/src/app/core/menu/menu-admin.component.ts | 27 | ||||
-rw-r--r-- | client/src/app/core/menu/menu.component.html | 4 | ||||
-rw-r--r-- | client/src/app/core/menu/menu.component.ts | 46 | ||||
-rw-r--r-- | client/src/app/core/routing/index.ts | 2 | ||||
-rw-r--r-- | client/src/app/core/routing/login-guard.service.ts (renamed from client/src/app/core/auth/login-guard.service.ts) | 2 | ||||
-rw-r--r-- | client/src/app/core/routing/user-right-guard.service.ts | 35 |
11 files changed, 129 insertions, 24 deletions
diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index 81bff99a0..085b763ec 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | // Do not use the barrel (dependency loop) | 1 | // Do not use the barrel (dependency loop) |
2 | import { UserRole } from '../../../../../shared/models/users/user-role.type' | 2 | import { hasUserRight, UserRole } from '../../../../../shared/models/users/user-role' |
3 | import { User, UserConstructorHash } from '../../shared/users/user.model' | 3 | import { User, UserConstructorHash } from '../../shared/users/user.model' |
4 | import { UserRight } from '../../../../../shared/models/users/user-right.enum' | ||
4 | 5 | ||
5 | export type TokenOptions = { | 6 | export type TokenOptions = { |
6 | accessToken: string | 7 | accessToken: string |
@@ -81,7 +82,7 @@ export class AuthUser extends User { | |||
81 | id: parseInt(localStorage.getItem(this.KEYS.ID), 10), | 82 | id: parseInt(localStorage.getItem(this.KEYS.ID), 10), |
82 | username: localStorage.getItem(this.KEYS.USERNAME), | 83 | username: localStorage.getItem(this.KEYS.USERNAME), |
83 | email: localStorage.getItem(this.KEYS.EMAIL), | 84 | email: localStorage.getItem(this.KEYS.EMAIL), |
84 | role: localStorage.getItem(this.KEYS.ROLE) as UserRole, | 85 | role: parseInt(localStorage.getItem(this.KEYS.ROLE), 10) as UserRole, |
85 | displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true' | 86 | displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true' |
86 | }, | 87 | }, |
87 | Tokens.load() | 88 | Tokens.load() |
@@ -122,11 +123,15 @@ export class AuthUser extends User { | |||
122 | this.tokens.refreshToken = refreshToken | 123 | this.tokens.refreshToken = refreshToken |
123 | } | 124 | } |
124 | 125 | ||
126 | hasRight(right: UserRight) { | ||
127 | return hasUserRight(this.role, right) | ||
128 | } | ||
129 | |||
125 | save () { | 130 | save () { |
126 | localStorage.setItem(AuthUser.KEYS.ID, this.id.toString()) | 131 | localStorage.setItem(AuthUser.KEYS.ID, this.id.toString()) |
127 | localStorage.setItem(AuthUser.KEYS.USERNAME, this.username) | 132 | localStorage.setItem(AuthUser.KEYS.USERNAME, this.username) |
128 | localStorage.setItem(AuthUser.KEYS.EMAIL, this.email) | 133 | localStorage.setItem(AuthUser.KEYS.EMAIL, this.email) |
129 | localStorage.setItem(AuthUser.KEYS.ROLE, this.role) | 134 | localStorage.setItem(AuthUser.KEYS.ROLE, this.role.toString()) |
130 | localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)) | 135 | localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW)) |
131 | this.tokens.save() | 136 | this.tokens.save() |
132 | } | 137 | } |
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index 9ac9ba7bb..df6e5135b 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts | |||
@@ -21,7 +21,7 @@ import { | |||
21 | // Do not use the barrel (dependency loop) | 21 | // Do not use the barrel (dependency loop) |
22 | import { RestExtractor } from '../../shared/rest' | 22 | import { RestExtractor } from '../../shared/rest' |
23 | import { UserLogin } from '../../../../../shared/models/users/user-login.model' | 23 | import { UserLogin } from '../../../../../shared/models/users/user-login.model' |
24 | import { User, UserConstructorHash } from '../../shared/users/user.model' | 24 | import { UserConstructorHash } from '../../shared/users/user.model' |
25 | 25 | ||
26 | interface UserLoginWithUsername extends UserLogin { | 26 | interface UserLoginWithUsername extends UserLogin { |
27 | access_token: string | 27 | access_token: string |
@@ -126,12 +126,6 @@ export class AuthService { | |||
126 | return this.user | 126 | return this.user |
127 | } | 127 | } |
128 | 128 | ||
129 | isAdmin () { | ||
130 | if (this.user === null) return false | ||
131 | |||
132 | return this.user.isAdmin() | ||
133 | } | ||
134 | |||
135 | isLoggedIn () { | 129 | isLoggedIn () { |
136 | return !!this.getAccessToken() | 130 | return !!this.getAccessToken() |
137 | } | 131 | } |
diff --git a/client/src/app/core/auth/index.ts b/client/src/app/core/auth/index.ts index a81f2c002..bc7bfec0e 100644 --- a/client/src/app/core/auth/index.ts +++ b/client/src/app/core/auth/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './auth-status.model' | 1 | export * from './auth-status.model' |
2 | export * from './auth-user.model' | 2 | export * from './auth-user.model' |
3 | export * from './auth.service' | 3 | export * from './auth.service' |
4 | export * from './login-guard.service' | 4 | export * from '../routing/login-guard.service' |
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 163a6bbde..90e2cb190 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts | |||
@@ -7,7 +7,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations' | |||
7 | import { SimpleNotificationsModule } from 'angular2-notifications' | 7 | import { SimpleNotificationsModule } from 'angular2-notifications' |
8 | import { ModalModule } from 'ngx-bootstrap/modal' | 8 | import { ModalModule } from 'ngx-bootstrap/modal' |
9 | 9 | ||
10 | import { AuthService, LoginGuard } from './auth' | 10 | import { AuthService } from './auth' |
11 | import { LoginGuard, UserRightGuard } from './routing' | ||
11 | import { ServerService } from './server' | 12 | import { ServerService } from './server' |
12 | import { ConfirmComponent, ConfirmService } from './confirm' | 13 | import { ConfirmComponent, ConfirmService } from './confirm' |
13 | import { MenuComponent, MenuAdminComponent } from './menu' | 14 | import { MenuComponent, MenuAdminComponent } from './menu' |
@@ -42,7 +43,8 @@ import { throwIfAlreadyLoaded } from './module-import-guard' | |||
42 | AuthService, | 43 | AuthService, |
43 | ConfirmService, | 44 | ConfirmService, |
44 | ServerService, | 45 | ServerService, |
45 | LoginGuard | 46 | LoginGuard, |
47 | UserRightGuard | ||
46 | ] | 48 | ] |
47 | }) | 49 | }) |
48 | export class CoreModule { | 50 | export class CoreModule { |
diff --git a/client/src/app/core/menu/menu-admin.component.html b/client/src/app/core/menu/menu-admin.component.html index edacdee6d..c2b2958b4 100644 --- a/client/src/app/core/menu/menu-admin.component.html +++ b/client/src/app/core/menu/menu-admin.component.html | |||
@@ -1,26 +1,26 @@ | |||
1 | <menu> | 1 | <menu> |
2 | <div class="panel-block"> | 2 | <div class="panel-block"> |
3 | <a routerLink="/admin/users/list" routerLinkActive="active"> | 3 | <a *ngIf="hasUsersRight()" routerLink="/admin/users" routerLinkActive="active"> |
4 | <span class="hidden-xs glyphicon glyphicon-user"></span> | 4 | <span class="hidden-xs glyphicon glyphicon-user"></span> |
5 | List users | 5 | List users |
6 | </a> | 6 | </a> |
7 | 7 | ||
8 | <a routerLink="/admin/friends/list" routerLinkActive="active"> | 8 | <a *ngIf="hasFriendsRight()" routerLink="/admin/friends" routerLinkActive="active"> |
9 | <span class="hidden-xs glyphicon glyphicon-cloud"></span> | 9 | <span class="hidden-xs glyphicon glyphicon-cloud"></span> |
10 | List friends | 10 | List friends |
11 | </a> | 11 | </a> |
12 | 12 | ||
13 | <a routerLink="/admin/requests/stats" routerLinkActive="active"> | 13 | <a *ngIf="hasRequestsStatRight()" routerLink="/admin/requests/stats" routerLinkActive="active"> |
14 | <span class="hidden-xs glyphicon glyphicon-stats"></span> | 14 | <span class="hidden-xs glyphicon glyphicon-stats"></span> |
15 | Request stats | 15 | Request stats |
16 | </a> | 16 | </a> |
17 | 17 | ||
18 | <a routerLink="/admin/video-abuses/list" routerLinkActive="active"> | 18 | <a *ngIf="hasVideoAbusesRight()" routerLink="/admin/video-abuses" routerLinkActive="active"> |
19 | <span class="hidden-xs glyphicon glyphicon-alert"></span> | 19 | <span class="hidden-xs glyphicon glyphicon-alert"></span> |
20 | Video abuses | 20 | Video abuses |
21 | </a> | 21 | </a> |
22 | 22 | ||
23 | <a routerLink="/admin/video-blacklist/list" routerLinkActive="active"> | 23 | <a *ngIf="hasVideoBlacklistRight()" routerLink="/admin/video-blacklist" routerLinkActive="active"> |
24 | <span class="hidden-xs glyphicon glyphicon-eye-close"></span> | 24 | <span class="hidden-xs glyphicon glyphicon-eye-close"></span> |
25 | Video blacklist | 25 | Video blacklist |
26 | </a> | 26 | </a> |
diff --git a/client/src/app/core/menu/menu-admin.component.ts b/client/src/app/core/menu/menu-admin.component.ts index f6cc6554c..074f1dbaf 100644 --- a/client/src/app/core/menu/menu-admin.component.ts +++ b/client/src/app/core/menu/menu-admin.component.ts | |||
@@ -1,8 +1,33 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | import { AuthService } from '../auth/auth.service' | ||
4 | import { UserRight } from '../../../../../shared' | ||
5 | |||
3 | @Component({ | 6 | @Component({ |
4 | selector: 'my-menu-admin', | 7 | selector: 'my-menu-admin', |
5 | templateUrl: './menu-admin.component.html', | 8 | templateUrl: './menu-admin.component.html', |
6 | styleUrls: [ './menu.component.scss' ] | 9 | styleUrls: [ './menu.component.scss' ] |
7 | }) | 10 | }) |
8 | export class MenuAdminComponent { } | 11 | export class MenuAdminComponent { |
12 | constructor (private auth: AuthService) {} | ||
13 | |||
14 | hasUsersRight () { | ||
15 | return this.auth.getUser().hasRight(UserRight.MANAGE_USERS) | ||
16 | } | ||
17 | |||
18 | hasFriendsRight () { | ||
19 | return this.auth.getUser().hasRight(UserRight.MANAGE_PODS) | ||
20 | } | ||
21 | |||
22 | hasRequestsStatRight () { | ||
23 | return this.auth.getUser().hasRight(UserRight.MANAGE_REQUEST_SCHEDULERS) | ||
24 | } | ||
25 | |||
26 | hasVideoAbusesRight () { | ||
27 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES) | ||
28 | } | ||
29 | |||
30 | hasVideoBlacklistRight () { | ||
31 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) | ||
32 | } | ||
33 | } | ||
diff --git a/client/src/app/core/menu/menu.component.html b/client/src/app/core/menu/menu.component.html index ca341a0fd..2d8aace54 100644 --- a/client/src/app/core/menu/menu.component.html +++ b/client/src/app/core/menu/menu.component.html | |||
@@ -39,10 +39,10 @@ | |||
39 | </a> | 39 | </a> |
40 | </div> | 40 | </div> |
41 | 41 | ||
42 | <div *ngIf="isUserAdmin()" class="panel-block"> | 42 | <div *ngIf="userHasAdminAccess" class="panel-block"> |
43 | <div class="block-title">Other</div> | 43 | <div class="block-title">Other</div> |
44 | 44 | ||
45 | <a routerLink="/admin" routerLinkActive="active"> | 45 | <a [routerLink]="getFirstAdminRouteAvailable()" routerLinkActive="active"> |
46 | <span class="hidden-xs glyphicon glyphicon-cog"></span> | 46 | <span class="hidden-xs glyphicon glyphicon-cog"></span> |
47 | Administration | 47 | Administration |
48 | </a> | 48 | </a> |
diff --git a/client/src/app/core/menu/menu.component.ts b/client/src/app/core/menu/menu.component.ts index 8f15d8838..c66a5eccc 100644 --- a/client/src/app/core/menu/menu.component.ts +++ b/client/src/app/core/menu/menu.component.ts | |||
@@ -3,6 +3,7 @@ import { Router } from '@angular/router' | |||
3 | 3 | ||
4 | import { AuthService, AuthStatus } from '../auth' | 4 | import { AuthService, AuthStatus } from '../auth' |
5 | import { ServerService } from '../server' | 5 | import { ServerService } from '../server' |
6 | import { UserRight } from '../../../../../shared/models/users/user-right.enum' | ||
6 | 7 | ||
7 | @Component({ | 8 | @Component({ |
8 | selector: 'my-menu', | 9 | selector: 'my-menu', |
@@ -11,6 +12,15 @@ import { ServerService } from '../server' | |||
11 | }) | 12 | }) |
12 | export class MenuComponent implements OnInit { | 13 | export class MenuComponent implements OnInit { |
13 | isLoggedIn: boolean | 14 | isLoggedIn: boolean |
15 | userHasAdminAccess = false | ||
16 | |||
17 | private routesPerRight = { | ||
18 | [UserRight.MANAGE_USERS]: '/admin/users', | ||
19 | [UserRight.MANAGE_PODS]: '/admin/friends', | ||
20 | [UserRight.MANAGE_REQUEST_SCHEDULERS]: '/admin/requests/stats', | ||
21 | [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses', | ||
22 | [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist' | ||
23 | } | ||
14 | 24 | ||
15 | constructor ( | 25 | constructor ( |
16 | private authService: AuthService, | 26 | private authService: AuthService, |
@@ -20,14 +30,17 @@ export class MenuComponent implements OnInit { | |||
20 | 30 | ||
21 | ngOnInit () { | 31 | ngOnInit () { |
22 | this.isLoggedIn = this.authService.isLoggedIn() | 32 | this.isLoggedIn = this.authService.isLoggedIn() |
33 | this.computeIsUserHasAdminAccess() | ||
23 | 34 | ||
24 | this.authService.loginChangedSource.subscribe( | 35 | this.authService.loginChangedSource.subscribe( |
25 | status => { | 36 | status => { |
26 | if (status === AuthStatus.LoggedIn) { | 37 | if (status === AuthStatus.LoggedIn) { |
27 | this.isLoggedIn = true | 38 | this.isLoggedIn = true |
39 | this.computeIsUserHasAdminAccess() | ||
28 | console.log('Logged in.') | 40 | console.log('Logged in.') |
29 | } else if (status === AuthStatus.LoggedOut) { | 41 | } else if (status === AuthStatus.LoggedOut) { |
30 | this.isLoggedIn = false | 42 | this.isLoggedIn = false |
43 | this.computeIsUserHasAdminAccess() | ||
31 | console.log('Logged out.') | 44 | console.log('Logged out.') |
32 | } else { | 45 | } else { |
33 | console.error('Unknown auth status: ' + status) | 46 | console.error('Unknown auth status: ' + status) |
@@ -40,8 +53,31 @@ export class MenuComponent implements OnInit { | |||
40 | return this.serverService.getConfig().signup.allowed | 53 | return this.serverService.getConfig().signup.allowed |
41 | } | 54 | } |
42 | 55 | ||
43 | isUserAdmin () { | 56 | getFirstAdminRightAvailable () { |
44 | return this.authService.isAdmin() | 57 | const user = this.authService.getUser() |
58 | if (!user) return undefined | ||
59 | |||
60 | const adminRights = [ | ||
61 | UserRight.MANAGE_USERS, | ||
62 | UserRight.MANAGE_PODS, | ||
63 | UserRight.MANAGE_REQUEST_SCHEDULERS, | ||
64 | UserRight.MANAGE_VIDEO_ABUSES, | ||
65 | UserRight.MANAGE_VIDEO_BLACKLIST | ||
66 | ] | ||
67 | |||
68 | for (const adminRight of adminRights) { | ||
69 | if (user.hasRight(adminRight)) { | ||
70 | return adminRight | ||
71 | } | ||
72 | } | ||
73 | |||
74 | return undefined | ||
75 | } | ||
76 | |||
77 | getFirstAdminRouteAvailable () { | ||
78 | const right = this.getFirstAdminRightAvailable() | ||
79 | |||
80 | return this.routesPerRight[right] | ||
45 | } | 81 | } |
46 | 82 | ||
47 | logout () { | 83 | logout () { |
@@ -49,4 +85,10 @@ export class MenuComponent implements OnInit { | |||
49 | // Redirect to home page | 85 | // Redirect to home page |
50 | this.router.navigate(['/videos/list']) | 86 | this.router.navigate(['/videos/list']) |
51 | } | 87 | } |
88 | |||
89 | private computeIsUserHasAdminAccess () { | ||
90 | const right = this.getFirstAdminRightAvailable() | ||
91 | |||
92 | this.userHasAdminAccess = right !== undefined | ||
93 | } | ||
52 | } | 94 | } |
diff --git a/client/src/app/core/routing/index.ts b/client/src/app/core/routing/index.ts index 17f3ee833..d1b982834 100644 --- a/client/src/app/core/routing/index.ts +++ b/client/src/app/core/routing/index.ts | |||
@@ -1 +1,3 @@ | |||
1 | export * from './login-guard.service' | ||
2 | export * from './user-right-guard.service' | ||
1 | export * from './preload-selected-modules-list' | 3 | export * from './preload-selected-modules-list' |
diff --git a/client/src/app/core/auth/login-guard.service.ts b/client/src/app/core/routing/login-guard.service.ts index c09e8fe97..18bc41ca6 100644 --- a/client/src/app/core/auth/login-guard.service.ts +++ b/client/src/app/core/routing/login-guard.service.ts | |||
@@ -7,7 +7,7 @@ import { | |||
7 | Router | 7 | Router |
8 | } from '@angular/router' | 8 | } from '@angular/router' |
9 | 9 | ||
10 | import { AuthService } from './auth.service' | 10 | import { AuthService } from '../auth/auth.service' |
11 | 11 | ||
12 | @Injectable() | 12 | @Injectable() |
13 | export class LoginGuard implements CanActivate, CanActivateChild { | 13 | export class LoginGuard implements CanActivate, CanActivateChild { |
diff --git a/client/src/app/core/routing/user-right-guard.service.ts b/client/src/app/core/routing/user-right-guard.service.ts new file mode 100644 index 000000000..65d029977 --- /dev/null +++ b/client/src/app/core/routing/user-right-guard.service.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { | ||
3 | ActivatedRouteSnapshot, | ||
4 | CanActivateChild, | ||
5 | RouterStateSnapshot, | ||
6 | CanActivate, | ||
7 | Router | ||
8 | } from '@angular/router' | ||
9 | |||
10 | import { AuthService } from '../auth' | ||
11 | |||
12 | @Injectable() | ||
13 | export class UserRightGuard implements CanActivate, CanActivateChild { | ||
14 | |||
15 | constructor ( | ||
16 | private router: Router, | ||
17 | private auth: AuthService | ||
18 | ) {} | ||
19 | |||
20 | canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { | ||
21 | const user = this.auth.getUser() | ||
22 | if (user) { | ||
23 | const neededUserRight = route.data.userRight | ||
24 | |||
25 | if (user.hasRight(neededUserRight)) return true | ||
26 | } | ||
27 | |||
28 | this.router.navigate([ '/login' ]) | ||
29 | return false | ||
30 | } | ||
31 | |||
32 | canActivateChild (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { | ||
33 | return this.canActivate(route, state) | ||
34 | } | ||
35 | } | ||