Add role control
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { AuthService, UserInfo } from '../../shared/services/auth.service';
|
||||
import { ApiConfigService } from './api-config.service';
|
||||
import { PermissionAction } from '../models/permission.model';
|
||||
|
||||
const SUPER_ADMIN = 'super_admin';
|
||||
|
||||
/**
|
||||
* Reads the current user's effective permissions (delivered on the UserInfo payload)
|
||||
* and answers can(module, action). super_admin always passes. This is a UX mirror —
|
||||
* the backend remains the authoritative permission boundary.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PermissionService {
|
||||
constructor(
|
||||
private auth: AuthService,
|
||||
private http: HttpClient,
|
||||
private apiConfig: ApiConfigService
|
||||
) { }
|
||||
|
||||
/** True if the current user may perform <action> on <module>. */
|
||||
can(module: string, action: PermissionAction): boolean {
|
||||
const user = this.auth.getCurrentUser();
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
if (user.roles?.includes(SUPER_ADMIN)) {
|
||||
return true;
|
||||
}
|
||||
const moduleActions = user.permissions?.[this.normalizeKey(module)];
|
||||
return !!moduleActions && !!moduleActions[action];
|
||||
}
|
||||
|
||||
canRead(module: string): boolean { return this.can(module, 'read'); }
|
||||
canWrite(module: string): boolean { return this.can(module, 'write'); }
|
||||
canDelete(module: string): boolean { return this.can(module, 'delete'); }
|
||||
canApprove(module: string): boolean { return this.can(module, 'approve'); }
|
||||
|
||||
/**
|
||||
* Re-fetches the current user (with fresh permissions) from GET /api/auth/me.
|
||||
* Call after an admin edits the matrix so the UI reflects the change without
|
||||
* a re-login. Returns the updated user, or null on failure.
|
||||
*/
|
||||
refresh(): Observable<UserInfo | null> {
|
||||
return this.http.get<UserInfo>(`${this.apiConfig.authUrl}/me`).pipe(
|
||||
tap(user => this.auth.setCurrentUser(user)),
|
||||
map(user => user),
|
||||
catchError(() => of(null))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Module names are stored PascalCase in code but arrive as camelCase dictionary
|
||||
* keys (server's DictionaryKeyPolicy). Lowercase the first character to match.
|
||||
*/
|
||||
private normalizeKey(module: string): string {
|
||||
if (!module) {
|
||||
return module;
|
||||
}
|
||||
return module.charAt(0).toLowerCase() + module.slice(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user