red-ui/apps/red-ui/src/app/services/user.service.ts
2022-07-25 15:40:54 +03:00

148 lines
4.8 KiB
TypeScript

import { inject, Inject, Injectable } from '@angular/core';
import { KeycloakService } from 'keycloak-angular';
import jwt_decode from 'jwt-decode';
import { ICreateUserRequest, IMyProfileUpdateRequest, IProfileUpdateRequest, IResetPasswordRequest, IUser, User } from '@red/domain';
import { BASE_HREF } from '../tokens';
import { BehaviorSubject, firstValueFrom, Observable } from 'rxjs';
import { CacheApiService, EntitiesService, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
import { tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class UserService extends EntitiesService<IUser, User> {
readonly currentUser$: Observable<User>;
protected readonly _defaultModelPath = 'user';
protected readonly _entityClass = User;
readonly #currentUser$ = new BehaviorSubject<User>(null);
constructor(
@Inject(BASE_HREF) private readonly _baseHref: string,
private readonly _keycloakService: KeycloakService,
private readonly _cacheApiService: CacheApiService,
) {
super();
this.currentUser$ = this.#currentUser$.asObservable();
}
get currentUser(): User {
return this.#currentUser$.value;
}
get managerUsers(): User[] {
return this.all.filter(user => user.isManager);
}
get eligibleUsers(): User[] {
return this.all.filter(user => user.isUser || user.isManager);
}
async initialize(): Promise<void> {
console.log('[Redaction] Initializing users for: ', this.currentUser);
if (!this.currentUser) {
return;
}
if (this.currentUser.isUserAdmin || this.currentUser.isUser || this.currentUser.isAdmin) {
await firstValueFrom(this.loadAll());
}
}
logout() {
this._cacheApiService.wipeCaches().then();
this._keycloakService.logout().then();
}
loadAll() {
const all$ = this.currentUser.isUserAdmin ? this.getUsers() : this.getUsers(true);
return all$.pipe(
mapEach(user => new User(user, user.roles, user.userId)),
tap(users => this.setEntities(users)),
);
}
async loadCurrentUser(): Promise<User> {
const token = await this._keycloakService.getToken();
const decoded = jwt_decode(token);
const userId = (<{ sub: string }>decoded).sub;
const roles = this._keycloakService.getUserRoles(true).filter(role => role.startsWith('RED_'));
let profile;
try {
profile = await this._keycloakService.loadUserProfile(true);
} catch (e) {
await this._keycloakService.logout();
console.log(e);
}
const user = new User(profile, roles, userId);
this.replace(user);
this.#currentUser$.next(this.find(userId));
return user;
}
getNameForId(userId: string): string | undefined {
return this.find(userId)?.name;
}
hasAnyRole(requiredRoles: string[], user = this.currentUser): boolean {
if (requiredRoles?.length > 0) {
for (const role of requiredRoles) {
if (user.hasRole(role)) {
return true;
}
}
return false;
}
return true;
}
getUsers(onlyRed = false, refreshCache = true): Observable<IUser[]> {
const url = onlyRed ? `${this._defaultModelPath}/red` : this._defaultModelPath;
return super.getAll(url, [{ key: 'refreshCache', value: refreshCache }]);
}
@Validate()
updateProfile(@RequiredParam() body: IProfileUpdateRequest, @RequiredParam() userId: string) {
return this._post<unknown>(body, `${this._defaultModelPath}/profile/${userId}`);
}
@Validate()
updateMyProfile(@RequiredParam() body: IMyProfileUpdateRequest) {
return this._post<unknown>(body, `${this._defaultModelPath}/my-profile`);
}
@Validate()
resetPassword(@RequiredParam() body: IResetPasswordRequest, @RequiredParam() userId: string) {
return this._post<unknown>(body, `${this._defaultModelPath}/${userId}/reset-password`);
}
@Validate()
create(@RequiredParam() body: ICreateUserRequest) {
return this._post(body);
}
delete(userIds: List) {
const queryParams = userIds.map<QueryParam>(userId => ({ key: 'userId', value: userId }));
return super.delete(userIds, this._defaultModelPath, queryParams);
}
find(id: string): User | undefined {
if (id?.toLowerCase() === 'system') {
return new User({ username: 'System' }, [], 'system');
}
if (!id) {
return undefined;
}
return super.find(id) || new User({ username: 'Deleted User' }, [], 'deleted');
}
}
export function getCurrentUser() {
return inject(UserService).currentUser;
}