import { AuthorizationCallServiceBase } from "./authorization-call.base"; import { ChangePasswordRequest, User, UserRegistration, UserRole } from "@models/user"; import { catchError, map, Observable, of, throwError } from "rxjs"; import { HttpClient, HttpErrorResponse } from "@angular/common/http"; import { inject } from "@angular/core"; import { environment } from "@environment"; import { extractHttpErrorMessage, toHttpError } from "@services/shared/http-error.util"; export class AuthorizationCallService extends AuthorizationCallServiceBase { private readonly http = inject(HttpClient); override login(username: string, password: string): Observable { return this.http .post(`${environment.apiUrl}/auth/login`, { username, password }) .pipe( map((raw) => this.userFromApi(raw, username)), catchError((error: unknown) => { if (error instanceof HttpErrorResponse && error.status === 404) { return throwError(() => new Error('User not found')); } if (error instanceof HttpErrorResponse && error.status === 401) { return throwError(() => new Error('Invalid password')); } return throwError(() => error); }) ); } override currentUser(): Observable { return this.http .get(`${environment.apiUrl}/auth/me`) .pipe( map((raw) => this.userFromApi(raw)), catchError((error: unknown) => toHttpError(error, { 401: 'Unauthenticated' })) ); } override register(userRegistration: UserRegistration): Observable { return this.http.post(`${environment.apiUrl}/auth/register`, userRegistration) .pipe( catchError((error: unknown) => toHttpError(error, { 400: 'Unable to register user.' })) ); } override changePassword(request: ChangePasswordRequest): Observable { return this.http .post(`${environment.apiUrl}/auth/change-password`, request, { responseType: 'text' }) .pipe( map(() => undefined), catchError((error: unknown) => { if (error instanceof HttpErrorResponse) { const message = extractHttpErrorMessage(error) ?? (error.status === 400 ? 'Missing required fields.' : null) ?? (error.status === 401 ? 'Current password is invalid' : null) ?? (error.status === 404 ? 'User not found' : null) ?? 'Unable to change password.'; return throwError(() => new Error(message)); } return throwError(() => error); }) ); } private userFromApi(raw: unknown, fallbackUsername?: string): User { const payload = (raw ?? {}) as Record; const userSource = (payload["user"] as Record | undefined) ?? (payload["profile"] as Record | undefined) ?? payload; return { username: String(userSource["username"] ?? fallbackUsername ?? ''), email: typeof userSource["email"] === "string" ? String(userSource["email"]) : null, role: this.normalizeRole(userSource["role"]) } satisfies User; } private normalizeRole(value: unknown): UserRole { return String(value ?? '').toUpperCase() === 'ADMIN' ? 'ADMIN' : 'USER'; } override logout(): Observable { return this.http .post(`${environment.apiUrl}/auth/logout`, {}) .pipe( map(() => undefined), catchError(() => of(undefined)) ); } }