test update some permissions
This commit is contained in:
parent
ac64335d5b
commit
25ce65e425
15 changed files with 582 additions and 493 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { NgModule, inject } from '@angular/core';
|
||||
import {inject, NgModule} from '@angular/core';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivateFn,
|
||||
|
|
@ -7,8 +7,9 @@ import {
|
|||
RouterStateSnapshot,
|
||||
Routes,
|
||||
} from '@angular/router';
|
||||
import { UserService } from './core/services/user.service';
|
||||
import { map } from 'rxjs';
|
||||
import {UserService} from './core/services/user.service';
|
||||
import {map} from 'rxjs';
|
||||
import {UserPermissions} from "./core/auth/userPermissions";
|
||||
|
||||
const authGuard: CanActivateFn = (
|
||||
route: ActivatedRouteSnapshot,
|
||||
|
|
@ -31,13 +32,38 @@ const authGuard: CanActivateFn = (
|
|||
);
|
||||
};
|
||||
|
||||
const loginGuard: CanActivateFn = (
|
||||
const permissionsGuard: (...requiredPermissions: UserPermissions[]) => CanActivateFn = (...requiredPermissions) => (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
) => {
|
||||
const userService: UserService = inject(UserService);
|
||||
const router: Router = inject(Router);
|
||||
|
||||
const user = userService.getCurrentUser()
|
||||
if (user == null)
|
||||
return router.createUrlTree(['/login'], {
|
||||
queryParams: {
|
||||
redirectUrl: state.url,
|
||||
},
|
||||
});
|
||||
|
||||
if (requiredPermissions.every(permission => user.permissions.includes(permission))) {
|
||||
return true
|
||||
}
|
||||
|
||||
return router.createUrlTree(['/unauthorized'], {
|
||||
queryParams: {
|
||||
redirectUrl: state.url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const loginGuard: CanActivateFn = (
|
||||
route: ActivatedRouteSnapshot
|
||||
) => {
|
||||
const userService: UserService = inject(UserService);
|
||||
const router: Router = inject(Router);
|
||||
|
||||
return userService.isAuthenticated.pipe(
|
||||
map((isAuth) => {
|
||||
if (!isAuth) {
|
||||
|
|
@ -83,15 +109,15 @@ const routes: Routes = [
|
|||
import('./features/recipes/recipes.component').then(
|
||||
(m) => m.RecipesComponent
|
||||
),
|
||||
canActivate: [authGuard],
|
||||
canActivate: [authGuard, permissionsGuard(UserPermissions.THAI_PERMISSION, UserPermissions.SUPER_ADMIN)],
|
||||
},
|
||||
{
|
||||
path: 'recipe/:productCode',
|
||||
loadComponent: () =>
|
||||
import(
|
||||
'./features/recipes/recipe-details/recipe-details.component'
|
||||
).then((m) => m.RecipeDetailsComponent),
|
||||
canActivate: [authGuard],
|
||||
).then((m) => m.RecipeDetailsComponent),
|
||||
canActivate: [authGuard, permissionsGuard(UserPermissions.THAI_PERMISSION, UserPermissions.SUPER_ADMIN)],
|
||||
},
|
||||
// {
|
||||
// path: 'log',
|
||||
|
|
@ -100,9 +126,17 @@ const routes: Routes = [
|
|||
// (m) => m.ChangelogComponent
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
path: 'unauthorized',
|
||||
loadComponent: () => import('./core/auth/unauthorized.component').then((m) => m.UnauthorizedComponent)
|
||||
},
|
||||
{
|
||||
path: 'notfound',
|
||||
loadComponent: () => import('./core/notfound.component').then((m) => m.NotfoundComponent)
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: 'recipes',
|
||||
redirectTo: 'notfound',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -112,4 +146,5 @@ const routes: Routes = [
|
|||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
export class AppRoutingModule {
|
||||
}
|
||||
|
|
|
|||
31
client/src/app/core/auth/unauthorized.component.ts
Normal file
31
client/src/app/core/auth/unauthorized.component.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-unauthorized',
|
||||
standalone: true,
|
||||
template: `
|
||||
<div class="flex pt-[100px] justify-center h-screen">
|
||||
<h1 class="text-2xl font-bold text-center text-red-500">
|
||||
Unauthorized, You 🫵🏻 not have permissions
|
||||
</h1>
|
||||
</div>`
|
||||
})
|
||||
export class UnauthorizedComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute
|
||||
) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
const redirectUrl = this.activatedRoute.snapshot.queryParams['redirectUrl'];
|
||||
if (redirectUrl) {
|
||||
this.router.navigate([redirectUrl]).catch(() => {
|
||||
// redirect to login page
|
||||
void this.router.navigate(['/login']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
client/src/app/core/auth/userPermissions.ts
Normal file
12
client/src/app/core/auth/userPermissions.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
export enum UserPermissions {
|
||||
NO_PERMISSION,
|
||||
THAI_PERMISSION = 1 << 0,
|
||||
MALAY_PERMISSION = 1 << 1,
|
||||
AUS_PERMISSION = 1 << 2,
|
||||
SUPER_ADMIN = 1 << 3
|
||||
}
|
||||
|
||||
export function getPermissions(perms: number) : UserPermissions[] {
|
||||
return Object.values(UserPermissions)
|
||||
.filter(permission => typeof permission === 'number' && (perms & permission) !== 0) as UserPermissions[];
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UserService } from '../services/user.service';
|
||||
import {getPermissions} from "../auth/userPermissions";
|
||||
|
||||
@Component({
|
||||
selector: 'app-callback',
|
||||
|
|
@ -19,18 +19,19 @@ export class CallbackComponent implements OnInit {
|
|||
this.route.queryParams.subscribe((params) => {
|
||||
console.log(params);
|
||||
|
||||
if (params['email'] && params['name'] && params['picture']) {
|
||||
if (params['email'] && params['name'] && params['picture'] && params['permissions']) {
|
||||
this.userService.setAuth({
|
||||
email: params['email'],
|
||||
name: params['name'],
|
||||
picture: params['picture'],
|
||||
permissions: getPermissions(params['permissions'])
|
||||
});
|
||||
}
|
||||
|
||||
if (params['redirect_to']) {
|
||||
this.router.navigate([params['redirect_to']]);
|
||||
void this.router.navigate([params['redirect_to']]);
|
||||
} else {
|
||||
this.router.navigate(['/']);
|
||||
void this.router.navigate(['/']);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
import {UserPermissions} from "../auth/userPermissions";
|
||||
|
||||
export interface User {
|
||||
email: string;
|
||||
name: string;
|
||||
picture: string;
|
||||
permissions: UserPermissions[];
|
||||
}
|
||||
|
|
|
|||
10
client/src/app/core/notfound.component.ts
Normal file
10
client/src/app/core/notfound.component.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-notfound',
|
||||
standalone: true,
|
||||
template: `<h1>Not Found!!!</h1>`
|
||||
})
|
||||
export class NotfoundComponent {
|
||||
|
||||
}
|
||||
|
|
@ -2,10 +2,9 @@ import { Injectable } from '@angular/core';
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
Observable,
|
||||
distinctUntilChanged,
|
||||
map,
|
||||
tap,
|
||||
|
||||
} from 'rxjs';
|
||||
import { User } from '../models/user.model';
|
||||
import { Router } from '@angular/router';
|
||||
|
|
@ -31,6 +30,10 @@ export class UserService {
|
|||
}
|
||||
}
|
||||
|
||||
getCurrentUser(): User | null {
|
||||
return this.currentUserSubject.value
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.purgeAuth();
|
||||
// post to api /revoke with cookie
|
||||
|
|
@ -43,21 +46,6 @@ export class UserService {
|
|||
});
|
||||
}
|
||||
|
||||
getCurrentUser(): Observable<{ user: User }> {
|
||||
return this.http
|
||||
.get<{ user: User }>(environment.api + '/auth/user', {
|
||||
withCredentials: true,
|
||||
})
|
||||
.pipe(
|
||||
tap({
|
||||
next: ({ user }) => {
|
||||
this.setAuth(user);
|
||||
},
|
||||
error: () => this.purgeAuth(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setAuth(user: User): void {
|
||||
window.localStorage.setItem('user', JSON.stringify(user));
|
||||
void this.currentUserSubject.next(user);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { CommonModule, DatePipe } from '@angular/common';
|
|||
import { Component, EventEmitter, OnInit } from '@angular/core';
|
||||
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { Observable, first } from 'rxjs';
|
||||
import {Observable, first, map} from 'rxjs';
|
||||
import { RecipeService } from 'src/app/core/services/recipe.service';
|
||||
import { ConfirmModal } from 'src/app/shared/modal/confirm/confirm-modal.component';
|
||||
import { animate, style, transition, trigger } from '@angular/animations';
|
||||
|
|
@ -11,8 +11,7 @@ import {
|
|||
RecipeDetail,
|
||||
RecipeDetailMat,
|
||||
} from 'src/app/core/models/recipe.model';
|
||||
import { Action, ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
|
||||
import { isEqual } from 'lodash';
|
||||
import { ActionRecord } from 'src/app/shared/actionRecord/actionRecord';
|
||||
import { UserService } from 'src/app/core/services/user.service';
|
||||
|
||||
@Component({
|
||||
|
|
@ -119,10 +118,9 @@ export class RecipeDetailsComponent implements OnInit {
|
|||
|
||||
// get username
|
||||
let username:string = ""
|
||||
this._userService.getCurrentUser().subscribe((user) => {
|
||||
username = user.user.name;
|
||||
|
||||
|
||||
this._userService.currentUser.pipe(map((user) => {
|
||||
if (user)
|
||||
username = user.name;
|
||||
|
||||
let to_send = {
|
||||
edit_by: username,
|
||||
|
|
@ -152,8 +150,8 @@ export class RecipeDetailsComponent implements OnInit {
|
|||
}
|
||||
);
|
||||
console.log('Sending changes');
|
||||
this._router.navigate(['/recipes']);
|
||||
})
|
||||
void this._router.navigate(['/recipes']);
|
||||
}))
|
||||
|
||||
|
||||
|
||||
|
|
@ -198,6 +196,6 @@ export class RecipeDetailsComponent implements OnInit {
|
|||
onRecipeListFormChange(repl: unknown[]) {
|
||||
console.log('Recipe List Form Changed', repl);
|
||||
this.repl = repl as never[];
|
||||
this.isValueChanged ||= repl != undefined ? true : false;
|
||||
this.isValueChanged ||= repl != undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue