Moved folders #405
This commit is contained in:
16
web/src/app/services/auth/auth.service.spec.ts
Normal file
16
web/src/app/services/auth/auth.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(AuthService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
304
web/src/app/services/auth/auth.service.ts
Normal file
304
web/src/app/services/auth/auth.service.ts
Normal file
@@ -0,0 +1,304 @@
|
||||
import { HttpClient, HttpHeaders } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { JwtHelperService } from "@auth0/angular-jwt";
|
||||
import { BehaviorSubject, firstValueFrom, Observable, Subject, Subscription, throwError } from "rxjs";
|
||||
import { catchError } from "rxjs/operators";
|
||||
import { AdminUpdateUserDTO } from "src/app/models/auth/admin-update-user.dto";
|
||||
import { AuthRoles } from "src/app/models/auth/auth-roles.enum";
|
||||
import { AuthUserDTO } from "src/app/models/auth/auth-user.dto";
|
||||
import { EMailStringDTO } from "src/app/models/auth/email-string.dto";
|
||||
import { ResetPasswordDTO } from "src/app/models/auth/reset-password.dto";
|
||||
import { TokenDTO } from "src/app/models/auth/token.dto";
|
||||
import { UpdateUserDTO } from "src/app/models/auth/update-user.dto";
|
||||
import { AuthUserSelectCriterion } from "src/app/models/selection/auth-user/auth-user-select-criterion.dto";
|
||||
import { GetFilteredAuthUsersResultDTO } from "src/app/models/selection/auth-user/get-filtered-auth-users-result.dto";
|
||||
import { SettingsService } from "../settings/settings.service";
|
||||
import { SpinnerService } from "../spinner/spinner.service";
|
||||
import { DiscordAuthURL } from "../../models/auth/discord-auth-url.dto";
|
||||
import { OAuthDTO } from "../../models/auth/oauth.dto";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class AuthService {
|
||||
|
||||
isLoggedIn$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
constructor(
|
||||
private appsettings: SettingsService,
|
||||
private http: HttpClient,
|
||||
private router: Router,
|
||||
private jwtHelper: JwtHelperService,
|
||||
private spinnerService: SpinnerService
|
||||
) {
|
||||
}
|
||||
|
||||
/* data requests */
|
||||
getAllUsers(): Observable<Array<AuthUserDTO>> {
|
||||
return this.http.get<Array<AuthUserDTO>>(`${this.appsettings.getApiURL()}/api/auth/users`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getFilteredUsers(selectCriterions: AuthUserSelectCriterion): Observable<GetFilteredAuthUsersResultDTO> {
|
||||
return this.http.post<GetFilteredAuthUsersResultDTO>(`${this.appsettings.getApiURL()}/api/auth/users/get/filtered`, selectCriterions, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getUserByEMail(email: string): Observable<AuthUserDTO> {
|
||||
return this.http.get<AuthUserDTO>(`${this.appsettings.getApiURL()}/api/auth/users/get/${email}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
findUserByEMail(email: string): Observable<AuthUserDTO> {
|
||||
return this.http.get<AuthUserDTO>(`${this.appsettings.getApiURL()}/api/auth/users/find/${email}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/* auth requsts */
|
||||
register(user: AuthUserDTO): Observable<unknown> {
|
||||
return this.http.post<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/register`, user, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
confirmEMail(id: string): Observable<boolean> {
|
||||
return this.http.post<boolean>(`${this.appsettings.getApiURL()}/api/auth/register-by-id/${id}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
login(user: AuthUserDTO): Observable<TokenDTO> {
|
||||
return this.http.post<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/login`, user, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
verifyLogin(): Observable<boolean> {
|
||||
return this.http.get<boolean>(`${this.appsettings.getApiURL()}/api/auth/verify-login`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
forgotPassword(email: string): Observable<unknown> {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/forgot-password/${email}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getEMailFromforgotPasswordId(id: string): Observable<EMailStringDTO> {
|
||||
return this.http.post<EMailStringDTO>(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password/${id}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
resetPassword(resetPasswordDTO: ResetPasswordDTO): Observable<unknown> {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/reset-password`, resetPasswordDTO, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
updateUser(updateUserDTO: UpdateUserDTO): Observable<unknown> {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/update-user`, updateUserDTO, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
updateUserAsAdmin(updateUserDTO: AdminUpdateUserDTO): Observable<unknown> {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/update-user-as-admin`, updateUserDTO, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
refresh(token: TokenDTO): Observable<TokenDTO> {
|
||||
return this.http.post<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/refresh`, token, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
deleteUserByMail(mail: string) {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/delete-user-by-mail/${mail}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/* discord auth */
|
||||
getDiscordAuthURL() {
|
||||
return this.http.get<DiscordAuthURL>(`${this.appsettings.getApiURL()}/api/auth/discord/get-url`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
discordLogin(code: string, state: string): Observable<TokenDTO> {
|
||||
return this.http.get<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/login?code=${code}&state=${state}`, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// /api/auth/discord/register?code=
|
||||
discordRegister(oAuthDTO: OAuthDTO) {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/auth/discord/register`, oAuthDTO, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// discordGetUser(code: string, state: string) {
|
||||
// return this.http.get<AuthUserDTO>(`${this.appsettings.getApiURL()}/api/auth/discord/get-user?code=${code}&state=${state}`, {
|
||||
// headers: new HttpHeaders({
|
||||
// 'Content-Type': 'application/json'
|
||||
// })
|
||||
// });
|
||||
// }
|
||||
|
||||
/* utils */
|
||||
saveToken(token: TokenDTO): void {
|
||||
localStorage.setItem("jwt", token.token);
|
||||
localStorage.setItem("rjwt", token.refreshToken);
|
||||
if (this.router.url.startsWith("/auth")) {
|
||||
this.router.navigate(["/dashboard"]);
|
||||
}
|
||||
}
|
||||
|
||||
getToken(): TokenDTO {
|
||||
return {
|
||||
token: localStorage.getItem("jwt") ?? "",
|
||||
refreshToken: localStorage.getItem("rjwt") ?? ""
|
||||
};
|
||||
}
|
||||
|
||||
getDecodedToken(token: TokenDTO | undefined = undefined): { [key: string]: any } | null {
|
||||
if (token) {
|
||||
return this.jwtHelper.decodeToken(token.token);
|
||||
}
|
||||
|
||||
return this.jwtHelper.decodeToken(this.getToken().token);
|
||||
}
|
||||
|
||||
logout(): Subscription | null {
|
||||
const token = this.getToken();
|
||||
|
||||
if (token && token.token && token.refreshToken) {
|
||||
return this.http.post<TokenDTO>(`${this.appsettings.getApiURL()}/api/auth/revoke`, token, {
|
||||
headers: new HttpHeaders({
|
||||
"Content-Type": "application/json"
|
||||
})
|
||||
}).pipe(catchError((error: any) => {
|
||||
error.error = null;
|
||||
this.isLoggedIn$.next(false);
|
||||
localStorage.removeItem("rjwt");
|
||||
this.router.navigate(["/auth/login"]);
|
||||
return throwError(() => error);
|
||||
})).subscribe(() => {
|
||||
this.isLoggedIn$.next(false);
|
||||
localStorage.removeItem("jwt");
|
||||
localStorage.removeItem("rjwt");
|
||||
this.router.navigate(["/auth/login"]);
|
||||
});
|
||||
}
|
||||
this.isLoggedIn$.next(false);
|
||||
localStorage.removeItem("rjwt");
|
||||
this.router.navigate(["/auth/login"]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async getLoggedInUser(): Promise<AuthUserDTO | null> {
|
||||
if (!await this.isUserLoggedInAsync()) {
|
||||
return null;
|
||||
}
|
||||
const token = this.getDecodedToken();
|
||||
if (!token) return null;
|
||||
|
||||
try {
|
||||
return await firstValueFrom(this.findUserByEMail(token["email"]));
|
||||
} catch (error: unknown) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async isUserLoggedInAsync(): Promise<boolean> {
|
||||
const token = this.getToken();
|
||||
|
||||
if (!token || !token.refreshToken) {
|
||||
this.isLoggedIn$.next(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const verifiedLogin = await firstValueFrom(this.verifyLogin());
|
||||
if (verifiedLogin) {
|
||||
this.isLoggedIn$.next(true);
|
||||
return true;
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
this.isLoggedIn$.next(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.spinnerService.showSpinner();
|
||||
const resfreshedToken = await firstValueFrom(await this.refresh(token));
|
||||
this.spinnerService.hideSpinner();
|
||||
if (resfreshedToken) {
|
||||
this.saveToken(resfreshedToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async hasUserPermission(role: AuthRoles): Promise<boolean> {
|
||||
if (!role || !await this.isUserLoggedInAsync()) {
|
||||
return false;
|
||||
}
|
||||
const token = this.getDecodedToken();
|
||||
if (!token) return false;
|
||||
return AuthRoles[token["role"]] === AuthRoles[role];
|
||||
}
|
||||
|
||||
getEMailFromDecodedToken(token: { [key: string]: any } | null): string | null {
|
||||
if (!token) {
|
||||
return null;
|
||||
}
|
||||
return token["email"];
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ConfirmationDialogService } from './confirmation-dialog.service';
|
||||
|
||||
describe('ConfirmationDialogService', () => {
|
||||
let service: ConfirmationDialogService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ConfirmationDialogService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@@ -0,0 +1,53 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ConfirmationService } from 'primeng/api';
|
||||
import { ConfirmationDialog } from 'src/app/models/utils/confirmation-dialog';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ConfirmationDialogService {
|
||||
|
||||
constructor(
|
||||
private confirmationService: ConfirmationService
|
||||
) { }
|
||||
|
||||
errorDialog(header: string, message: string) {
|
||||
this.confirmationService.confirm({
|
||||
key: 'errorConfirmationDialog',
|
||||
header: header,
|
||||
message: message
|
||||
});
|
||||
}
|
||||
|
||||
confirmDialog(header: string, message: string, accept?: () => void, reject?: () => void) {
|
||||
let options: ConfirmationDialog = {
|
||||
key: 'confirmConfirmationDialog',
|
||||
header: header,
|
||||
message: message
|
||||
};
|
||||
|
||||
if (accept) {
|
||||
options.accept = accept;
|
||||
}
|
||||
|
||||
if (reject) {
|
||||
options.reject = reject;
|
||||
}
|
||||
|
||||
this.confirmationService.confirm(options);
|
||||
}
|
||||
|
||||
warningDialog(header: string, message: string, accept?: () => void) {
|
||||
let options: ConfirmationDialog = {
|
||||
key: 'warningConfirmationDialog',
|
||||
header: header,
|
||||
message: message
|
||||
};
|
||||
|
||||
if (accept) {
|
||||
options.accept = accept;
|
||||
}
|
||||
|
||||
this.confirmationService.confirm(options);
|
||||
}
|
||||
}
|
16
web/src/app/services/data/data.service.spec.ts
Normal file
16
web/src/app/services/data/data.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
|
||||
describe('DataService', () => {
|
||||
let service: DataService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DataService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
90
web/src/app/services/data/data.service.ts
Normal file
90
web/src/app/services/data/data.service.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { SettingsService } from "../settings/settings.service";
|
||||
import { map, Observable } from "rxjs";
|
||||
import { Variables } from "../../models/graphql/variables.model";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { Server } from "../../models/data/server.model";
|
||||
import { Queries } from "../../models/graphql/queries.model";
|
||||
import { Query } from "../../models/graphql/query.model";
|
||||
import { SpinnerService } from "../spinner/spinner.service";
|
||||
import { GraphQLResult } from "../../models/graphql/result.model";
|
||||
import { ToastService } from "../toast/toast.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { ServerService } from "../server.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class DataService {
|
||||
|
||||
constructor(
|
||||
private appsettings: SettingsService,
|
||||
private http: HttpClient,
|
||||
private server: ServerService,
|
||||
private spinner: SpinnerService,
|
||||
private router: Router,
|
||||
private toast: ToastService,
|
||||
private translate: TranslateService,
|
||||
) {
|
||||
}
|
||||
|
||||
public getServerFromRoute(route: ActivatedRoute): Promise<Server> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.spinner.showSpinner();
|
||||
if (!route.snapshot.params["serverId"] || route.snapshot.params["serverId"] == "undefined") {
|
||||
this.spinner.hideSpinner();
|
||||
this.router.navigate(["/dashboard"]);
|
||||
reject();
|
||||
}
|
||||
|
||||
this.query<Server>(Queries.serversQuery, {
|
||||
filter: { id: route.snapshot.params["serverId"] }
|
||||
},
|
||||
function(data: Query) {
|
||||
return data.servers.length > 0 ? data.servers[0] : null;
|
||||
}
|
||||
).subscribe(server => {
|
||||
this.server.setServer(server);
|
||||
this.spinner.hideSpinner();
|
||||
resolve(server);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public query<T>(query: string, variables?: Variables, f?: Function): Observable<T> {
|
||||
return this.http
|
||||
.post<GraphQLResult>(`${this.appsettings.getApiURL()}/api/graphql`, {
|
||||
query: query,
|
||||
variables: variables
|
||||
})
|
||||
.pipe(map(d => {
|
||||
if (d.errors && d.errors.length > 0) {
|
||||
throw new Error(d.errors.map((x: { message: String }) => x.message).toString());
|
||||
}
|
||||
return d.data;
|
||||
}))
|
||||
.pipe(map((d) => f ? f(d) : d));
|
||||
}
|
||||
|
||||
public mutation<T>(query: string, variables?: object, f?: Function): Observable<T> {
|
||||
return this.http
|
||||
.post<GraphQLResult>(`${this.appsettings.getApiURL()}/api/graphql`, {
|
||||
query: query,
|
||||
variables: variables
|
||||
})
|
||||
.pipe(map(d => {
|
||||
if (d.errors && d.errors.length > 0) {
|
||||
d.errors.forEach((error: Error) => {
|
||||
this.toast.error(this.translate.instant("common.error"), error.message)
|
||||
});
|
||||
|
||||
throw new Error(d.errors.toString());
|
||||
}
|
||||
return d.data;
|
||||
}))
|
||||
.pipe(map((d) => f ? f(d) : d));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ErrorHandlerService } from './error-handler.service';
|
||||
|
||||
describe('ErrorHandlerService', () => {
|
||||
let service: ErrorHandlerService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ErrorHandlerService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
48
web/src/app/services/error-handler/error-handler.service.ts
Normal file
48
web/src/app/services/error-handler/error-handler.service.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { HttpErrorResponse } from "@angular/common/http";
|
||||
import { ErrorHandler, Injectable } from "@angular/core";
|
||||
import { Observable, throwError } from "rxjs";
|
||||
import { ErrorDTO } from "src/app/models/error/error-dto";
|
||||
import { ServiceErrorCode } from "src/app/models/error/service-error-code.enum";
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
import { ToastService } from "../toast/toast.service";
|
||||
|
||||
@Injectable()
|
||||
export class ErrorHandlerService implements ErrorHandler {
|
||||
|
||||
constructor(
|
||||
private auth: AuthService,
|
||||
private toast: ToastService,
|
||||
) { }
|
||||
|
||||
handleError(error: HttpErrorResponse): Observable<never> {
|
||||
if (error && error.error) {
|
||||
let message = 'Unbekannter Fehler';
|
||||
let header = 'Fehler';
|
||||
const errorDto: ErrorDTO = error.error;
|
||||
|
||||
if (errorDto.errorCode === ServiceErrorCode.Unauthorized) {
|
||||
this.auth.logout();
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
if (errorDto.errorCode !== undefined) {
|
||||
header = 'Fehlercode: ' + errorDto.errorCode;
|
||||
}
|
||||
|
||||
if (errorDto.message) {
|
||||
message = errorDto.message;
|
||||
} else if (error.message) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
this.toast.error(header, message);
|
||||
} else {
|
||||
console.error(error.message);
|
||||
}
|
||||
|
||||
if (error.status === 401) {
|
||||
this.auth.logout();
|
||||
}
|
||||
return throwError(() => error);
|
||||
}
|
||||
}
|
16
web/src/app/services/gui/gui.service.spec.ts
Normal file
16
web/src/app/services/gui/gui.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GuiService } from './gui.service';
|
||||
|
||||
describe('GuiService', () => {
|
||||
let service: GuiService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(GuiService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
41
web/src/app/services/gui/gui.service.ts
Normal file
41
web/src/app/services/gui/gui.service.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subscribable } from 'rxjs';
|
||||
import { SettingsDTO } from 'src/app/models/config/settings.dto';
|
||||
import { SoftwareVersionDTO } from 'src/app/models/config/software-version.dto';
|
||||
import { SettingsService } from '../settings/settings.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class GuiService {
|
||||
|
||||
constructor(
|
||||
private appsettings: SettingsService,
|
||||
private http: HttpClient,
|
||||
) { }
|
||||
|
||||
getApiVersion(): Observable<SoftwareVersionDTO> {
|
||||
return this.http.get<SoftwareVersionDTO>(`${this.appsettings.getApiURL()}/api/gui/api-version`, {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getSettings(): Observable<SettingsDTO> {
|
||||
return this.http.get<SettingsDTO>(`${this.appsettings.getApiURL()}/api/gui/settings`, {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
sendTestMail(mail: string): Observable<unknown> {
|
||||
return this.http.post(`${this.appsettings.getApiURL()}/api/gui/send-test-mail/${mail}`, {
|
||||
headers: new HttpHeaders({
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
16
web/src/app/services/server.service.spec.ts
Normal file
16
web/src/app/services/server.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ServerService } from './server.service';
|
||||
|
||||
describe('ServerService', () => {
|
||||
let service: ServerService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ServerService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
37
web/src/app/services/server.service.ts
Normal file
37
web/src/app/services/server.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { Server } from "../models/data/server.model";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class ServerService {
|
||||
|
||||
|
||||
server$ = new BehaviorSubject<Server | undefined>(undefined);
|
||||
|
||||
constructor(
|
||||
private router: Router
|
||||
) {
|
||||
this.router.events.subscribe(event => {
|
||||
if (!(event instanceof NavigationEnd)) {
|
||||
return;
|
||||
}
|
||||
if (!event.url.startsWith("/server/") && this.server$.value) {
|
||||
this.setServer(undefined);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setServer(server: Server | undefined) {
|
||||
if (!server) {
|
||||
this.server$.next(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.id != this.server$.value?.id) {
|
||||
this.server$.next(server);
|
||||
}
|
||||
}
|
||||
}
|
16
web/src/app/services/settings/settings.service.spec.ts
Normal file
16
web/src/app/services/settings/settings.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SettingsService } from './settings.service';
|
||||
|
||||
describe('SettingsService', () => {
|
||||
let service: SettingsService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(SettingsService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
86
web/src/app/services/settings/settings.service.ts
Normal file
86
web/src/app/services/settings/settings.service.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Injectable } from "@angular/core";
|
||||
import { forkJoin, throwError } from "rxjs";
|
||||
import { catchError } from "rxjs/operators";
|
||||
import { AppAndVersionSettings, AppSettings, VersionSettings } from "src/app/models/config/app-settings";
|
||||
import { SoftwareVersion } from "src/app/models/config/software-version";
|
||||
import { Theme } from "src/app/models/view/theme";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class SettingsService {
|
||||
appSettings!: AppSettings;
|
||||
versionSettings!: VersionSettings;
|
||||
|
||||
constructor(
|
||||
private http: HttpClient
|
||||
) {
|
||||
}
|
||||
|
||||
loadSettings(version: boolean = false): Promise<AppAndVersionSettings> {
|
||||
return new Promise((resolve, reject) => {
|
||||
forkJoin([
|
||||
this.http.get<AppSettings>("../../assets/config.json")
|
||||
.pipe(catchError(error => {
|
||||
reject(error);
|
||||
return throwError(() => error);
|
||||
})),
|
||||
this.http.get<VersionSettings>("../../assets/version.json")
|
||||
.pipe(catchError(error => {
|
||||
reject(error);
|
||||
return throwError(() => error);
|
||||
}))
|
||||
]).subscribe(settings => {
|
||||
this.appSettings = settings[0];
|
||||
this.versionSettings = settings[1];
|
||||
resolve({...settings[0], ...settings[1]});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public getApiURL(): string {
|
||||
if (!this.appSettings || !this.appSettings.ApiURL) {
|
||||
console.error("ApiUrl is not set!");
|
||||
return "";
|
||||
}
|
||||
return this.appSettings.ApiURL;
|
||||
}
|
||||
|
||||
public getPrivacyURL(): string {
|
||||
if (!this.appSettings || !this.appSettings.PrivacyURL) {
|
||||
console.error("PrivacyURL is not set!");
|
||||
return "";
|
||||
}
|
||||
return this.appSettings.PrivacyURL;
|
||||
}
|
||||
|
||||
public getImprintURL(): string {
|
||||
if (!this.appSettings || !this.appSettings.ImprintURL) {
|
||||
console.error("ImprintURL is not set!");
|
||||
return "";
|
||||
}
|
||||
return this.appSettings.ImprintURL;
|
||||
}
|
||||
|
||||
public getWebVersion(): SoftwareVersion | null {
|
||||
if (!this.versionSettings || !this.versionSettings.WebVersion) {
|
||||
console.error("WebVersion is not set!");
|
||||
return null;
|
||||
}
|
||||
return new SoftwareVersion(
|
||||
this.versionSettings.WebVersion.Major,
|
||||
this.versionSettings.WebVersion.Minor,
|
||||
this.versionSettings.WebVersion.Micro
|
||||
);
|
||||
}
|
||||
|
||||
public getThemes(): Theme[] | null {
|
||||
if (!this.appSettings || !this.appSettings.Themes) {
|
||||
console.error("Themes is not set!");
|
||||
return null;
|
||||
}
|
||||
return this.appSettings.Themes;
|
||||
}
|
||||
}
|
||||
|
16
web/src/app/services/sidebar/sidebar.service.spec.ts
Normal file
16
web/src/app/services/sidebar/sidebar.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SidebarService } from './sidebar.service';
|
||||
|
||||
describe('SidebarService', () => {
|
||||
let service: SidebarService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(SidebarService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
231
web/src/app/services/sidebar/sidebar.service.ts
Normal file
231
web/src/app/services/sidebar/sidebar.service.ts
Normal file
@@ -0,0 +1,231 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { MenuItem } from "primeng/api";
|
||||
import { BehaviorSubject, forkJoin, Observable } from "rxjs";
|
||||
import { AuthRoles } from "../../models/auth/auth-roles.enum";
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { NavigationEnd, Router } from "@angular/router";
|
||||
import { ThemeService } from "../theme/theme.service";
|
||||
import { Server } from "../../models/data/server.model";
|
||||
import { UserDTO } from "../../models/auth/auth-user.dto";
|
||||
import { ServerService } from "../server.service";
|
||||
import { HasServerFeatureFlagQuery, PossibleFeatureFlagsQuery, Query } from "../../models/graphql/query.model";
|
||||
import { Queries } from "../../models/graphql/queries.model";
|
||||
import { DataService } from "../data/data.service";
|
||||
import { FeatureFlag } from "../../models/config/feature-flags.model";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class SidebarService {
|
||||
|
||||
isSidebarOpen: boolean = true;
|
||||
menuItems$ = new BehaviorSubject<MenuItem[]>(new Array<MenuItem>());
|
||||
server!: Server | undefined;
|
||||
|
||||
dashboard: MenuItem = {};
|
||||
serverDashboard: MenuItem = {};
|
||||
serverProfile: MenuItem = {};
|
||||
serverMembers: MenuItem = {};
|
||||
serverAutoRoles: MenuItem = {};
|
||||
serverLevels: MenuItem = {};
|
||||
serverAchievements: MenuItem = {};
|
||||
serverShortRoleNames: MenuItem = {};
|
||||
serverConfig: MenuItem = {};
|
||||
serverMenu: MenuItem = {};
|
||||
adminConfig: MenuItem = {};
|
||||
adminUsers: MenuItem = {};
|
||||
adminMenu: MenuItem = {};
|
||||
|
||||
featureFlags: FeatureFlag[] = [];
|
||||
|
||||
constructor(
|
||||
private themeService: ThemeService,
|
||||
private authService: AuthService,
|
||||
private translateService: TranslateService,
|
||||
private router: Router,
|
||||
private serverService: ServerService,
|
||||
private data: DataService
|
||||
) {
|
||||
this.themeService.isSidebarOpen$.subscribe(value => {
|
||||
this.isSidebarOpen = value;
|
||||
this.setMenu(true);
|
||||
});
|
||||
|
||||
this.translateService.onLangChange.subscribe(_ => {
|
||||
this.setMenu(true);
|
||||
});
|
||||
|
||||
this.serverService.server$.subscribe(server => {
|
||||
this.server = server;
|
||||
if (server) {
|
||||
this.setMenu(true);
|
||||
} else {
|
||||
this.setMenu(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async buildMenu(user: UserDTO | null, hasPermission: boolean, isTechnician: boolean = false) {
|
||||
this.dashboard = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.dashboard") : "",
|
||||
icon: "pi pi-th-large",
|
||||
routerLink: "dashboard"
|
||||
};
|
||||
this.serverDashboard = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.dashboard") : "",
|
||||
icon: "pi pi-th-large",
|
||||
routerLink: `server/${this.server?.id}`
|
||||
};
|
||||
this.serverProfile = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.profile") : "",
|
||||
icon: "pi pi-id-card",
|
||||
routerLink: `server/${this.server?.id}/members/${user?.id}`
|
||||
};
|
||||
this.serverMembers = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.members") : "",
|
||||
icon: "pi pi-users",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/members`
|
||||
};
|
||||
|
||||
this.serverAutoRoles = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.auto_roles") : "",
|
||||
icon: "pi pi-sitemap",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/auto-roles`
|
||||
};
|
||||
|
||||
this.serverLevels = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.levels") : "",
|
||||
icon: "pi pi-book",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/levels`
|
||||
};
|
||||
|
||||
this.serverAchievements = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.achievements") : "",
|
||||
icon: "pi pi-angle-double-up",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/achievements`
|
||||
};
|
||||
|
||||
this.serverShortRoleNames = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.short_role_names") : "",
|
||||
icon: "pi pi-list",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/short-role-names`
|
||||
};
|
||||
|
||||
this.serverConfig = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.server.configuration") : "",
|
||||
icon: "pi pi-cog",
|
||||
visible: true,
|
||||
routerLink: `server/${this.server?.id}/config`
|
||||
};
|
||||
|
||||
this.serverMenu = {
|
||||
label: this.isSidebarOpen ? this.server?.name : "",
|
||||
icon: "pi pi-server",
|
||||
visible: false,
|
||||
expanded: true,
|
||||
items: [this.serverDashboard, this.serverProfile, this.serverMembers, this.serverAutoRoles, this.serverLevels, this.serverAchievements, this.serverShortRoleNames, this.serverConfig]
|
||||
};
|
||||
this.adminConfig = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.config") : "",
|
||||
visible: hasPermission || isTechnician,
|
||||
icon: "pi pi-cog",
|
||||
routerLink: "/admin/settings"
|
||||
};
|
||||
this.adminUsers = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.auth_user_list") : "",
|
||||
visible: hasPermission,
|
||||
icon: "pi pi-user-edit",
|
||||
routerLink: "/admin/users"
|
||||
};
|
||||
this.adminMenu = {
|
||||
label: this.isSidebarOpen ? this.translateService.instant("sidebar.administration") : "",
|
||||
icon: "pi pi-cog",
|
||||
visible: hasPermission || isTechnician,
|
||||
expanded: true,
|
||||
items: [this.adminConfig, this.adminUsers]
|
||||
};
|
||||
}
|
||||
|
||||
setMenu(build: boolean = false) {
|
||||
const server = this.server;
|
||||
|
||||
if (server) {
|
||||
this.featureFlags = [];
|
||||
this.data.query<PossibleFeatureFlagsQuery>("{possibleFeatureFlags}"
|
||||
).subscribe(data => {
|
||||
let observables: Observable<HasServerFeatureFlagQuery>[] = [];
|
||||
data.possibleFeatureFlags.forEach(flag => {
|
||||
observables.push(
|
||||
this.data.query<HasServerFeatureFlagQuery>(Queries.hasServerFeatureFlag, {
|
||||
filter: { id: server.id },
|
||||
flag: flag
|
||||
},
|
||||
function(data: Query) {
|
||||
return data.servers[0];
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
forkJoin(observables).subscribe(data => {
|
||||
data.forEach(flag => {
|
||||
if (!flag.hasFeatureFlag.value) {
|
||||
return;
|
||||
}
|
||||
this.featureFlags.push(flag.hasFeatureFlag);
|
||||
});
|
||||
this._setMenu(build);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this._setMenu(build);
|
||||
}
|
||||
}
|
||||
|
||||
private _setMenu(build: boolean = false) {
|
||||
this.authService.hasUserPermission(AuthRoles.Admin).then(async hasPermission => {
|
||||
let authUser = await this.authService.getLoggedInUser();
|
||||
let user: UserDTO | null = authUser?.users?.find(u => u.server == this.server?.id) ?? null;
|
||||
let isTechnician = (authUser?.users?.map(u => u.isTechnician).filter(u => u) ?? []).length > 0;
|
||||
let isTechnicianAndFullAccessActive = this.hasFeature("TechnicianFullAccess") && isTechnician;
|
||||
|
||||
if (build || this.menuItems$.value.length == 0) {
|
||||
await this.buildMenu(user, hasPermission, isTechnician);
|
||||
}
|
||||
|
||||
if (this.server) {
|
||||
this.serverMenu.visible = true;
|
||||
this.serverMembers.visible = isTechnicianAndFullAccessActive || user?.isModerator;
|
||||
this.serverAutoRoles.visible = isTechnicianAndFullAccessActive || this.hasFeature("AutoRoleModule") && user?.isModerator;
|
||||
this.serverLevels.visible = isTechnicianAndFullAccessActive || this.hasFeature("LevelModule") && user?.isModerator;
|
||||
this.serverAchievements.visible = isTechnicianAndFullAccessActive || this.hasFeature("AchievementsModule") && user?.isModerator;
|
||||
this.serverShortRoleNames.visible = isTechnicianAndFullAccessActive || this.hasFeature("ShortRoleName") && user?.isAdmin;
|
||||
|
||||
this.serverConfig.visible = isTechnicianAndFullAccessActive || user?.isAdmin;
|
||||
} else {
|
||||
this.serverMenu.visible = false;
|
||||
}
|
||||
|
||||
let menuItems: MenuItem[] = [
|
||||
this.dashboard,
|
||||
this.serverMenu,
|
||||
this.adminMenu
|
||||
];
|
||||
this.menuItems$.next(menuItems);
|
||||
});
|
||||
}
|
||||
|
||||
public hasFeature(key: string): boolean {
|
||||
const flag = this.featureFlags.filter(flag => flag.key == key);
|
||||
if (flag.length == 0) {
|
||||
return false;
|
||||
}
|
||||
return flag[0].value;
|
||||
}
|
||||
}
|
16
web/src/app/services/socket/socket.service.spec.ts
Normal file
16
web/src/app/services/socket/socket.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SocketService } from './socket.service';
|
||||
|
||||
describe('SocketService', () => {
|
||||
let service: SocketService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(SocketService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
74
web/src/app/services/socket/socket.service.ts
Normal file
74
web/src/app/services/socket/socket.service.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ToastOptions } from "src/app/models/utils/toast-options";
|
||||
import { SettingsService } from "../settings/settings.service";
|
||||
import { SpinnerService } from "../spinner/spinner.service";
|
||||
import { ToastService } from "../toast/toast.service";
|
||||
import io from "socket.io-client";
|
||||
import { MessageService } from "primeng/api";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class SocketService {
|
||||
private socket: any;
|
||||
disconnected = false;
|
||||
|
||||
constructor(
|
||||
private settingsService: SettingsService,
|
||||
private toastService: ToastService,
|
||||
private spinnerService: SpinnerService,
|
||||
private messageService: MessageService
|
||||
) {
|
||||
}
|
||||
|
||||
startSocket() {
|
||||
this.socket = io(`${this.settingsService.getApiURL()}`, { path: "/api/socket.io" });
|
||||
this.socket.on("connect", () => {
|
||||
if (this.disconnected) {
|
||||
this.spinnerService.hideSpinner();
|
||||
const options: ToastOptions = {
|
||||
closable: false
|
||||
};
|
||||
this.messageService.clear();
|
||||
this.toastService.info("Server verbunden", "Die Verbindung zum Server konnte hergestellt werden.", options);
|
||||
}
|
||||
|
||||
this.disconnected = false;
|
||||
console.info("Connected!");
|
||||
});
|
||||
|
||||
this.socket.on("connect_error", (err: Error) => {
|
||||
if (this.disconnected) {
|
||||
this.spinnerService.showSpinner();
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn("Connect error!");
|
||||
this.disconnected = true;
|
||||
const options: ToastOptions = {
|
||||
sticky: true,
|
||||
closable: false
|
||||
};
|
||||
this.messageService.clear();
|
||||
this.toastService.error("Server nicht erreichbar", "Die Verbindung zum Server konnte nicht hergestellt werden!\nLaden Sie die Seite neu.", options);
|
||||
console.error(err.toString());
|
||||
});
|
||||
|
||||
this.socket.on("disconnect", () => {
|
||||
if (this.disconnected) {
|
||||
this.spinnerService.showSpinner();
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn("Disconnected!");
|
||||
this.disconnected = true;
|
||||
const options: ToastOptions = {
|
||||
sticky: true,
|
||||
closable: false
|
||||
};
|
||||
this.spinnerService.showSpinner();
|
||||
this.messageService.clear();
|
||||
this.toastService.error("Verbindung unterbrochen", "Die Verbindung zum Server konnte nicht hergestellt werden!\nLaden Sie die Seite neu.", options);
|
||||
});
|
||||
}
|
||||
}
|
16
web/src/app/services/spinner/spinner.service.spec.ts
Normal file
16
web/src/app/services/spinner/spinner.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SpinnerService } from './spinner.service';
|
||||
|
||||
describe('SpinnerService', () => {
|
||||
let service: SpinnerService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(SpinnerService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
23
web/src/app/services/spinner/spinner.service.ts
Normal file
23
web/src/app/services/spinner/spinner.service.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SpinnerService {
|
||||
|
||||
showSpinnerState$ = new BehaviorSubject<boolean>(false);
|
||||
constructor() { }
|
||||
|
||||
showSpinner() {
|
||||
this.showSpinnerState$.next(true);
|
||||
}
|
||||
|
||||
hideSpinner() {
|
||||
this.showSpinnerState$.next(false);
|
||||
}
|
||||
|
||||
toggleSpinner() {
|
||||
this.showSpinnerState$.next(!this.showSpinnerState$.value);
|
||||
}
|
||||
}
|
16
web/src/app/services/theme/theme.service.spec.ts
Normal file
16
web/src/app/services/theme/theme.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ThemeService } from './theme.service';
|
||||
|
||||
describe('ThemeService', () => {
|
||||
let service: ThemeService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ThemeService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
107
web/src/app/services/theme/theme.service.ts
Normal file
107
web/src/app/services/theme/theme.service.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { Themes } from "src/app/models/view/themes.enum";
|
||||
import { AuthService } from "../auth/auth.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root"
|
||||
})
|
||||
export class ThemeService {
|
||||
|
||||
themeName: string = Themes.Default;
|
||||
isSidebarOpen = false;
|
||||
|
||||
themeName$ = new BehaviorSubject<string>(Themes.Default);
|
||||
isSidebarOpen$ = new BehaviorSubject<boolean>(true);
|
||||
|
||||
constructor(
|
||||
private authService: AuthService
|
||||
) {
|
||||
this.themeName$.subscribe(themeName => {
|
||||
this.themeName = themeName;
|
||||
});
|
||||
this.isSidebarOpen$.subscribe(isSidebarOpen => {
|
||||
this.isSidebarOpen = isSidebarOpen;
|
||||
});
|
||||
|
||||
this.loadTheme();
|
||||
}
|
||||
|
||||
loadTheme(): void {
|
||||
const token = this.authService.getDecodedToken();
|
||||
const mail = this.authService.getEMailFromDecodedToken(token);
|
||||
|
||||
let defaultThemeName = localStorage.getItem(`default_themeName`);
|
||||
if (!defaultThemeName) {
|
||||
defaultThemeName = Themes.Default;
|
||||
}
|
||||
|
||||
if (!mail) {
|
||||
this.setTheme(defaultThemeName);
|
||||
return;
|
||||
}
|
||||
|
||||
let userThemeName = localStorage.getItem(`${mail}_themeName`);
|
||||
if (!userThemeName) {
|
||||
this.setTheme(defaultThemeName);
|
||||
return;
|
||||
}
|
||||
this.setTheme(userThemeName);
|
||||
}
|
||||
|
||||
setTheme(name: string, isDefault: boolean = false): void {
|
||||
if (isDefault) {
|
||||
localStorage.setItem(`default_themeName`, name);
|
||||
this.themeName$.next(name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.authService.isLoggedIn$.value) {
|
||||
localStorage.setItem(`default_themeName`, Themes.Default);
|
||||
this.themeName$.next(Themes.Default);
|
||||
}
|
||||
|
||||
const token = this.authService.getDecodedToken();
|
||||
const mail = this.authService.getEMailFromDecodedToken(token);
|
||||
if (mail) {
|
||||
localStorage.setItem(`${mail}_themeName`, name);
|
||||
}
|
||||
localStorage.setItem(`default_themeName`, name);
|
||||
this.themeName$.next(name);
|
||||
}
|
||||
|
||||
loadMenu() {
|
||||
const token = this.authService.getDecodedToken();
|
||||
const mail = this.authService.getEMailFromDecodedToken(token);
|
||||
|
||||
if (!mail) {
|
||||
this.setSideWidth(true);
|
||||
return;
|
||||
}
|
||||
|
||||
let isMenuOpen = true;
|
||||
let isMenuOpenStr = localStorage.getItem(`${mail}_isMenuOpen`);
|
||||
if (isMenuOpenStr) {
|
||||
isMenuOpen = JSON.parse(isMenuOpenStr);
|
||||
}
|
||||
|
||||
this.setIsMenuOpen(isMenuOpen);
|
||||
}
|
||||
|
||||
setIsMenuOpen(isMenuOpen: boolean) {
|
||||
const token = this.authService.getDecodedToken();
|
||||
const mail = this.authService.getEMailFromDecodedToken(token);
|
||||
|
||||
if (!mail) {
|
||||
this.setSideWidth(true);
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem(`${mail}_isMenuOpen`, isMenuOpen + "");
|
||||
this.setSideWidth(isMenuOpen);
|
||||
}
|
||||
|
||||
setSideWidth(isSidebarOpen: boolean): void {
|
||||
this.isSidebarOpen$.next(isSidebarOpen);
|
||||
}
|
||||
}
|
16
web/src/app/services/toast/toast.service.spec.ts
Normal file
16
web/src/app/services/toast/toast.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ToastService } from './toast.service';
|
||||
|
||||
describe('ToastService', () => {
|
||||
let service: ToastService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ToastService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
40
web/src/app/services/toast/toast.service.ts
Normal file
40
web/src/app/services/toast/toast.service.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { ToastOptions } from 'src/app/models/utils/toast-options';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ToastService {
|
||||
|
||||
constructor(
|
||||
private messageService: MessageService
|
||||
) { }
|
||||
|
||||
private toast(type: string, summary: string, detail: string, options?: ToastOptions) {
|
||||
this.messageService.add({
|
||||
severity: type,
|
||||
summary: summary,
|
||||
detail: detail,
|
||||
life: options?.life,
|
||||
sticky: options?.sticky,
|
||||
closable: options?.closable
|
||||
});
|
||||
}
|
||||
|
||||
success(summary: string, detail: string, options?: ToastOptions) {
|
||||
this.toast('success', summary, detail, options);
|
||||
}
|
||||
|
||||
info(summary: string, detail: string, options?: ToastOptions) {
|
||||
this.toast('info', summary, detail, options);
|
||||
}
|
||||
|
||||
warn(summary: string, detail: string, options?: ToastOptions) {
|
||||
this.toast('warn', summary, detail, options);
|
||||
}
|
||||
|
||||
error(summary: string, detail: string, options?: ToastOptions) {
|
||||
this.toast('error', summary, detail, options);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user