Compare commits
12 Commits
2871505591
...
dba0d3cd62
Author | SHA1 | Date | |
---|---|---|---|
dba0d3cd62 | |||
7a9bca86bc | |||
f24c1fd9c8 | |||
c945a1016b | |||
8a584fd28a | |||
60d306f9c9 | |||
5d79d86c44 | |||
eada16110b | |||
b215d8909c | |||
1f03c2a9c3 | |||
48a74ecbf5 | |||
fd5a1cb14f |
35
package-lock.json
generated
35
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b2",
|
"version": "1.0.0-b3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b2",
|
"version": "1.0.0-b3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^18.2.1",
|
"@angular/animations": "^18.2.1",
|
||||||
"@angular/cdk": "~18.2.1",
|
"@angular/cdk": "~18.2.1",
|
||||||
@ -19,9 +19,10 @@
|
|||||||
"@angular/platform-browser": "^18.2.1",
|
"@angular/platform-browser": "^18.2.1",
|
||||||
"@angular/platform-browser-dynamic": "^18.2.1",
|
"@angular/platform-browser-dynamic": "^18.2.1",
|
||||||
"@angular/router": "^18.2.1",
|
"@angular/router": "^18.2.1",
|
||||||
|
"@dhutaryan/ngx-mat-timepicker": "^18.0.1",
|
||||||
"@progress/kendo-date-math": "^1.5.13",
|
"@progress/kendo-date-math": "^1.5.13",
|
||||||
"rxjs": "~7.8.1",
|
"rxjs": "~7.8.1",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.7.0",
|
||||||
"zone.js": "^0.14.10"
|
"zone.js": "^0.14.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -35,7 +36,6 @@
|
|||||||
"karma-coverage": "~2.2.1",
|
"karma-coverage": "~2.2.1",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"terser-webpack-plugin": "^5.3.10",
|
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.5.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -232,6 +232,13 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@angular-devkit/build-angular/node_modules/tslib": {
|
||||||
|
"version": "2.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||||
|
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
"node_modules/@angular-devkit/build-webpack": {
|
"node_modules/@angular-devkit/build-webpack": {
|
||||||
"version": "0.1802.1",
|
"version": "0.1802.1",
|
||||||
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.1.tgz",
|
"resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.1.tgz",
|
||||||
@ -2528,6 +2535,20 @@
|
|||||||
"node": ">=0.1.90"
|
"node": ">=0.1.90"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dhutaryan/ngx-mat-timepicker": {
|
||||||
|
"version": "18.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dhutaryan/ngx-mat-timepicker/-/ngx-mat-timepicker-18.0.1.tgz",
|
||||||
|
"integrity": "sha512-7qOiDFGorfmJJ/f9In4jHRJq8sDZqtX0aBFQU/KEGkBywmm0In7C+Z7To1DWM5hbR/XAC4d6b+sOqq0Pcqqsmw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": ">=2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=18.0.0",
|
||||||
|
"@angular/core": ">=18.0.0",
|
||||||
|
"@angular/material": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@discoveryjs/json-ext": {
|
"node_modules/@discoveryjs/json-ext": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz",
|
||||||
@ -12544,9 +12565,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.6.3",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||||
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
"node_modules/tuf-js": {
|
"node_modules/tuf-js": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b2",
|
"version": "1.0.0-b3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
@ -21,9 +21,10 @@
|
|||||||
"@angular/platform-browser": "^18.2.1",
|
"@angular/platform-browser": "^18.2.1",
|
||||||
"@angular/platform-browser-dynamic": "^18.2.1",
|
"@angular/platform-browser-dynamic": "^18.2.1",
|
||||||
"@angular/router": "^18.2.1",
|
"@angular/router": "^18.2.1",
|
||||||
|
"@dhutaryan/ngx-mat-timepicker": "^18.0.1",
|
||||||
"@progress/kendo-date-math": "^1.5.13",
|
"@progress/kendo-date-math": "^1.5.13",
|
||||||
"rxjs": "~7.8.1",
|
"rxjs": "~7.8.1",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.7.0",
|
||||||
"zone.js": "^0.14.10"
|
"zone.js": "^0.14.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -37,7 +38,6 @@
|
|||||||
"karma-coverage": "~2.2.1",
|
"karma-coverage": "~2.2.1",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"terser-webpack-plugin": "^5.3.10",
|
|
||||||
"typescript": "^5.5.4"
|
"typescript": "^5.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import {HttpHeaders} from "@angular/common/http";
|
import {HttpHeaders} from "@angular/common/http";
|
||||||
|
|
||||||
export interface SetRequestBuilderAfterBuild {
|
|
||||||
setRequestBuilder(request: RequestData): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RequestData {
|
export interface RequestData {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
queryParams: Record<string, string | number | boolean | Array<any> | null> | null;
|
queryParams: Record<string, string | number | boolean | Array<any> | null> | null;
|
||||||
@ -11,6 +7,7 @@ export interface RequestData {
|
|||||||
data: any;
|
data: any;
|
||||||
silenceMode: boolean;
|
silenceMode: boolean;
|
||||||
withCredentials: boolean;
|
withCredentials: boolean;
|
||||||
|
needAuth: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RequestBuilder {
|
export class RequestBuilder {
|
||||||
@ -20,10 +17,8 @@ export class RequestBuilder {
|
|||||||
private data: any = null;
|
private data: any = null;
|
||||||
private silenceMode: boolean = false;
|
private silenceMode: boolean = false;
|
||||||
private withCredentials: boolean = false;
|
private withCredentials: boolean = false;
|
||||||
private readonly object: any;
|
|
||||||
|
|
||||||
constructor(obj: any) {
|
constructor() {
|
||||||
this.object = obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setEndpoint(endpoint: string): this {
|
public setEndpoint(endpoint: string): this {
|
||||||
@ -58,16 +53,16 @@ export class RequestBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public build<Type>(): Type {
|
public get build(): RequestData {
|
||||||
(this.object as SetRequestBuilderAfterBuild).setRequestBuilder({
|
return {
|
||||||
endpoint: this.endpoint,
|
endpoint: this.endpoint,
|
||||||
queryParams: this.queryParams,
|
queryParams: this.queryParams,
|
||||||
httpHeaders: this.httpHeaders,
|
httpHeaders: this.httpHeaders,
|
||||||
data: this.data,
|
data: this.data,
|
||||||
silenceMode: this.silenceMode,
|
silenceMode: this.silenceMode,
|
||||||
withCredentials: this.withCredentials
|
withCredentials: this.withCredentials,
|
||||||
});
|
needAuth: false
|
||||||
return this.object as Type;
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getEndpoint(): string {
|
public getEndpoint(): string {
|
||||||
@ -97,16 +92,8 @@ export class RequestBuilder {
|
|||||||
httpHeaders: new HttpHeaders(),
|
httpHeaders: new HttpHeaders(),
|
||||||
data: null,
|
data: null,
|
||||||
silenceMode: false,
|
silenceMode: false,
|
||||||
withCredentials: false
|
withCredentials: false,
|
||||||
|
needAuth: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset(): void {
|
|
||||||
this.endpoint = '';
|
|
||||||
this.queryParams = null;
|
|
||||||
this.httpHeaders = new HttpHeaders();
|
|
||||||
this.data = null;
|
|
||||||
this.silenceMode = false;
|
|
||||||
this.withCredentials = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import {catchError, filter, mergeMap, Observable, retryWhen, switchMap, tap, timer} from "rxjs";
|
import {catchError, distinctUntilChanged, filter, first, mergeMap, Observable, retryWhen, switchMap, timer} from "rxjs";
|
||||||
import {HttpClient, HttpErrorResponse} from "@angular/common/http";
|
import {HttpClient, HttpErrorResponse} from "@angular/common/http";
|
||||||
import {NotifyColor, OpenNotifyService} from "@service/open-notify.service";
|
import {NotifyColor, OpenNotifyService} from "@service/open-notify.service";
|
||||||
import {environment} from "@environment";
|
import {environment} from "@environment";
|
||||||
import {Router} from "@angular/router";
|
import {Router} from "@angular/router";
|
||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {RequestBuilder, RequestData, SetRequestBuilderAfterBuild} from "@api/RequestBuilder";
|
import {RequestBuilder, RequestData} from "@api/RequestBuilder";
|
||||||
import {TokenRefreshService} from "@service/token-refresh.service";
|
import {TokenRefreshService} from "@service/token-refresh.service";
|
||||||
import {AuthToken} from "@service/auth.service";
|
import {AuthToken} from "@service/auth.service";
|
||||||
|
|
||||||
@ -36,19 +36,16 @@ export enum AvailableVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default abstract class ApiService implements SetRequestBuilderAfterBuild {
|
export default abstract class ApiService {
|
||||||
constructor(private http: HttpClient, private notify: OpenNotifyService, private router: Router, protected tokenRefreshService: TokenRefreshService) {
|
constructor(private http: HttpClient, private notify: OpenNotifyService, private router: Router, protected tokenRefreshService: TokenRefreshService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private apiUrl = environment.apiUrl;
|
private apiUrl = environment.apiUrl;
|
||||||
|
|
||||||
protected abstract basePath: string;
|
protected abstract basePath: string;
|
||||||
protected abstract version: AvailableVersion;
|
protected abstract version: AvailableVersion;
|
||||||
private request: RequestData = RequestBuilder.getStandardRequestData();
|
|
||||||
public static readonly tokenKey = 'auth_token';
|
|
||||||
|
|
||||||
public setRequestBuilder(request: RequestData): void {
|
public static readonly tokenKey = 'auth_token';
|
||||||
this.request = request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static addQuery(endpoint: string, queryParams?: Record<string, string | number | boolean | Array<any> | null> | null): string {
|
private static addQuery(endpoint: string, queryParams?: Record<string, string | number | boolean | Array<any> | null> | null): string {
|
||||||
const url = new URL(endpoint);
|
const url = new URL(endpoint);
|
||||||
@ -72,73 +69,80 @@ export default abstract class ApiService implements SetRequestBuilderAfterBuild
|
|||||||
return parts.map(part => part.replace(/(^\/+|\/+$)/g, '')).join('/');
|
return parts.map(part => part.replace(/(^\/+|\/+$)/g, '')).join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get combinedUrl() {
|
protected combinedUrl(request: RequestData) {
|
||||||
return ApiService.addQuery(ApiService.combineUrls(this.apiUrl, AvailableVersion[this.version], this.basePath, this.request.endpoint), this.request.queryParams);
|
return ApiService.addQuery(ApiService.combineUrls(this.apiUrl, AvailableVersion[this.version], this.basePath, request.endpoint), request.queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
private makeHttpRequest<Type>(method: 'get' | 'post' | 'delete' | 'put'): Observable<Type> {
|
private sendHttpRequest<Type>(method: 'get' | 'post' | 'delete' | 'put', request: RequestData): Observable<Type> {
|
||||||
const doneEndpoint = this.combinedUrl;
|
const doneEndpoint = this.combinedUrl(request);
|
||||||
|
|
||||||
return this.tokenRefreshService.getTokenRefreshing$().pipe(
|
return this.http.request<Type>(method, doneEndpoint, {
|
||||||
filter(isRefreshing => !isRefreshing),
|
withCredentials: request.withCredentials,
|
||||||
switchMap(() =>
|
headers: request.httpHeaders,
|
||||||
this.http.request<Type>(method, doneEndpoint, {
|
body: request.data
|
||||||
withCredentials: this.request.withCredentials,
|
}).pipe(
|
||||||
headers: this.request.httpHeaders,
|
retryWithInterval<Type>(),
|
||||||
body: this.request.data
|
catchError(error => {
|
||||||
}).pipe(
|
if (!request.silenceMode)
|
||||||
tap(_ => this.request = RequestBuilder.getStandardRequestData()),
|
this.handleError(error);
|
||||||
retryWithInterval<Type>(),
|
|
||||||
catchError(error => {
|
|
||||||
if (!this.request.silenceMode)
|
|
||||||
this.handleError(error);
|
|
||||||
|
|
||||||
this.request = RequestBuilder.getStandardRequestData();
|
throw error;
|
||||||
throw error;
|
})
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private makeHttpRequest<Type>(method: 'get' | 'post' | 'delete' | 'put', request: RequestData): Observable<Type> {
|
||||||
|
if (request.needAuth)
|
||||||
|
return this.tokenRefreshService.getTokenRefreshing$().pipe(
|
||||||
|
distinctUntilChanged(),
|
||||||
|
filter(isRefreshing => !isRefreshing),
|
||||||
|
first(),
|
||||||
|
switchMap(() => {
|
||||||
|
const token = localStorage.getItem(ApiService.tokenKey);
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
const authToken = AuthToken.httpHeader((JSON.parse(token) as AuthToken));
|
||||||
|
authToken.keys().forEach(key => request.httpHeaders = request.httpHeaders.append(key, authToken.get(key) ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.sendHttpRequest<Type>(method, request);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.sendHttpRequest<Type>(method, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRequest(request: RequestData | string | null): RequestData {
|
||||||
|
if (request === null)
|
||||||
|
return this.createRequestBuilder().build;
|
||||||
|
if (typeof request === 'string')
|
||||||
|
return this.createRequestBuilder().setEndpoint(request as string).build;
|
||||||
|
|
||||||
|
return request as RequestData;
|
||||||
|
}
|
||||||
|
|
||||||
public createRequestBuilder() {
|
public createRequestBuilder() {
|
||||||
this.request = RequestBuilder.getStandardRequestData();
|
return new RequestBuilder();
|
||||||
return new RequestBuilder(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get<Type>(endpoint: string = ''): Observable<Type> {
|
public get<Type>(request: RequestData | string | null = null): Observable<Type> {
|
||||||
if (endpoint)
|
return this.makeHttpRequest<Type>('get', this.getRequest(request));
|
||||||
this.request.endpoint = endpoint;
|
|
||||||
return this.makeHttpRequest<Type>('get');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public post<Type>(endpoint: string = ''): Observable<Type> {
|
public post<Type>(request: RequestData | string | null = null): Observable<Type> {
|
||||||
if (endpoint)
|
return this.makeHttpRequest<Type>('post', this.getRequest(request));
|
||||||
this.request.endpoint = endpoint;
|
|
||||||
return this.makeHttpRequest<Type>('post');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public put<Type>(endpoint: string = ''): Observable<Type> {
|
public put<Type>(request: RequestData | string | null = null): Observable<Type> {
|
||||||
if (endpoint)
|
return this.makeHttpRequest<Type>('put', this.getRequest(request));
|
||||||
this.request.endpoint = endpoint;
|
|
||||||
return this.makeHttpRequest<Type>('put');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public delete<Type>(endpoint: string = ''): Observable<Type> {
|
public delete<Type>(request: RequestData | string | null = null): Observable<Type> {
|
||||||
if (endpoint)
|
return this.makeHttpRequest<Type>('delete', this.getRequest(request));
|
||||||
this.request.endpoint = endpoint;
|
|
||||||
return this.makeHttpRequest<Type>('delete');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public addAuth() {
|
public addAuth(request: RequestData) {
|
||||||
const token = localStorage.getItem(ApiService.tokenKey);
|
request.needAuth = true;
|
||||||
|
|
||||||
if (!token)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
const authToken = AuthToken.httpHeader((JSON.parse(token) as AuthToken));
|
|
||||||
authToken.keys().forEach(key => this.request.httpHeaders = this.request.httpHeaders.append(key, authToken.get(key) ?? ''));
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,26 +12,29 @@ export default class AuthApiService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public login(login: LoginRequest) {
|
public login(login: LoginRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('Login')
|
.setEndpoint('Login')
|
||||||
.setData(login)
|
.setData(login)
|
||||||
.build<ApiService>()
|
.setWithCredentials()
|
||||||
.post<TokenResponse>()
|
.build;
|
||||||
|
|
||||||
|
return this.post<TokenResponse>(request)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(response => {
|
tap(response => {
|
||||||
AuthService.setToken(response, AvailableAuthenticationProvider.Bearer, this.createRequestBuilder().setEndpoint('ReLogin').build<AuthApiService>().combinedUrl);
|
AuthService.setToken(response, AvailableAuthenticationProvider.Bearer, this.combinedUrl(this.createRequestBuilder().setEndpoint('ReLogin').build));
|
||||||
this.tokenRefreshService.startTokenRefresh(response.expiresIn);
|
this.tokenRefreshService.setRefreshTokenExpireMs(response.expiresIn);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public logout() {
|
public logout() {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.setEndpoint('Logout')
|
.setEndpoint('Logout')
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.addAuth()
|
|
||||||
.get()
|
return this.addAuth(request)
|
||||||
|
.get(request)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(_ => {
|
tap(_ => {
|
||||||
localStorage.removeItem(ApiService.tokenKey);
|
localStorage.removeItem(ApiService.tokenKey);
|
||||||
@ -40,11 +43,13 @@ export default class AuthApiService extends ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getRole(isSilence: boolean = true) {
|
public getRole(isSilence: boolean = true) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setSilenceMode(isSilence)
|
.setSilenceMode(isSilence)
|
||||||
.build<ApiService>()
|
.setEndpoint('GetRole')
|
||||||
.addAuth()
|
.build;
|
||||||
.get<AuthRoles>('GetRole')
|
|
||||||
|
return this.addAuth(request)
|
||||||
|
.get<AuthRoles>(request)
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError(_ => {
|
catchError(_ => {
|
||||||
return of(null);
|
return of(null);
|
||||||
|
@ -8,10 +8,11 @@ export class DisciplineService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public getDisciplines(page: number | null = null, pageSize: number | null = null) {
|
public getDisciplines(page: number | null = null, pageSize: number | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setQueryParams({page: page, pageSize: pageSize})
|
.setQueryParams({page: page, pageSize: pageSize})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<DisciplineResponse[]>();
|
|
||||||
|
return this.get<DisciplineResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getById(id: number) {
|
public getById(id: number) {
|
||||||
|
@ -9,10 +9,11 @@ export class FacultyService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public getFaculties(page: number | null = null, pageSize: number | null = null) {
|
public getFaculties(page: number | null = null, pageSize: number | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setQueryParams({page: page, pageSize: pageSize})
|
.setQueryParams({page: page, pageSize: pageSize})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<FacultyResponse[]>();
|
|
||||||
|
return this.get<FacultyResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getById(id: number) {
|
public getById(id: number) {
|
||||||
|
@ -9,10 +9,11 @@ export class GroupService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public getGroups(page: number | null = null, pageSize: number | null = null) {
|
public getGroups(page: number | null = null, pageSize: number | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setQueryParams({page: page, pageSize: pageSize})
|
.setQueryParams({page: page, pageSize: pageSize})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<GroupResponse[]>();
|
|
||||||
|
return this.get<GroupResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getById(id: number) {
|
public getById(id: number) {
|
||||||
|
@ -8,10 +8,11 @@ export class ProfessorService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public getProfessors(page: number | null = null, pageSize: number | null = null) {
|
public getProfessors(page: number | null = null, pageSize: number | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setQueryParams({page: page, pageSize: pageSize})
|
.setQueryParams({page: page, pageSize: pageSize})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<ProfessorResponse[]>();
|
|
||||||
|
return this.get<ProfessorResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getById(id: number) {
|
public getById(id: number) {
|
||||||
|
@ -20,41 +20,46 @@ export class ScheduleService extends ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public postSchedule(data: ScheduleRequest) {
|
public postSchedule(data: ScheduleRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<ScheduleResponse[]>();
|
|
||||||
|
return this.post<ScheduleResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getByGroup(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
public getByGroup(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('GetByGroup/' + id.toString())
|
.setEndpoint('GetByGroup/' + id.toString())
|
||||||
.setQueryParams({isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls})
|
.setQueryParams({isEven: isEven, disciplines: disciplines, professors: professors, lectureHalls: lectureHalls})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<ScheduleResponse[]>();
|
|
||||||
|
return this.get<ScheduleResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getByProfessor(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
public getByProfessor(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('GetByProfessor/' + id.toString())
|
.setEndpoint('GetByProfessor/' + id.toString())
|
||||||
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls})
|
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, lectureHalls: lectureHalls})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<ScheduleResponse[]>();
|
|
||||||
|
return this.get<ScheduleResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getByLectureHall(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) {
|
public getByLectureHall(id: number, isEven: boolean | null = null, disciplines: Array<number> | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('GetByLectureHall/' + id.toString())
|
.setEndpoint('GetByLectureHall/' + id.toString())
|
||||||
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, professors: professors})
|
.setQueryParams({isEven: isEven, disciplines: disciplines, groups: groups, professors: professors})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<ScheduleResponse[]>();
|
|
||||||
|
return this.get<ScheduleResponse[]>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getByDiscipline(id: number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
public getByDiscipline(id: number, isEven: boolean | null = null, groups: Array<number> | null = null, professors: Array<number> | null = null, lectureHalls: Array<number> | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('GetByDiscipline/' + id.toString())
|
.setEndpoint('GetByDiscipline/' + id.toString())
|
||||||
.setQueryParams({isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls})
|
.setQueryParams({isEven: isEven, groups: groups, professors: professors, lectureHalls: lectureHalls})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<ScheduleResponse[]>();
|
|
||||||
|
return this.get<ScheduleResponse[]>(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,101 +14,112 @@ export default class SetupService extends ApiService {
|
|||||||
public readonly version = AvailableVersion.v1;
|
public readonly version = AvailableVersion.v1;
|
||||||
|
|
||||||
public checkToken(token: string) {
|
public checkToken(token: string) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('CheckToken')
|
.setEndpoint('CheckToken')
|
||||||
.setQueryParams({token: token})
|
.setQueryParams({token: token})
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<boolean>();
|
|
||||||
|
return this.get<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPsql(data: DatabaseRequest) {
|
public setPsql(data: DatabaseRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetPsql')
|
.setEndpoint('SetPsql')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setMysql(data: DatabaseRequest) {
|
public setMysql(data: DatabaseRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetMysql')
|
.setEndpoint('SetMysql')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSqlite(path: string | null = null) {
|
public setSqlite(path: string | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetSqlite')
|
.setEndpoint('SetSqlite')
|
||||||
.setQueryParams({path: path})
|
.setQueryParams({path: path})
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.get<boolean>();
|
|
||||||
|
return this.get<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setRedis(data: CacheRequest) {
|
public setRedis(data: CacheRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetRedis')
|
.setEndpoint('SetRedis')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setMemcached() {
|
public setMemcached() {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetMemcached')
|
.setEndpoint('SetMemcached')
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public createAdmin(data: CreateUserRequest) {
|
public createAdmin(data: CreateUserRequest) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('CreateAdmin')
|
.setEndpoint('CreateAdmin')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setLogging(data: LoggingRequest | null = null) {
|
public setLogging(data: LoggingRequest | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetLogging')
|
.setEndpoint('SetLogging')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setEmail(data: EmailRequest | null = null) {
|
public setEmail(data: EmailRequest | null = null) {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetEmail')
|
.setEndpoint('SetEmail')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSchedule(data: ScheduleConfigurationRequest) {
|
public setSchedule(data: ScheduleConfigurationRequest) {
|
||||||
data.startTerm = new DateOnly(data.startTerm).toString();
|
data.startTerm = new DateOnly(data.startTerm).toString();
|
||||||
|
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('SetSchedule')
|
.setEndpoint('SetSchedule')
|
||||||
.setData(data)
|
.setData(data)
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public submit() {
|
public submit() {
|
||||||
return this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('Submit')
|
.setEndpoint('Submit')
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build<ApiService>()
|
.build;
|
||||||
.post<boolean>();
|
|
||||||
|
return this.post<boolean>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isConfigured() {
|
public isConfigured() {
|
||||||
|
@ -4,7 +4,6 @@ import {FooterComponent} from "@component/common/footer/footer.component";
|
|||||||
import localeRu from '@angular/common/locales/ru';
|
import localeRu from '@angular/common/locales/ru';
|
||||||
import {registerLocaleData} from '@angular/common';
|
import {registerLocaleData} from '@angular/common';
|
||||||
import {FocusNextDirective} from "@/directives/focus-next.directive";
|
import {FocusNextDirective} from "@/directives/focus-next.directive";
|
||||||
import {TokenRefreshService} from "@service/token-refresh.service";
|
|
||||||
import {HeaderComponent} from "@component/common/header/header.component";
|
import {HeaderComponent} from "@component/common/header/header.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -17,8 +16,7 @@ import {HeaderComponent} from "@component/common/header/header.component";
|
|||||||
<app-footer/>`
|
<app-footer/>`
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
constructor(tokenRefreshService: TokenRefreshService) {
|
constructor() {
|
||||||
registerLocaleData(localeRu);
|
registerLocaleData(localeRu);
|
||||||
tokenRefreshService.startTokenRefresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
<!--suppress CssInvalidPropertyValue -->
|
<!--suppress CssInvalidPropertyValue -->
|
||||||
<button mat-button [matMenuTriggerFor]="menu" #menuTrigger="matMenuTrigger" [id]="idButton">{{ textButton }}</button>
|
<button mat-button [matMenuTriggerFor]="menu" #menuTrigger="matMenuTrigger" [id]="idButton" style="margin-bottom: 10px;">{{ textButton }}</button>
|
||||||
|
|
||||||
<mat-menu #menu="matMenu" [hasBackdrop]="false" class="menu-options">
|
<mat-menu #menu="matMenu" [hasBackdrop]="false" class="menu-options">
|
||||||
<div (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" style="padding: 0 15px 15px">
|
<div (click)="$event.stopPropagation()" (keydown)="$event.stopPropagation()" style="padding: 0 15px 15px">
|
||||||
<div class="header-menu">
|
<div class="header-menu">
|
||||||
<mat-form-field appearance="outline" color="accent" style="display:flex;">
|
<mat-form-field appearance="outline" color="accent" style="display:flex;">
|
||||||
<input matInput placeholder="Поиск..." [(ngModel)]="searchQuery" [disabled]="data.length === 0">
|
<input matInput placeholder="Поиск..." [(ngModel)]="searchQuery" [disabled]="data === null || data.length === 0">
|
||||||
<button mat-icon-button matSuffix (click)="clearSearchQuery()" [disabled]="data.length === 0">
|
<button mat-icon-button matSuffix (click)="clearSearchQuery()" [disabled]="data === null || data.length === 0">
|
||||||
<mat-icon style="color: var(--mdc-filled-button-label-text-color);">close</mat-icon>
|
<mat-icon style="color: var(--mdc-filled-button-label-text-color);">close</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<mat-checkbox (click)="checkData()" [disabled]="data.length === 0" #chooseCheckbox/>
|
<mat-checkbox (click)="checkData()" [disabled]="data === null || data.length === 0" #chooseCheckbox/>
|
||||||
<button mat-button (click)="clearAll()" [disabled]="data.length === 0">Очистить</button>
|
<button mat-button (click)="clearAll()" [disabled]="data === null || data.length === 0">Очистить</button>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
@if (data.length === 0) {
|
@if (data === null || data.length === 0) {
|
||||||
<app-loading-indicator style="display: flex; justify-content: center;" [loading]="dataLoaded !== null"
|
<app-loading-indicator style="display: flex; justify-content: center;" [loading]="data === null"
|
||||||
(retryFunction)="retryLoadData.emit()"/>
|
(retryFunction)="retryLoadData.emit()"/>
|
||||||
} @else {
|
} @else {
|
||||||
<mat-selection-list>
|
<mat-selection-list>
|
||||||
|
@ -47,17 +47,19 @@ export interface SelectData {
|
|||||||
export class OtherComponent {
|
export class OtherComponent {
|
||||||
private _searchQuery: string = '';
|
private _searchQuery: string = '';
|
||||||
protected filteredData: BehaviorSubject<SelectData[]> = new BehaviorSubject<SelectData[]>([]);
|
protected filteredData: BehaviorSubject<SelectData[]> = new BehaviorSubject<SelectData[]>([]);
|
||||||
protected data: SelectData[] = [];
|
protected data: SelectData[] | null = null;
|
||||||
|
|
||||||
@Input() idButton!: string;
|
@Input() idButton!: string;
|
||||||
@Input() textButton!: string;
|
@Input() textButton!: string;
|
||||||
@ViewChild('menuTrigger') menuTrigger!: MatMenuTrigger;
|
@ViewChild('menuTrigger') menuTrigger!: MatMenuTrigger;
|
||||||
@ViewChild('chooseCheckbox') chooseCheckbox!: MatCheckbox;
|
@ViewChild('chooseCheckbox') chooseCheckbox!: MatCheckbox;
|
||||||
|
|
||||||
@Input() dataLoaded: boolean | null = false;
|
|
||||||
@Output() retryLoadData: EventEmitter<void> = new EventEmitter<void>();
|
@Output() retryLoadData: EventEmitter<void> = new EventEmitter<void>();
|
||||||
|
|
||||||
get selectedIds(): number[] {
|
get selectedIds(): number[] {
|
||||||
|
if (this.data === null)
|
||||||
|
return [];
|
||||||
|
|
||||||
return this.data.filter(x => x.selected).map(x => x.id);
|
return this.data.filter(x => x.selected).map(x => x.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +74,9 @@ export class OtherComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateCheckBox() {
|
private updateCheckBox() {
|
||||||
|
if (this.data === null)
|
||||||
|
return;
|
||||||
|
|
||||||
this.chooseCheckbox.checked = this.data.every(x => x.selected);
|
this.chooseCheckbox.checked = this.data.every(x => x.selected);
|
||||||
this.chooseCheckbox.indeterminate = this.data.some(x => x.selected) && !this.chooseCheckbox.checked;
|
this.chooseCheckbox.indeterminate = this.data.some(x => x.selected) && !this.chooseCheckbox.checked;
|
||||||
}
|
}
|
||||||
@ -82,6 +87,9 @@ export class OtherComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected updateFilteredData(): void {
|
protected updateFilteredData(): void {
|
||||||
|
if (this.data === null)
|
||||||
|
return;
|
||||||
|
|
||||||
this.filteredData.next(this.data.filter(x =>
|
this.filteredData.next(this.data.filter(x =>
|
||||||
x.name.toLowerCase().includes(this.searchQuery.toLowerCase())
|
x.name.toLowerCase().includes(this.searchQuery.toLowerCase())
|
||||||
));
|
));
|
||||||
@ -92,7 +100,7 @@ export class OtherComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected clearAll(): void {
|
protected clearAll(): void {
|
||||||
this.data.forEach(x => x.selected = false);
|
this.data?.forEach(x => x.selected = false);
|
||||||
|
|
||||||
if (this.searchQuery !== '') {
|
if (this.searchQuery !== '') {
|
||||||
const updatedData = this.filteredData.value.map(x => {
|
const updatedData = this.filteredData.value.map(x => {
|
||||||
@ -109,7 +117,7 @@ export class OtherComponent {
|
|||||||
const check: boolean = this.filteredData.value.some(x => !x.selected) && !this.filteredData.value.every(x => x.selected);
|
const check: boolean = this.filteredData.value.some(x => !x.selected) && !this.filteredData.value.every(x => x.selected);
|
||||||
|
|
||||||
const updatedData = this.filteredData.value.map(data => {
|
const updatedData = this.filteredData.value.map(data => {
|
||||||
this.data.find(x => x.id === data.id)!.selected = check;
|
this.data!.find(x => x.id === data.id)!.selected = check;
|
||||||
return {...data, selected: check};
|
return {...data, selected: check};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,7 +126,7 @@ export class OtherComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected checkboxStateChange(item: number) {
|
protected checkboxStateChange(item: number) {
|
||||||
const data = this.data.find(x => x.id === item)!;
|
const data = this.data!.find(x => x.id === item)!;
|
||||||
data.selected = !data.selected;
|
data.selected = !data.selected;
|
||||||
const updatedData = this.filteredData.value;
|
const updatedData = this.filteredData.value;
|
||||||
updatedData.find(x => x.id === item)!.selected = data.selected;
|
updatedData.find(x => x.id === item)!.selected = data.selected;
|
||||||
|
@ -20,7 +20,7 @@ export class HasRoleDirective {
|
|||||||
|
|
||||||
this.authService
|
this.authService
|
||||||
.getRole()
|
.getRole()
|
||||||
.pipe(catchError(error => {
|
.pipe(catchError(_ => {
|
||||||
this.viewContainer.clear();
|
this.viewContainer.clear();
|
||||||
return of(null);
|
return of(null);
|
||||||
}))
|
}))
|
||||||
|
@ -40,11 +40,11 @@ export class LoginComponent {
|
|||||||
protected loginButtonIsDisable: boolean = true;
|
protected loginButtonIsDisable: boolean = true;
|
||||||
protected errorText: string = '';
|
protected errorText: string = '';
|
||||||
|
|
||||||
constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private route: Router) {
|
constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private router: Router) {
|
||||||
this.auth.getRole()
|
this.auth.getRole()
|
||||||
.subscribe(data => {
|
.subscribe(data => {
|
||||||
if (data !== null)
|
if (data !== null)
|
||||||
route.navigate(['admin']).then();
|
router.navigate(['admin']).then();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.loginForm = this.formBuilder.group({
|
this.loginForm = this.formBuilder.group({
|
||||||
@ -89,7 +89,7 @@ export class LoginComponent {
|
|||||||
.subscribe(_ => {
|
.subscribe(_ => {
|
||||||
this.loaderActive = false;
|
this.loaderActive = false;
|
||||||
this.errorText = '';
|
this.errorText = '';
|
||||||
this.route.navigate(['admin']).then();
|
this.router.navigate(['admin']).then();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import {Component} from '@angular/core';
|
|||||||
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||||
import {NavigationService} from "@service/navigation.service";
|
import {NavigationService} from "@service/navigation.service";
|
||||||
import SetupService from "@api/v1/setup.service";
|
import SetupService from "@api/v1/setup.service";
|
||||||
import {DateAdapter, MatNativeDateModule} from "@angular/material/core";
|
import {MAT_DATE_LOCALE, MatNativeDateModule} from "@angular/material/core";
|
||||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||||
import {MatSelectModule} from "@angular/material/select";
|
import {MatSelectModule} from "@angular/material/select";
|
||||||
import {MatInput} from "@angular/material/input";
|
import {MatInput} from "@angular/material/input";
|
||||||
@ -25,17 +25,16 @@ import {MatDatepickerModule} from "@angular/material/datepicker";
|
|||||||
MatDatepickerModule,
|
MatDatepickerModule,
|
||||||
MatNativeDateModule
|
MatNativeDateModule
|
||||||
],
|
],
|
||||||
templateUrl: './schedule.component.html'
|
templateUrl: './schedule.component.html',
|
||||||
|
providers: [{provide: MAT_DATE_LOCALE, useValue: 'ru-RU'}]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class ScheduleComponent {
|
export class ScheduleComponent {
|
||||||
protected scheduleSettings!: FormGroup;
|
protected scheduleSettings!: FormGroup;
|
||||||
|
|
||||||
constructor(
|
constructor(private navigationService: NavigationService, formBuilder: FormBuilder, private api: SetupService) {
|
||||||
private navigationService: NavigationService, private formBuilder: FormBuilder, private api: SetupService, private _adapter: DateAdapter<any>) {
|
this.scheduleSettings = formBuilder.group({
|
||||||
this._adapter.setLocale('ru');
|
cron: ['0 */6 * * *', Validators.pattern(/^(\S+\s){4}\S$/)],
|
||||||
this.scheduleSettings = this.formBuilder.group({
|
|
||||||
cron: ['0 */6 * * *', Validators.pattern(/^([^\s]+\s){4}[^\s]{1}$/)],
|
|
||||||
startTerm: ['', Validators.required]
|
startTerm: ['', Validators.required]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {EventEmitter, Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
import {HttpClient, HttpHeaders} from "@angular/common/http";
|
||||||
import {Observable, tap} from "rxjs";
|
import {map, Observable, throwError} from "rxjs";
|
||||||
import {TokenResponse} from "@api/v1/tokenResponse";
|
import {TokenResponse} from "@api/v1/tokenResponse";
|
||||||
import ApiService from "@api/api.service";
|
import ApiService from "@api/api.service";
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ export class AuthToken {
|
|||||||
this.endpoint = refreshEndpoint;
|
this.endpoint = refreshEndpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
static httpHeader(token: AuthToken): HttpHeaders {
|
public static httpHeader(token: AuthToken): HttpHeaders {
|
||||||
let header = new HttpHeaders();
|
let header = new HttpHeaders();
|
||||||
|
|
||||||
if (token.authProvider === AvailableAuthenticationProvider.Bearer)
|
if (token.authProvider === AvailableAuthenticationProvider.Bearer)
|
||||||
@ -35,8 +35,6 @@ export class AuthToken {
|
|||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
public expireTokenChange = new EventEmitter<Date>();
|
|
||||||
|
|
||||||
constructor(private http: HttpClient) {
|
constructor(private http: HttpClient) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,12 +54,11 @@ export class AuthService {
|
|||||||
return result <= new Date() ? new Date() : result;
|
return result <= new Date() ? new Date() : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public refreshToken(): Observable<TokenResponse> {
|
public refreshToken(): Observable<Date> {
|
||||||
const token = localStorage.getItem(ApiService.tokenKey);
|
const token = localStorage.getItem(ApiService.tokenKey);
|
||||||
|
|
||||||
console.log(token);
|
|
||||||
if (!token)
|
if (!token)
|
||||||
throw new Error("token is not found");
|
return throwError(() => new Error("Token is not found"));
|
||||||
|
|
||||||
const authToken = JSON.parse(token) as AuthToken;
|
const authToken = JSON.parse(token) as AuthToken;
|
||||||
|
|
||||||
@ -69,14 +66,16 @@ export class AuthService {
|
|||||||
case AvailableAuthenticationProvider.Bearer:
|
case AvailableAuthenticationProvider.Bearer:
|
||||||
return this.http.get<TokenResponse>(authToken.endpoint, {withCredentials: true})
|
return this.http.get<TokenResponse>(authToken.endpoint, {withCredentials: true})
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(response => {
|
map(response => {
|
||||||
const newExpireDate = new Date(response.expiresIn);
|
const newExpireDate = new Date(response.expiresIn);
|
||||||
const oldExpireDate = new Date(authToken.expiresIn);
|
const oldExpireDate = new Date(authToken.expiresIn);
|
||||||
|
|
||||||
if (newExpireDate.getTime() !== oldExpireDate.getTime()) {
|
if (newExpireDate.getTime() !== oldExpireDate.getTime()) {
|
||||||
AuthService.setToken(response, AvailableAuthenticationProvider.Bearer, authToken.endpoint);
|
AuthService.setToken(response, AvailableAuthenticationProvider.Bearer, authToken.endpoint);
|
||||||
this.expireTokenChange.emit(newExpireDate);
|
return newExpireDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return newExpireDate;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {BehaviorSubject, filter, interval, Subscription, switchMap} from "rxjs";
|
import {BehaviorSubject, catchError, of, Subject} from "rxjs";
|
||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {AuthService} from "@service/auth.service";
|
import {AuthService} from "@service/auth.service";
|
||||||
import {environment} from "@environment";
|
import {environment} from "@environment";
|
||||||
@ -8,64 +8,75 @@ import ApiService from "@api/api.service";
|
|||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class TokenRefreshService {
|
export class TokenRefreshService {
|
||||||
private tokenRefreshSubscription: Subscription | undefined;
|
|
||||||
private tokenRefreshing$ = new BehaviorSubject<boolean>(false);
|
private tokenRefreshing$ = new BehaviorSubject<boolean>(false);
|
||||||
|
private refreshTokenTimeout: any;
|
||||||
private refreshTokenExpireMs: number = environment.retryDelay;
|
private refreshTokenExpireMs: number = environment.retryDelay;
|
||||||
|
|
||||||
constructor(private authService: AuthService) {
|
constructor(private authService: AuthService) {
|
||||||
this.setRefreshTokenExpireMs(AuthService.tokenExpiresIn.getTime() - 1000 - Date.now());
|
this.setRefreshTokenExpireMs(AuthService.tokenExpiresIn);
|
||||||
|
|
||||||
authService.expireTokenChange.subscribe(date => {
|
|
||||||
console.debug('Expire token change event received:', date);
|
|
||||||
this.setRefreshTokenExpireMs(date.getTime() - 1000 - Date.now());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public startTokenRefresh(date: Date | null = null): void {
|
private startTokenRefresh(): void {
|
||||||
if (date)
|
this.refreshTokenTimeout = setTimeout(() => {
|
||||||
this.refreshTokenExpireMs = new Date(date).getTime() - 1000 - Date.now();
|
this.refreshToken();
|
||||||
|
}, this.refreshTokenExpireMs);
|
||||||
|
}
|
||||||
|
|
||||||
console.debug(this.tokenRefreshSubscription);
|
private refreshToken(): void {
|
||||||
if (this.tokenRefreshSubscription && !this.tokenRefreshSubscription.closed)
|
if (this.tokenRefreshing$.value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.tokenRefreshSubscription = interval(this.refreshTokenExpireMs).pipe(
|
this.tokenRefreshing$.next(true);
|
||||||
filter(isRefreshing => !isRefreshing),
|
|
||||||
switchMap(() => {
|
this.authService.refreshToken()
|
||||||
this.tokenRefreshing$.next(true);
|
.pipe(
|
||||||
console.debug('Send query to refresh token');
|
catchError(error => {
|
||||||
return this.authService.refreshToken();
|
if (error.status === 403 || error.status === 401 || !localStorage.getItem(ApiService.tokenKey)) {
|
||||||
})
|
localStorage.removeItem(ApiService.tokenKey);
|
||||||
).subscribe({
|
return of(undefined);
|
||||||
next: (_) => {
|
}
|
||||||
|
|
||||||
|
let retryTime = this.refreshTokenExpireMs;
|
||||||
|
|
||||||
|
if (retryTime < environment.retryDelay)
|
||||||
|
retryTime = environment.retryDelay;
|
||||||
|
|
||||||
|
// 15 minutes
|
||||||
|
if (retryTime * 2 <= 900_000)
|
||||||
|
retryTime *= 2;
|
||||||
|
else
|
||||||
|
retryTime = 900_000;
|
||||||
|
|
||||||
|
return of(retryTime);
|
||||||
|
}))
|
||||||
|
.subscribe(data => {
|
||||||
|
if (data)
|
||||||
|
this.setRefreshTokenExpireMs(data);
|
||||||
|
|
||||||
this.tokenRefreshing$.next(false);
|
this.tokenRefreshing$.next(false);
|
||||||
},
|
});
|
||||||
error: error => {
|
|
||||||
this.tokenRefreshing$.next(false);
|
|
||||||
localStorage.removeItem(ApiService.tokenKey);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTokenRefreshing$(): BehaviorSubject<boolean> {
|
public getTokenRefreshing$(): Subject<boolean> {
|
||||||
return this.tokenRefreshing$;
|
return this.tokenRefreshing$;
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopTokenRefresh(): void {
|
public setRefreshTokenExpireMs(expireMs: number | string | Date | null = null): void {
|
||||||
if (this.tokenRefreshSubscription && !this.tokenRefreshSubscription.closed) {
|
let expireMsNumber: number;
|
||||||
this.tokenRefreshSubscription.unsubscribe();
|
if (expireMs === null)
|
||||||
this.tokenRefreshSubscription = undefined;
|
expireMsNumber = -1;
|
||||||
}
|
else if (expireMs instanceof Date || typeof expireMs === 'string')
|
||||||
}
|
expireMsNumber = new Date(expireMs).getTime() - 1000 - Date.now();
|
||||||
|
else
|
||||||
|
expireMsNumber = expireMs;
|
||||||
|
|
||||||
public setRefreshTokenExpireMs(expireMs: number): void {
|
if (expireMsNumber < environment.retryDelay)
|
||||||
if (expireMs < environment.retryDelay)
|
expireMsNumber = environment.retryDelay;
|
||||||
expireMs = environment.retryDelay;
|
|
||||||
|
|
||||||
this.refreshTokenExpireMs = expireMs;
|
this.refreshTokenExpireMs = expireMsNumber;
|
||||||
|
console.log('New refresh token interval:', this.refreshTokenExpireMs);
|
||||||
|
|
||||||
console.log(expireMs);
|
clearTimeout(this.refreshTokenTimeout);
|
||||||
this.stopTokenRefresh();
|
|
||||||
this.startTokenRefresh();
|
this.startTokenRefresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user