Compare commits
5 Commits
a8b1485b0e
...
fcd179166e
Author | SHA1 | Date | |
---|---|---|---|
fcd179166e | |||
224d7a3443 | |||
2370a2051b | |||
1d691ccc09 | |||
a7542eaf32 |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b10",
|
"version": "1.0.0-rc0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b10",
|
"version": "1.0.0-rc0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.0.5",
|
"@angular/animations": "^19.0.5",
|
||||||
"@angular/cdk": "~19.0.4",
|
"@angular/cdk": "~19.0.4",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "frontend",
|
"name": "frontend",
|
||||||
"version": "1.0.0-b10",
|
"version": "1.0.0-rc0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
|
@ -7,6 +7,7 @@ import {AvailableOAuthProvidersResponse} from "@api/v1/availableProvidersRespons
|
|||||||
import {OAuthProvider} from "@model/oAuthProvider";
|
import {OAuthProvider} from "@model/oAuthProvider";
|
||||||
import {TwoFactorAuthentication} from "@model/twoFactorAuthentication";
|
import {TwoFactorAuthentication} from "@model/twoFactorAuthentication";
|
||||||
import {TwoFactorAuthRequest} from "@api/v1/twoFactorAuthRequest";
|
import {TwoFactorAuthRequest} from "@api/v1/twoFactorAuthRequest";
|
||||||
|
import {OAuthAction} from "@model/oAuthAction";
|
||||||
|
|
||||||
export interface OAuthProviderData extends AvailableOAuthProvidersResponse {
|
export interface OAuthProviderData extends AvailableOAuthProvidersResponse {
|
||||||
icon: string;
|
icon: string;
|
||||||
@ -83,9 +84,10 @@ export default class AuthApiService extends ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public availableProviders(): Observable<OAuthProviderData[]> {
|
public availableProviders(callback: string): Observable<OAuthProviderData[]> {
|
||||||
let request = this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('AvailableProviders')
|
.setEndpoint('AvailableProviders')
|
||||||
|
.setQueryParams({callback: callback})
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build;
|
.build;
|
||||||
|
|
||||||
@ -97,4 +99,21 @@ export default class AuthApiService extends ApiService {
|
|||||||
}) as OAuthProviderData);
|
}) as OAuthProviderData);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private handleTokenRequest(token: string, action: OAuthAction) {
|
||||||
|
return this.createRequestBuilder()
|
||||||
|
.setEndpoint('HandleToken')
|
||||||
|
.setQueryParams({token: token, action: action})
|
||||||
|
.setWithCredentials()
|
||||||
|
.build;
|
||||||
|
}
|
||||||
|
|
||||||
|
public loginOAuth(token: string) {
|
||||||
|
return this.get<TwoFactorAuthentication>(this.handleTokenRequest(token, OAuthAction.Login));
|
||||||
|
}
|
||||||
|
|
||||||
|
public linkAccount(token: string): Observable<null> {
|
||||||
|
const request = this.handleTokenRequest(token, OAuthAction.Bind);
|
||||||
|
return this.addAuth(request).get(request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import ApiService, {AvailableVersion} from "@api/api.service";
|
import ApiService, {AvailableVersion} from "@api/api.service";
|
||||||
import {catchError, of, switchMap} from "rxjs";
|
import {catchError, of} from "rxjs";
|
||||||
import {DatabaseResponse} from "@api/v1/configuration/databaseResponse";
|
import {DatabaseResponse} from "@api/v1/configuration/databaseResponse";
|
||||||
import {DatabaseRequest} from "@api/v1/configuration/databaseRequest";
|
import {DatabaseRequest} from "@api/v1/configuration/databaseRequest";
|
||||||
import {CacheRequest} from "@api/v1/configuration/cacheRequest";
|
import {CacheRequest} from "@api/v1/configuration/cacheRequest";
|
||||||
@ -137,18 +137,21 @@ export default class SetupService extends ApiService {
|
|||||||
|
|
||||||
public adminConfiguration() {
|
public adminConfiguration() {
|
||||||
let request = this.createRequestBuilder()
|
let request = this.createRequestBuilder()
|
||||||
.setEndpoint('UpdateAdminConfiguration')
|
.setEndpoint('AdminConfiguration')
|
||||||
.setWithCredentials()
|
.setWithCredentials()
|
||||||
.build;
|
.build;
|
||||||
|
|
||||||
return this.get(request).pipe(switchMap(_ => {
|
return this.get<UserResponse>(request);
|
||||||
request = this.createRequestBuilder()
|
}
|
||||||
.setEndpoint('AdminConfiguration')
|
|
||||||
.setWithCredentials()
|
|
||||||
.build;
|
|
||||||
|
|
||||||
return this.get<UserResponse>(request);
|
public registerOAuth(token: string) {
|
||||||
}));
|
let request = this.createRequestBuilder()
|
||||||
|
.setEndpoint('HandleToken')
|
||||||
|
.setQueryParams({token: token})
|
||||||
|
.setWithCredentials()
|
||||||
|
.build;
|
||||||
|
|
||||||
|
return this.get<null>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setLogging(data: LoggingRequest | null = null) {
|
public setLogging(data: LoggingRequest | null = null) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
@if (providers.length !== 0) {
|
@if (!loading && providers.length !== 0) {
|
||||||
<hr/>
|
<hr/>
|
||||||
<div>
|
<div>
|
||||||
<p class="mat-body-2 secondary">{{ message }}</p>
|
<p class="mat-body-2 secondary">{{ message }}</p>
|
||||||
@ -17,4 +17,7 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
} @else if (loading) {
|
||||||
|
<hr/>
|
||||||
|
<app-data-spinner style="display: flex; justify-content: center;"/>
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import {Component, EventEmitter, Inject, Input, Output} from '@angular/core';
|
import {Component, EventEmitter, Inject, Input, OnInit, Output} from '@angular/core';
|
||||||
import AuthApiService, {OAuthProviderData} from "@api/v1/authApiService";
|
import AuthApiService, {OAuthProviderData} from "@api/v1/authApiService";
|
||||||
import {OAuthProvider} from "@model/oAuthProvider";
|
import {OAuthProvider} from "@model/oAuthProvider";
|
||||||
import {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
import {
|
import {
|
||||||
MAT_DIALOG_DATA, MatDialog,
|
MAT_DIALOG_DATA,
|
||||||
|
MatDialog,
|
||||||
MatDialogActions,
|
MatDialogActions,
|
||||||
MatDialogContent,
|
MatDialogContent,
|
||||||
MatDialogRef,
|
MatDialogRef,
|
||||||
@ -11,6 +12,11 @@ import {
|
|||||||
} from "@angular/material/dialog";
|
} from "@angular/material/dialog";
|
||||||
import {MatButton} from "@angular/material/button";
|
import {MatButton} from "@angular/material/button";
|
||||||
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
||||||
|
import {ActivatedRoute} from "@angular/router";
|
||||||
|
import {catchError, finalize, Observable, switchMap, tap} from "rxjs";
|
||||||
|
import {TwoFactorAuthentication} from "@model/twoFactorAuthentication";
|
||||||
|
import {OAuthAction} from "@model/oAuthAction";
|
||||||
|
import SetupService from "@api/v1/setup.service";
|
||||||
|
|
||||||
interface AvailableOAuthProviders extends OAuthProviderData {
|
interface AvailableOAuthProviders extends OAuthProviderData {
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
@ -60,12 +66,13 @@ export class DeleteConfirmDialog {
|
|||||||
],
|
],
|
||||||
templateUrl: './OAuthProviders.html',
|
templateUrl: './OAuthProviders.html',
|
||||||
styleUrl: './OAuthProviders.css',
|
styleUrl: './OAuthProviders.css',
|
||||||
providers: [AuthApiService]
|
providers: [SetupService, AuthApiService]
|
||||||
})
|
})
|
||||||
export class OAuthProviders {
|
export class OAuthProviders implements OnInit {
|
||||||
protected providers: AvailableOAuthProviders[] = [];
|
protected providers: AvailableOAuthProviders[] = [];
|
||||||
protected _activeProvidersId: OAuthProvider[] = [];
|
protected _activeProvidersId: OAuthProvider[] = [];
|
||||||
protected _activeProviders: string[] = [];
|
protected _activeProviders: string[] = [];
|
||||||
|
protected loading = true;
|
||||||
|
|
||||||
@Input() message: string = 'Вы можете войти в аккаунт через';
|
@Input() message: string = 'Вы можете войти в аккаунт через';
|
||||||
|
|
||||||
@ -80,11 +87,73 @@ export class OAuthProviders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Input() canUnlink: boolean = false;
|
@Input() canUnlink: boolean = false;
|
||||||
|
@Input() action: OAuthAction = OAuthAction.Login;
|
||||||
|
@Input() isSetup: boolean = false;
|
||||||
|
|
||||||
@Output() public oAuthUpdateProviders = new EventEmitter();
|
@Output() public oAuthUpdateProviders = new EventEmitter();
|
||||||
|
@Output() public oAuthLoginResult: EventEmitter<TwoFactorAuthentication> = new EventEmitter();
|
||||||
|
|
||||||
constructor(authApi: AuthApiService, private notify: ToastrService, private dialog: MatDialog) {
|
constructor(private setupApi: SetupService,
|
||||||
authApi.availableProviders().subscribe(providers => this.updateDisabledProviders(providers));
|
private authApi: AuthApiService,
|
||||||
|
private notify: ToastrService,
|
||||||
|
private dialog: MatDialog,
|
||||||
|
private route: ActivatedRoute) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const fullUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}`;
|
||||||
|
this.authApi.availableProviders(fullUrl).subscribe(providers => {
|
||||||
|
this.updateDisabledProviders(providers);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.route.queryParamMap
|
||||||
|
.pipe(
|
||||||
|
switchMap(params => {
|
||||||
|
const result = params.get('result');
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
this.loading = false; // Нет результата, завершение загрузки
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.handleOAuthResult(result); // Обрабатываем результат
|
||||||
|
}),
|
||||||
|
catchError(_ => {
|
||||||
|
this.loading = false;
|
||||||
|
return [];
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleOAuthResult(result: string): Observable<any> {
|
||||||
|
switch (this.action) {
|
||||||
|
case OAuthAction.Login:
|
||||||
|
return this.authApi.loginOAuth(result).pipe(
|
||||||
|
tap(auth => {
|
||||||
|
this.oAuthLoginResult.emit(auth);
|
||||||
|
}),
|
||||||
|
finalize(() => {
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
case OAuthAction.Bind:
|
||||||
|
if (this.isSetup) {
|
||||||
|
return this.setupApi.registerOAuth(result).pipe(
|
||||||
|
tap(() => {
|
||||||
|
this.oAuthUpdateProviders.emit();
|
||||||
|
}),
|
||||||
|
finalize(() => {
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else
|
||||||
|
throw new Error('Action "Bind" requires setup mode to be enabled.');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown action type for action ' + this.action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateDisabledProviders(data: OAuthProviderData[] | null = null) {
|
private updateDisabledProviders(data: OAuthProviderData[] | null = null) {
|
||||||
@ -98,26 +167,15 @@ export class OAuthProviders {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected openOAuth(provider: AvailableOAuthProviders) {
|
protected openOAuth(provider: AvailableOAuthProviders) {
|
||||||
console.log(provider.redirect);
|
|
||||||
const oauthWindow = window.open(
|
const oauthWindow = window.open(
|
||||||
provider.redirect,
|
provider.redirect,
|
||||||
'_blank',
|
'_self'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!oauthWindow) {
|
if (!oauthWindow) {
|
||||||
this.notify.error('Не удалось открыть OAuth окно');
|
this.notify.error('Не удалось открыть OAuth окно');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
provider.active = true;
|
|
||||||
|
|
||||||
const checkInterval = setInterval(() => {
|
|
||||||
if (oauthWindow.closed) {
|
|
||||||
clearInterval(checkInterval);
|
|
||||||
this.oAuthUpdateProviders.emit();
|
|
||||||
provider.active = false;
|
|
||||||
}
|
|
||||||
}, 1500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected confirmDelete(provider: AvailableOAuthProviders) {
|
protected confirmDelete(provider: AvailableOAuthProviders) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div [formGroup]="formGroup">
|
<div [formGroup]="formGroup" style="display: flex; flex-direction: column; align-items: stretch;">
|
||||||
<mat-form-field color="accent">
|
<mat-form-field color="accent">
|
||||||
<mat-label>Пароль</mat-label>
|
<mat-label>Пароль</mat-label>
|
||||||
<input matInput
|
<input matInput
|
||||||
|
@ -1,36 +1,53 @@
|
|||||||
<mat-sidenav-container class="formLogin">
|
<mat-sidenav-container class="formLogin">
|
||||||
|
|
||||||
<mat-card>
|
<mat-card>
|
||||||
<p class="mat-h3">
|
<p class="mat-h3">
|
||||||
Вход в систему
|
Вход в систему
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form [formGroup]="loginForm">
|
<form [formGroup]="loginForm">
|
||||||
<mat-form-field color="accent">
|
@if (!requiresTwoFactorAuth) {
|
||||||
<mat-label>Имя пользователя/email</mat-label>
|
<mat-form-field color="accent">
|
||||||
<input matInput
|
<mat-label>Имя пользователя/email</mat-label>
|
||||||
formControlName="user"
|
<input matInput
|
||||||
matTooltip='Укажите имя пользователя используя латинские буквы и цифры без пробелов или email'
|
formControlName="user"
|
||||||
required
|
matTooltip='Укажите имя пользователя используя латинские буквы и цифры без пробелов или email'
|
||||||
focusNext="passwordNextFocus">
|
required
|
||||||
|
focusNext="passwordNextFocus">
|
||||||
|
|
||||||
@if (loginForm.get('user')?.hasError('required')) {
|
@if (loginForm.get('user')?.hasError('required')) {
|
||||||
<mat-error>
|
<mat-error>
|
||||||
Имя пользователя или email является <i>обязательным</i>
|
Имя пользователя или email является <i>обязательным</i>
|
||||||
</mat-error>
|
</mat-error>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (loginForm.get('user')?.hasError('minlength')) {
|
@if (loginForm.get('user')?.hasError('minlength')) {
|
||||||
<mat-error>
|
<mat-error>
|
||||||
Количество символов должно быть не менее 4
|
Количество символов должно быть не менее 4
|
||||||
</mat-error>
|
</mat-error>
|
||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<password-input [focusNext]="'loginNextFocus'" [formGroup]="loginForm"/>
|
<password-input [focusNext]="'loginNextFocus'" [formGroup]="loginForm"/>
|
||||||
|
} @else {
|
||||||
|
<mat-form-field color="accent">
|
||||||
|
<mat-label>Код 2FA</mat-label>
|
||||||
|
<input matInput
|
||||||
|
formControlName="twoFactorCode"
|
||||||
|
matTooltip="Введите код из приложения"
|
||||||
|
required
|
||||||
|
focusNext="loginNextFocus">
|
||||||
|
@if (loginForm.get('twoFactorCode')?.hasError('required')) {
|
||||||
|
<mat-error>
|
||||||
|
Код 2FA обязателен.
|
||||||
|
</mat-error>
|
||||||
|
}
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<OAuthProviders/>
|
@if (!requiresTwoFactorAuth) {
|
||||||
|
<OAuthProviders (oAuthLoginResult)="loginOAuth($event)"/>
|
||||||
|
}
|
||||||
|
|
||||||
<mat-error>
|
<mat-error>
|
||||||
{{ errorText }}
|
{{ errorText }}
|
||||||
@ -42,7 +59,7 @@
|
|||||||
} @else {
|
} @else {
|
||||||
<button mat-flat-button color="accent"
|
<button mat-flat-button color="accent"
|
||||||
[disabled]="loginButtonIsDisable"
|
[disabled]="loginButtonIsDisable"
|
||||||
(click)="login()"
|
(click)="requiresTwoFactorAuth ? login2Fa() : login()"
|
||||||
id="loginNextFocus">
|
id="loginNextFocus">
|
||||||
Войти
|
Войти
|
||||||
</button>
|
</button>
|
||||||
|
@ -5,7 +5,7 @@ import {MatInput} from "@angular/material/input";
|
|||||||
import {MatTooltip} from "@angular/material/tooltip";
|
import {MatTooltip} from "@angular/material/tooltip";
|
||||||
import {MatButton} from "@angular/material/button";
|
import {MatButton} from "@angular/material/button";
|
||||||
import {MatCard} from "@angular/material/card";
|
import {MatCard} from "@angular/material/card";
|
||||||
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||||
import {FocusNextDirective} from "@/directives/focus-next.directive";
|
import {FocusNextDirective} from "@/directives/focus-next.directive";
|
||||||
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
import {DataSpinnerComponent} from "@component/common/data-spinner/data-spinner.component";
|
||||||
import AuthApiService from "@api/v1/authApiService";
|
import AuthApiService from "@api/v1/authApiService";
|
||||||
@ -40,6 +40,7 @@ export class LoginComponent {
|
|||||||
protected loaderActive: boolean = false;
|
protected loaderActive: boolean = false;
|
||||||
protected loginButtonIsDisable: boolean = true;
|
protected loginButtonIsDisable: boolean = true;
|
||||||
protected errorText: string = '';
|
protected errorText: string = '';
|
||||||
|
protected requiresTwoFactorAuth: boolean = false;
|
||||||
|
|
||||||
constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private router: Router) {
|
constructor(private formBuilder: FormBuilder, private auth: AuthApiService, private router: Router) {
|
||||||
this.auth.getRole()
|
this.auth.getRole()
|
||||||
@ -69,6 +70,22 @@ export class LoginComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateTwoFactorValidation(data: TwoFactorAuthentication) {
|
||||||
|
if (data === TwoFactorAuthentication.None) {
|
||||||
|
this.router.navigate(['admin']).then();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.requiresTwoFactorAuth = true;
|
||||||
|
this.loginForm.addControl(
|
||||||
|
'twoFactorCode',
|
||||||
|
new FormControl('', Validators.required)
|
||||||
|
);
|
||||||
|
this.loginForm.removeControl('user');
|
||||||
|
this.loginForm.removeControl('password');
|
||||||
|
this.loginButtonIsDisable = !this.loginForm.valid;
|
||||||
|
}
|
||||||
|
|
||||||
protected login() {
|
protected login() {
|
||||||
this.loaderActive = true;
|
this.loaderActive = true;
|
||||||
|
|
||||||
@ -85,11 +102,31 @@ export class LoginComponent {
|
|||||||
.subscribe(x => {
|
.subscribe(x => {
|
||||||
this.loaderActive = false;
|
this.loaderActive = false;
|
||||||
this.errorText = '';
|
this.errorText = '';
|
||||||
|
this.updateTwoFactorValidation(x);
|
||||||
if (x == TwoFactorAuthentication.None)
|
|
||||||
this.router.navigate(['admin']).then();
|
|
||||||
else
|
|
||||||
this.router.navigate(['two-factor']).then();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected login2Fa() {
|
||||||
|
this.loaderActive = true;
|
||||||
|
|
||||||
|
this.auth.twoFactorAuth({
|
||||||
|
code: this.loginForm.get('twoFactorCode')?.value,
|
||||||
|
method: TwoFactorAuthentication.TotpRequired
|
||||||
|
})
|
||||||
|
.pipe(catchError(error => {
|
||||||
|
this.loaderActive = false;
|
||||||
|
this.errorText = error.error.detail;
|
||||||
|
this.loginButtonIsDisable = true;
|
||||||
|
throw error;
|
||||||
|
}))
|
||||||
|
.subscribe(_ => {
|
||||||
|
this.loaderActive = false;
|
||||||
|
this.errorText = '';
|
||||||
|
this.router.navigate(['admin']).then();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected loginOAuth(result: TwoFactorAuthentication) {
|
||||||
|
this.updateTwoFactorValidation(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,9 @@
|
|||||||
}
|
}
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<OAuthProviders [canUnlink]="true" [activeProvidersId]="activatedProviders" (oAuthUpdateProviders)="updateProviders()"
|
<OAuthProviders [canUnlink]="true" [activeProvidersId]="activatedProviders"
|
||||||
[message]="'Или можете получить часть данных от сторонних сервисов'"/>
|
(oAuthUpdateProviders)="updateProviders()"
|
||||||
|
[message]="'Или можете получить часть данных от сторонних сервисов'"
|
||||||
|
[action]="OAuthAction.Bind" [isSetup]="true"/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
import {Location} from '@angular/common';
|
||||||
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 {passwordMatchValidator} from '@service/password-match.validator';
|
import {passwordMatchValidator} from '@service/password-match.validator';
|
||||||
@ -13,6 +14,8 @@ import AuthApiService from "@api/v1/authApiService";
|
|||||||
import {OAuthProviders} from "@component/OAuthProviders/OAuthProviders";
|
import {OAuthProviders} from "@component/OAuthProviders/OAuthProviders";
|
||||||
import {OAuthProvider} from "@model/oAuthProvider";
|
import {OAuthProvider} from "@model/oAuthProvider";
|
||||||
import {PasswordInputComponent} from "@component/common/password-input/password-input.component";
|
import {PasswordInputComponent} from "@component/common/password-input/password-input.component";
|
||||||
|
import {OAuthAction} from "@model/oAuthAction";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-create-admin',
|
selector: 'app-create-admin',
|
||||||
@ -29,7 +32,7 @@ import {PasswordInputComponent} from "@component/common/password-input/password-
|
|||||||
PasswordInputComponent
|
PasswordInputComponent
|
||||||
],
|
],
|
||||||
templateUrl: './create-admin.component.html',
|
templateUrl: './create-admin.component.html',
|
||||||
providers: [AuthApiService]
|
providers: [AuthApiService, Location]
|
||||||
})
|
})
|
||||||
|
|
||||||
export class CreateAdminComponent {
|
export class CreateAdminComponent {
|
||||||
@ -37,8 +40,9 @@ export class CreateAdminComponent {
|
|||||||
protected hideRetypePass = true;
|
protected hideRetypePass = true;
|
||||||
protected activatedProviders: OAuthProvider[] = [];
|
protected activatedProviders: OAuthProvider[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(private router: Router,
|
||||||
private navigationService: NavigationService, private formBuilder: FormBuilder, private api: SetupService) {
|
private location: Location,
|
||||||
|
private navigationService: NavigationService, private formBuilder: FormBuilder, private api: SetupService) {
|
||||||
this.createAdminForm = this.formBuilder.group({
|
this.createAdminForm = this.formBuilder.group({
|
||||||
user: ['', Validators.pattern(/^([A-Za-z0-9]){4,}$/)],
|
user: ['', Validators.pattern(/^([A-Za-z0-9]){4,}$/)],
|
||||||
email: ['', Validators.email],
|
email: ['', Validators.email],
|
||||||
@ -76,6 +80,9 @@ export class CreateAdminComponent {
|
|||||||
|
|
||||||
this.activatedProviders = configuration.usedOAuthProviders;
|
this.activatedProviders = configuration.usedOAuthProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentPath = this.router.url.split('?')[0];
|
||||||
|
this.location.replaceState(currentPath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,4 +94,6 @@ export class CreateAdminComponent {
|
|||||||
protected updateProviders() {
|
protected updateProviders() {
|
||||||
this.updateAdminData();
|
this.updateAdminData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly OAuthAction = OAuthAction;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {Component, ViewEncapsulation} from '@angular/core';
|
import {Component, ViewEncapsulation} from '@angular/core';
|
||||||
import {MatSidenavModule} from "@angular/material/sidenav";
|
import {MatSidenavModule} from "@angular/material/sidenav";
|
||||||
import {Router, RouterOutlet} from "@angular/router";
|
import {ActivatedRoute, Router, RouterOutlet} from "@angular/router";
|
||||||
import {MatCard} from "@angular/material/card";
|
import {MatCard} from "@angular/material/card";
|
||||||
import {MatButton} from "@angular/material/button";
|
import {MatButton} from "@angular/material/button";
|
||||||
import {NavigationService} from "@service/navigation.service";
|
import {NavigationService} from "@service/navigation.service";
|
||||||
@ -30,20 +30,29 @@ export class SetupComponent {
|
|||||||
protected skipButtonDisabled: boolean = false;
|
protected skipButtonDisabled: boolean = false;
|
||||||
protected loaderActive: boolean = false;
|
protected loaderActive: boolean = false;
|
||||||
|
|
||||||
protected routes: Array<string> = ['', 'welcome', 'database', 'cache', 'password-policy', 'schedule', 'logging', 'create-admin', 'two-factor', 'summary'];
|
protected routes: Array<string> = ['', 'welcome', 'create-admin', 'database', 'cache', 'password-policy', 'schedule', 'logging', 'two-factor', 'summary'];
|
||||||
private index: number = 1;
|
private index: number = 1;
|
||||||
|
|
||||||
protected get getIndex() {
|
protected get getIndex() {
|
||||||
return this.index;
|
return this.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private router: Router, private navigationService: NavigationService, api: SetupService, private notify: ToastrService) {
|
constructor(private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private navigationService: NavigationService,
|
||||||
|
api: SetupService,
|
||||||
|
private notify: ToastrService) {
|
||||||
|
|
||||||
api.isConfigured().subscribe(x => {
|
api.isConfigured().subscribe(x => {
|
||||||
if (x) this.router.navigate(['/']).then();
|
if (x) this.router.navigate(['/']).then();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.router.url.includes(this.routes[this.index])) {
|
if (!this.router.url.includes(this.routes[this.index])) {
|
||||||
this.router.navigate(['setup/', this.routes[this.index]]).then();
|
const currentQueryParams = this.route.snapshot.queryParams;
|
||||||
|
this.router.navigate(
|
||||||
|
['setup/', this.routes[this.index]],
|
||||||
|
{queryParams: currentQueryParams}
|
||||||
|
).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initializeButtonSubscriptions();
|
this.initializeButtonSubscriptions();
|
||||||
@ -104,13 +113,25 @@ export class SetupComponent {
|
|||||||
this.moveToPreviousPage();
|
this.moveToPreviousPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private moveToNextPage() {
|
private moveToNextPage(): void {
|
||||||
if (this.index < this.routes.length - 1) {
|
if (this.index < this.routes.length - 1) {
|
||||||
this.index++;
|
this.index++;
|
||||||
this.router.navigate(['setup/', this.routes[this.index]]).then();
|
|
||||||
this.initializePage();
|
const currentQueryParams = this.route.snapshot.queryParams;
|
||||||
|
|
||||||
|
this.router.navigate(
|
||||||
|
['setup/', this.routes[this.index]],
|
||||||
|
{queryParams: currentQueryParams}
|
||||||
|
).then(() => {
|
||||||
|
this.initializePage();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate(['/']).then();
|
const currentQueryParams = this.route.snapshot.queryParams;
|
||||||
|
|
||||||
|
this.router.navigate(
|
||||||
|
['/'],
|
||||||
|
{queryParams: currentQueryParams}
|
||||||
|
).then();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
src/shared/structs/oAuthAction.ts
Normal file
4
src/shared/structs/oAuthAction.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum OAuthAction {
|
||||||
|
Login,
|
||||||
|
Bind
|
||||||
|
}
|
Reference in New Issue
Block a user