Compare commits
6 Commits
8138a63324
...
eda6ca4b1a
Author | SHA1 | Date | |
---|---|---|---|
eda6ca4b1a | |||
10bf53adec | |||
e10075dfed | |||
2b482d2b2d | |||
9017e87175 | |||
16e25905dc |
@ -158,7 +158,7 @@ export default abstract class ApiService {
|
||||
|
||||
private handleError(error: HttpErrorResponse): void {
|
||||
// todo: change to Retry-After condition
|
||||
if (error.error && error.error.toString().includes("setup")) {
|
||||
if (error.error && error.error.detail.includes("setup")) {
|
||||
this.router.navigate(['/setup/']).then();
|
||||
return;
|
||||
}
|
||||
@ -167,6 +167,10 @@ export default abstract class ApiService {
|
||||
let message: string | undefined = undefined;
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
title = `Произошла ошибка: ${error.error.message}`;
|
||||
} else {
|
||||
if (error.error && error.error.type && error.error.title) {
|
||||
title = error.error.title || `Ошибка с кодом ${error.status}`;
|
||||
message = error.error.detail || 'Неизвестная ошибка';
|
||||
} else {
|
||||
switch (error.status) {
|
||||
case 0:
|
||||
@ -195,11 +199,9 @@ export default abstract class ApiService {
|
||||
title = `Сервер вернул код ошибки: ${error.status}`;
|
||||
break;
|
||||
}
|
||||
if (error.error?.Error)
|
||||
message = error.error.Error;
|
||||
else if (error.error instanceof String)
|
||||
message = error.error.toString();
|
||||
else
|
||||
}
|
||||
|
||||
if (!message)
|
||||
message = error.error.statusMessage;
|
||||
}
|
||||
this.notify.error(message == '' ? undefined : message, title);
|
||||
|
@ -75,3 +75,11 @@
|
||||
.provider-item.provider-unlink:hover::after {
|
||||
transform: translate(-50%, -50%) scale(1.0);
|
||||
}
|
||||
|
||||
.provider-item .provider-spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(1.0);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
@ -6,9 +6,13 @@
|
||||
<div class="provider-container">
|
||||
@for (provider of providers; track $index) {
|
||||
<a class="provider-item" (click)="provider.disabled ? confirmDelete(provider) : openOAuth(provider)"
|
||||
[class.disabled]="!canUnlink && provider.disabled" [class.provider-unlink]="canUnlink && provider.disabled">
|
||||
[class.disabled]="!canUnlink && provider.disabled || provider.active"
|
||||
[class.provider-unlink]="canUnlink && provider.disabled">
|
||||
<img [alt]="provider.providerName" [src]="provider.icon"
|
||||
class="provider-icon" draggable="false"/>
|
||||
@if (provider.active) {
|
||||
<app-data-spinner class="provider-spinner"/>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Component, Inject, Input, OnInit} from '@angular/core';
|
||||
import {Component, EventEmitter, Inject, Input, Output} from '@angular/core';
|
||||
import AuthApiService, {OAuthProviderData} from "@api/v1/authApiService";
|
||||
import {OAuthProvider} from "@model/oAuthProvider";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
@ -10,9 +10,11 @@ import {
|
||||
MatDialogTitle
|
||||
} from "@angular/material/dialog";
|
||||
import {MatButton} from "@angular/material/button";
|
||||
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
||||
|
||||
interface AvailableOAuthProviders extends OAuthProviderData {
|
||||
disabled: boolean;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
@ -53,17 +55,24 @@ export class DeleteConfirmDialog {
|
||||
|
||||
@Component({
|
||||
selector: 'OAuthProviders',
|
||||
imports: [],
|
||||
imports: [
|
||||
DataSpinnerComponent
|
||||
],
|
||||
templateUrl: './OAuthProviders.html',
|
||||
styleUrl: './OAuthProviders.css',
|
||||
providers: [AuthApiService]
|
||||
})
|
||||
export class OAuthProviders implements OnInit {
|
||||
export class OAuthProviders {
|
||||
protected providers: AvailableOAuthProviders[] = [];
|
||||
protected _activeProvidersId: OAuthProvider[] = [];
|
||||
protected _activeProviders: string[] = [];
|
||||
|
||||
@Input() message: string = 'Вы можете войти в аккаунт через';
|
||||
@Input() activeProviders: string[] = [];
|
||||
|
||||
@Input() set activeProviders(data: string[]) {
|
||||
this._activeProviders = data;
|
||||
this.updateDisabledProviders();
|
||||
}
|
||||
|
||||
@Input() set activeProvidersId(data: OAuthProvider[]) {
|
||||
this._activeProvidersId = data;
|
||||
@ -72,6 +81,8 @@ export class OAuthProviders implements OnInit {
|
||||
|
||||
@Input() canUnlink: boolean = false;
|
||||
|
||||
@Output() public oAuthUpdateProviders = new EventEmitter();
|
||||
|
||||
constructor(authApi: AuthApiService, private notify: ToastrService, private dialog: MatDialog) {
|
||||
authApi.availableProviders().subscribe(providers => this.updateDisabledProviders(providers));
|
||||
}
|
||||
@ -80,23 +91,12 @@ export class OAuthProviders implements OnInit {
|
||||
this.providers = (data ?? this.providers).map(provider => {
|
||||
return {
|
||||
...provider,
|
||||
disabled: this._activeProvidersId.includes(provider.provider) || this.activeProviders.includes(provider.providerName)
|
||||
disabled: this._activeProvidersId.includes(provider.provider) || this._activeProviders.includes(provider.providerName),
|
||||
active: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data && event.data.success === false) {
|
||||
console.error(event.data.message);
|
||||
this.notify.error(event.data.message, 'OAuth ошибка');
|
||||
} else {
|
||||
this.activeProvidersId.push(event.data.provider);
|
||||
this.updateDisabledProviders();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected openOAuth(provider: AvailableOAuthProviders) {
|
||||
console.log(provider.redirect);
|
||||
const oauthWindow = window.open(
|
||||
@ -108,6 +108,16 @@ export class OAuthProviders implements OnInit {
|
||||
this.notify.error('Не удалось открыть OAuth окно');
|
||||
return;
|
||||
}
|
||||
|
||||
provider.active = true;
|
||||
|
||||
const checkInterval = setInterval(() => {
|
||||
if (oauthWindow.closed) {
|
||||
clearInterval(checkInterval);
|
||||
this.oAuthUpdateProviders.emit();
|
||||
provider.active = false;
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
protected confirmDelete(provider: AvailableOAuthProviders) {
|
||||
|
@ -82,7 +82,7 @@ export class LoginComponent {
|
||||
})
|
||||
.pipe(catchError(error => {
|
||||
this.loaderActive = false;
|
||||
this.errorText = error.error instanceof String ? error.error : error.statusText;
|
||||
this.errorText = error.error instanceof String ? error.statusText : error.error;
|
||||
this.loginButtonIsDisable = true;
|
||||
throw error;
|
||||
}))
|
||||
|
@ -116,7 +116,7 @@
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<OAuthProviders [canUnlink]="true" [activeProvidersId]="activatedProviders"
|
||||
<OAuthProviders [canUnlink]="true" [activeProvidersId]="activatedProviders" (oAuthUpdateProviders)="updateProviders()"
|
||||
[message]="'Или можете получить часть данных от сторонних сервисов'"/>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -70,9 +70,16 @@ export class CreateAdminComponent {
|
||||
this.createAdminForm.get('password')?.updateValueAndValidity();
|
||||
});
|
||||
|
||||
this.updateAdminData();
|
||||
}
|
||||
|
||||
private updateAdminData() {
|
||||
this.api.adminConfiguration().subscribe(configuration => {
|
||||
if (configuration) {
|
||||
if (this.createAdminForm.get('email')?.value == 0)
|
||||
this.createAdminForm.get('email')?.setValue(configuration.email);
|
||||
|
||||
if (this.createAdminForm.get('user')?.value == 0)
|
||||
this.createAdminForm.get('user')?.setValue(configuration.username);
|
||||
|
||||
this.activatedProviders = configuration.usedOAuthProviders;
|
||||
@ -111,4 +118,8 @@ export class CreateAdminComponent {
|
||||
this.hideRetypePass = !this.hideRetypePass;
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
protected updateProviders() {
|
||||
this.updateAdminData();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,11 @@
|
||||
Настройте систему логирования как будет удобно для отображения.
|
||||
Можно настроить путь к файлу, имена файлов или вовсе отключить логирование в файл.
|
||||
</p>
|
||||
<p class="mat-body-2 secondary">
|
||||
Также вы можете настроить интеграцию с Seq.
|
||||
Введите необходимые данные и мы отправим тестовый лог на сервер Seq. Его уровень будет Warning.
|
||||
Если тестовый лог не появился вернитесь на данный шаг и перепроверьте данные.
|
||||
</p>
|
||||
|
||||
<form [formGroup]="loggingSettings">
|
||||
<p>
|
||||
@ -31,5 +36,18 @@
|
||||
matTooltip="Укажите название файла, в который будут записаны логи"
|
||||
formControlName="logName">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field color="accent">
|
||||
<mat-label>Сервер Seq</mat-label>
|
||||
<input matInput
|
||||
matTooltip="Укажите сервер Seq вначале указав схему (http/https)"
|
||||
formControlName="seqServer">
|
||||
</mat-form-field>
|
||||
<mat-form-field color="accent">
|
||||
<mat-label>Api ключ Seq</mat-label>
|
||||
<input matInput
|
||||
matTooltip="Укажите ключ API, который вы создали в Seq"
|
||||
formControlName="seqKey">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -45,7 +45,9 @@ export class LoggingComponent {
|
||||
this.loggingSettings = this.formBuilder.group({
|
||||
enabled: [true, Validators.required],
|
||||
logPath: [''],
|
||||
logName: ['']
|
||||
logName: [''],
|
||||
seqServer: [''],
|
||||
seqKey: ['']
|
||||
}
|
||||
);
|
||||
|
||||
@ -56,9 +58,11 @@ export class LoggingComponent {
|
||||
|
||||
this.navigationService.nextButtonAction = () => {
|
||||
return this.api.setLogging({
|
||||
"enableLogToFile": this.loggingSettings.get('enabled')?.value,
|
||||
"logFileName": this.loggingSettings.get('logName')?.value,
|
||||
"logFilePath": this.loggingSettings.get('logPath')?.value
|
||||
enableLogToFile: this.loggingSettings.get('enabled')?.value,
|
||||
logFileName: this.loggingSettings.get('logName')?.value,
|
||||
logFilePath: this.loggingSettings.get('logPath')?.value,
|
||||
apiServerSeq: this.loggingSettings.get('seqServer')?.value,
|
||||
apiKeySeq: this.loggingSettings.get('seqKey')?.value
|
||||
}
|
||||
);
|
||||
};
|
||||
@ -73,6 +77,8 @@ export class LoggingComponent {
|
||||
this.loggingSettings.get('enabled')?.setValue(x.enableLogToFile);
|
||||
this.loggingSettings.get('logName')?.setValue(x.logFileName);
|
||||
this.loggingSettings.get('logPath')?.setValue(x.logFilePath);
|
||||
this.loggingSettings.get('seqServer')?.setValue(x.apiServerSeq);
|
||||
this.loggingSettings.get('seqKey')?.setValue(x.apiKeySeq);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,16 @@
|
||||
Путь к файлу журнала: {{ loggingConfig.logFilePath }}
|
||||
</div>
|
||||
}
|
||||
@if (loggingConfig.apiServerSeq) {
|
||||
<div>
|
||||
Сервер Seq: {{ loggingConfig.apiServerSeq }}
|
||||
</div>
|
||||
}
|
||||
@if (loggingConfig.apiKeySeq) {
|
||||
<div>
|
||||
Ключ Seq: {{ loggingConfig.apiKeySeq }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
<h3>Ваш код: <i><strong>{{ secret }}</strong></i></h3>
|
||||
|
||||
<div>
|
||||
<img [src]="totpImage" alt="totp-qr-code"/>
|
||||
<img [src]="totpImage" alt="totp-qr-code" style="max-height: 60vh;"/>
|
||||
</div>
|
||||
|
||||
<form [formGroup]="twoFactorForm">
|
||||
|
@ -2,4 +2,6 @@ export interface LoggingRequest {
|
||||
enableLogToFile: boolean;
|
||||
logFileName?: string;
|
||||
logFilePath?: string;
|
||||
apiServerSeq?: string;
|
||||
apiKeySeq?: string;
|
||||
}
|
||||
|
Reference in New Issue
Block a user