mirror of https://github.com/abpframework/abp
commit
ff289bcaea
@ -1,3 +0,0 @@
|
||||
<h1> @abp/ng.account </h1>
|
||||
|
||||
[docs.abp.io](https://docs.abp.io)
|
||||
@ -1,7 +0,0 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/account/config",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { ACCOUNT_ROUTE_PROVIDERS } from './providers/route.provider';
|
||||
|
||||
@NgModule()
|
||||
export class AccountConfigModule {
|
||||
static forRoot(): ModuleWithProviders<AccountConfigModule> {
|
||||
return {
|
||||
ngModule: AccountConfigModule,
|
||||
providers: [ACCOUNT_ROUTE_PROVIDERS],
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './route-names';
|
||||
@ -1,6 +0,0 @@
|
||||
export const enum eAccountRouteNames {
|
||||
Account = 'AbpAccount::Menu:Account',
|
||||
Login = 'AbpAccount::Login',
|
||||
Register = 'AbpAccount::Register',
|
||||
ManageProfile = 'AbpAccount::ManageYourProfile',
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './route.provider';
|
||||
@ -1,39 +0,0 @@
|
||||
import { eLayoutType, RoutesService } from '@abp/ng.core';
|
||||
import { APP_INITIALIZER } from '@angular/core';
|
||||
import { eAccountRouteNames } from '../enums/route-names';
|
||||
|
||||
export const ACCOUNT_ROUTE_PROVIDERS = [
|
||||
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true },
|
||||
];
|
||||
|
||||
export function configureRoutes(routesService: RoutesService) {
|
||||
return () => {
|
||||
routesService.add([
|
||||
{
|
||||
path: '/account',
|
||||
name: eAccountRouteNames.Account,
|
||||
invisible: true,
|
||||
layout: eLayoutType.application,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
path: '/account/login',
|
||||
name: eAccountRouteNames.Login,
|
||||
parentName: eAccountRouteNames.Account,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
path: '/account/register',
|
||||
name: eAccountRouteNames.Register,
|
||||
parentName: eAccountRouteNames.Account,
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
path: '/account/manage-profile',
|
||||
name: eAccountRouteNames.ManageProfile,
|
||||
parentName: eAccountRouteNames.Account,
|
||||
order: 3,
|
||||
},
|
||||
]);
|
||||
};
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
export * from './account-config.module';
|
||||
export * from './enums';
|
||||
export * from './providers';
|
||||
@ -1,6 +0,0 @@
|
||||
const jestConfig = require('../../jest.config');
|
||||
|
||||
module.exports = {
|
||||
...jestConfig,
|
||||
name: 'account',
|
||||
};
|
||||
@ -1,8 +0,0 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/account",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
},
|
||||
"whitelistedNonPeerDependencies": ["@abp/ng.theme.shared"]
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
entryPoints: {
|
||||
'.': {},
|
||||
'./config': {},
|
||||
'./dist': { ignore: true },
|
||||
},
|
||||
};
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "@abp/ng.account",
|
||||
"version": "3.3.1",
|
||||
"homepage": "https://abp.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/abpframework/abp.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@abp/ng.theme.shared": "~3.3.1",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
import {
|
||||
DynamicLayoutComponent,
|
||||
AuthGuard,
|
||||
ReplaceableComponents,
|
||||
ReplaceableRouteContainerComponent,
|
||||
} from '@abp/ng.core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
|
||||
import { RegisterComponent } from './components/register/register.component';
|
||||
import { eAccountComponents } from './enums/components';
|
||||
import { AuthenticationFlowGuard } from './guards/authentication-flow.guard';
|
||||
import { ManageProfileGuard } from './guards/manage-profile.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', pathMatch: 'full', redirectTo: 'login' },
|
||||
{
|
||||
path: '',
|
||||
component: DynamicLayoutComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
component: ReplaceableRouteContainerComponent,
|
||||
canActivate: [AuthenticationFlowGuard],
|
||||
data: {
|
||||
replaceableComponent: {
|
||||
key: eAccountComponents.Login,
|
||||
defaultComponent: LoginComponent,
|
||||
} as ReplaceableComponents.RouteData<LoginComponent>,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
component: ReplaceableRouteContainerComponent,
|
||||
canActivate: [AuthenticationFlowGuard],
|
||||
data: {
|
||||
replaceableComponent: {
|
||||
key: eAccountComponents.Register,
|
||||
defaultComponent: RegisterComponent,
|
||||
} as ReplaceableComponents.RouteData<RegisterComponent>,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'manage-profile',
|
||||
component: ReplaceableRouteContainerComponent,
|
||||
canActivate: [AuthGuard, ManageProfileGuard],
|
||||
data: {
|
||||
replaceableComponent: {
|
||||
key: eAccountComponents.ManageProfile,
|
||||
defaultComponent: ManageProfileComponent,
|
||||
} as ReplaceableComponents.RouteData<ManageProfileComponent>,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AccountRoutingModule {}
|
||||
@ -1,59 +0,0 @@
|
||||
import { CoreModule, LazyModuleFactory } from '@abp/ng.core';
|
||||
import { ThemeSharedModule } from '@abp/ng.theme.shared';
|
||||
import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core';
|
||||
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { NgxValidateCoreModule } from '@ngx-validate/core';
|
||||
import { AccountRoutingModule } from './account-routing.module';
|
||||
import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.component';
|
||||
import { ChangePasswordComponent } from './components/change-password/change-password.component';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component';
|
||||
import { PersonalSettingsComponent } from './components/personal-settings/personal-settings.component';
|
||||
import { RegisterComponent } from './components/register/register.component';
|
||||
import { TenantBoxComponent } from './components/tenant-box/tenant-box.component';
|
||||
import { Options } from './models/options';
|
||||
import { ACCOUNT_OPTIONS } from './tokens/options.token';
|
||||
import { accountOptionsFactory } from './utils/factory-utils';
|
||||
import { AuthenticationFlowGuard } from './guards/authentication-flow.guard';
|
||||
import { ManageProfileGuard } from './guards/manage-profile.guard';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AuthWrapperComponent,
|
||||
LoginComponent,
|
||||
RegisterComponent,
|
||||
TenantBoxComponent,
|
||||
ChangePasswordComponent,
|
||||
ManageProfileComponent,
|
||||
PersonalSettingsComponent,
|
||||
],
|
||||
imports: [
|
||||
CoreModule,
|
||||
AccountRoutingModule,
|
||||
ThemeSharedModule,
|
||||
NgbDropdownModule,
|
||||
NgxValidateCoreModule,
|
||||
],
|
||||
exports: [],
|
||||
})
|
||||
export class AccountModule {
|
||||
static forChild(options: Options): ModuleWithProviders<AccountModule> {
|
||||
return {
|
||||
ngModule: AccountModule,
|
||||
providers: [
|
||||
AuthenticationFlowGuard,
|
||||
ManageProfileGuard,
|
||||
{ provide: ACCOUNT_OPTIONS, useValue: options },
|
||||
{
|
||||
provide: 'ACCOUNT_OPTIONS',
|
||||
useFactory: accountOptionsFactory,
|
||||
deps: [ACCOUNT_OPTIONS],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
static forLazy(options: Options): NgModuleFactory<AccountModule> {
|
||||
return new LazyModuleFactory(AccountModule.forChild(options));
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="mx-auto col col-md-5">
|
||||
<ng-container *ngIf="(isMultiTenancyEnabled$ | async) && multiTenancy.isTenantBoxVisible">
|
||||
<abp-tenant-box *abpReplaceableTemplate="{ componentKey: tenantBoxKey }"></abp-tenant-box>
|
||||
</ng-container>
|
||||
|
||||
<div class="abp-account-container">
|
||||
<div
|
||||
*ngIf="enableLocalLogin; else disableLocalLoginTemplate"
|
||||
class="card mt-3 shadow-sm rounded"
|
||||
>
|
||||
<div class="card-body p-5">
|
||||
<ng-content *ngTemplateOutlet="mainContentRef"></ng-content>
|
||||
</div>
|
||||
<ng-content *ngTemplateOutlet="cancelContentRef"></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #disableLocalLoginTemplate>
|
||||
<div class="alert alert-warning">
|
||||
<strong>{{ 'AbpAccount::InvalidLoginRequest' | abpLocalization }}</strong>
|
||||
{{ 'AbpAccount::ThereAreNoLoginSchemesConfiguredForThisClient' | abpLocalization }}
|
||||
</div>
|
||||
</ng-template>
|
||||
@ -1,45 +0,0 @@
|
||||
import { ConfigState, SubscriptionService, MultiTenancyService } from '@abp/ng.core';
|
||||
import { Component, Input, OnInit, TemplateRef } from '@angular/core';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { eAccountComponents } from '../../enums/components';
|
||||
import { Account } from '../../models/account';
|
||||
|
||||
@Component({
|
||||
selector: 'abp-auth-wrapper',
|
||||
templateUrl: './auth-wrapper.component.html',
|
||||
exportAs: 'abpAuthWrapper',
|
||||
providers: [SubscriptionService],
|
||||
})
|
||||
export class AuthWrapperComponent
|
||||
implements Account.AuthWrapperComponentInputs, Account.AuthWrapperComponentOutputs, OnInit {
|
||||
@Input()
|
||||
readonly mainContentRef: TemplateRef<any>;
|
||||
|
||||
@Input()
|
||||
readonly cancelContentRef: TemplateRef<any>;
|
||||
|
||||
@Select(ConfigState.getDeep('multiTenancy.isEnabled'))
|
||||
isMultiTenancyEnabled$: Observable<boolean>;
|
||||
|
||||
enableLocalLogin = true;
|
||||
|
||||
tenantBoxKey = eAccountComponents.TenantBox;
|
||||
|
||||
constructor(
|
||||
public readonly multiTenancy: MultiTenancyService,
|
||||
private store: Store,
|
||||
private subscription: SubscriptionService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.subscription.addOne(
|
||||
this.store.select(ConfigState.getSetting('Abp.Account.EnableLocalLogin')),
|
||||
value => {
|
||||
if (value) {
|
||||
this.enableLocalLogin = value.toLowerCase() !== 'false';
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,48 +0,0 @@
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()" [mapErrorsFn]="mapErrorsFn" validateOnSubmit>
|
||||
<div *ngIf="!hideCurrentPassword" class="form-group">
|
||||
<label for="current-password">{{
|
||||
'AbpIdentity::DisplayName:CurrentPassword' | abpLocalization
|
||||
}}</label
|
||||
><span> * </span
|
||||
><input
|
||||
type="password"
|
||||
id="current-password"
|
||||
class="form-control"
|
||||
formControlName="password"
|
||||
autofocus
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="new-password">{{ 'AbpIdentity::DisplayName:NewPassword' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input
|
||||
type="password"
|
||||
id="new-password"
|
||||
class="form-control"
|
||||
formControlName="newPassword"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm-new-password">{{
|
||||
'AbpIdentity::DisplayName:NewPasswordConfirm' | abpLocalization
|
||||
}}</label
|
||||
><span> * </span
|
||||
><input
|
||||
type="password"
|
||||
id="confirm-new-password"
|
||||
class="form-control"
|
||||
formControlName="repeatNewPassword"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</div>
|
||||
<abp-button
|
||||
iconClass="fa fa-check"
|
||||
buttonClass="btn btn-primary color-white"
|
||||
buttonType="submit"
|
||||
[loading]="inProgress"
|
||||
[disabled]="form?.invalid"
|
||||
>{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button
|
||||
>
|
||||
</form>
|
||||
@ -1,100 +0,0 @@
|
||||
import { ChangePassword, ProfileState } from '@abp/ng.core';
|
||||
import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared';
|
||||
import { Component, Injector, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||
import { comparePasswords, Validation } from '@ngx-validate/core';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import snq from 'snq';
|
||||
import { Account } from '../../models/account';
|
||||
|
||||
const { required } = Validators;
|
||||
|
||||
const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword'];
|
||||
|
||||
@Component({
|
||||
selector: 'abp-change-password-form',
|
||||
templateUrl: './change-password.component.html',
|
||||
exportAs: 'abpChangePasswordForm',
|
||||
})
|
||||
export class ChangePasswordComponent
|
||||
implements OnInit, Account.ChangePasswordComponentInputs, Account.ChangePasswordComponentOutputs {
|
||||
form: FormGroup;
|
||||
|
||||
inProgress: boolean;
|
||||
|
||||
hideCurrentPassword: boolean;
|
||||
|
||||
mapErrorsFn: Validation.MapErrorsFn = (errors, groupErrors, control) => {
|
||||
if (PASSWORD_FIELDS.indexOf(String(control.name)) < 0) return errors;
|
||||
|
||||
return errors.concat(groupErrors.filter(({ key }) => key === 'passwordMismatch'));
|
||||
};
|
||||
|
||||
constructor(
|
||||
private injector: Injector,
|
||||
private fb: FormBuilder,
|
||||
private store: Store,
|
||||
private toasterService: ToasterService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.hideCurrentPassword = !this.store.selectSnapshot(ProfileState.getProfile).hasPassword;
|
||||
|
||||
const passwordValidations = getPasswordValidators(this.injector);
|
||||
|
||||
this.form = this.fb.group(
|
||||
{
|
||||
password: ['', required],
|
||||
newPassword: [
|
||||
'',
|
||||
{
|
||||
validators: [required, ...passwordValidations],
|
||||
},
|
||||
],
|
||||
repeatNewPassword: [
|
||||
'',
|
||||
{
|
||||
validators: [required, ...passwordValidations],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
validators: [comparePasswords(PASSWORD_FIELDS)],
|
||||
},
|
||||
);
|
||||
|
||||
if (this.hideCurrentPassword) this.form.removeControl('password');
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.form.invalid) return;
|
||||
this.inProgress = true;
|
||||
this.store
|
||||
.dispatch(
|
||||
new ChangePassword({
|
||||
...(!this.hideCurrentPassword && { currentPassword: this.form.get('password').value }),
|
||||
newPassword: this.form.get('newPassword').value,
|
||||
}),
|
||||
)
|
||||
.pipe(finalize(() => (this.inProgress = false)))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.form.reset();
|
||||
this.toasterService.success('AbpAccount::PasswordChangedMessage', '', {
|
||||
life: 5000,
|
||||
});
|
||||
|
||||
if (this.hideCurrentPassword) {
|
||||
this.hideCurrentPassword = false;
|
||||
this.form.addControl('password', new FormControl('', [required]));
|
||||
}
|
||||
},
|
||||
error: err => {
|
||||
this.toasterService.error(
|
||||
snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
export * from './change-password/change-password.component';
|
||||
export * from './login/login.component';
|
||||
export * from './manage-profile/manage-profile.component';
|
||||
export * from './register/register.component';
|
||||
export * from './personal-settings/personal-settings.component';
|
||||
export * from './tenant-box/tenant-box.component';
|
||||
@ -1,74 +0,0 @@
|
||||
<abp-auth-wrapper
|
||||
*abpReplaceableTemplate="{
|
||||
componentKey: authWrapperKey,
|
||||
inputs: {
|
||||
mainContentRef: { value: mainContentRef },
|
||||
cancelContentRef: { value: cancelContentRef }
|
||||
}
|
||||
}"
|
||||
[mainContentRef]="mainContentRef"
|
||||
[cancelContentRef]="cancelContentRef"
|
||||
>
|
||||
</abp-auth-wrapper>
|
||||
<ng-template #mainContentRef>
|
||||
<h4>{{ 'AbpAccount::Login' | abpLocalization }}</h4>
|
||||
<strong *ngIf="isSelfRegistrationEnabled">
|
||||
{{ 'AbpAccount::AreYouANewUser' | abpLocalization }}
|
||||
<a class="text-decoration-none" routerLink="/account/register">{{
|
||||
'AbpAccount::Register' | abpLocalization
|
||||
}}</a>
|
||||
</strong>
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()" validateOnSubmit class="mt-4">
|
||||
<div class="form-group">
|
||||
<label for="login-input-user-name-or-email-address">{{
|
||||
'AbpAccount::UserNameOrEmailAddress' | abpLocalization
|
||||
}}</label>
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
id="login-input-user-name-or-email-address"
|
||||
formControlName="username"
|
||||
autocomplete="username"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="login-input-password">{{ 'AbpAccount::Password' | abpLocalization }}</label>
|
||||
<input
|
||||
class="form-control"
|
||||
type="password"
|
||||
id="login-input-password"
|
||||
formControlName="password"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-check" validationTarget validationStyle>
|
||||
<label class="form-check-label" for="login-input-remember-me">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
id="login-input-remember-me"
|
||||
formControlName="remember"
|
||||
/>
|
||||
{{ 'AbpAccount::RememberMe' | abpLocalization }}
|
||||
</label>
|
||||
</div>
|
||||
<abp-button
|
||||
[loading]="inProgress"
|
||||
buttonType="submit"
|
||||
name="Action"
|
||||
buttonClass="btn-block btn-lg mt-3 btn btn-primary"
|
||||
>
|
||||
{{ 'AbpAccount::Login' | abpLocalization }}
|
||||
</abp-button>
|
||||
</form>
|
||||
</ng-template>
|
||||
<ng-template #cancelContentRef>
|
||||
<div class="card-footer text-center border-0">
|
||||
<a routerLink="/">
|
||||
<button type="button" name="Action" value="Cancel" class="px-2 py-0 btn btn-link">
|
||||
{{ 'AbpAccount::Cancel' | abpLocalization }}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</ng-template>
|
||||
@ -1,70 +0,0 @@
|
||||
import { AuthService, ConfigState } from '@abp/ng.core';
|
||||
import { ToasterService } from '@abp/ng.theme.shared';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { throwError } from 'rxjs';
|
||||
import { catchError, finalize } from 'rxjs/operators';
|
||||
import snq from 'snq';
|
||||
import { eAccountComponents } from '../../enums/components';
|
||||
|
||||
const { maxLength, minLength, required } = Validators;
|
||||
|
||||
@Component({
|
||||
selector: 'abp-login',
|
||||
templateUrl: './login.component.html',
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
form: FormGroup;
|
||||
|
||||
inProgress: boolean;
|
||||
|
||||
isSelfRegistrationEnabled = true;
|
||||
|
||||
authWrapperKey = eAccountComponents.AuthWrapper;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private oauthService: OAuthService,
|
||||
private store: Store,
|
||||
private toasterService: ToasterService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.isSelfRegistrationEnabled =
|
||||
(
|
||||
(this.store.selectSnapshot(
|
||||
ConfigState.getSetting('Abp.Account.IsSelfRegistrationEnabled'),
|
||||
) as string) || ''
|
||||
).toLowerCase() !== 'false';
|
||||
|
||||
this.form = this.fb.group({
|
||||
username: ['', [required, maxLength(255)]],
|
||||
password: ['', [required, maxLength(128)]],
|
||||
remember: [false],
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.form.invalid) return;
|
||||
|
||||
this.inProgress = true;
|
||||
this.authService
|
||||
.login(this.form.get('username').value, this.form.get('password').value)
|
||||
.pipe(
|
||||
catchError(err => {
|
||||
this.toasterService.error(
|
||||
snq(() => err.error.error_description) ||
|
||||
snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'),
|
||||
'AbpAccount::Error',
|
||||
{ life: 7000 },
|
||||
);
|
||||
return throwError(err);
|
||||
}),
|
||||
finalize(() => (this.inProgress = false)),
|
||||
)
|
||||
.subscribe(() => {});
|
||||
}
|
||||
}
|
||||
@ -1,58 +0,0 @@
|
||||
<div id="AbpContentToolbar"></div>
|
||||
|
||||
<div class="card border-0 shadow-sm min-h-400" [abpLoading]="!isProfileLoaded">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-3">
|
||||
<ul class="nav flex-column nav-pills" id="nav-tab" role="tablist">
|
||||
<li
|
||||
*ngIf="!hideChangePasswordTab && isProfileLoaded"
|
||||
class="nav-item"
|
||||
(click)="selectedTab = 0"
|
||||
>
|
||||
<a
|
||||
class="nav-link"
|
||||
[ngClass]="{ active: selectedTab === 0 }"
|
||||
role="tab"
|
||||
href="javascript:void(0)"
|
||||
>{{ 'AbpUi::ChangePassword' | abpLocalization }}</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item mb-2" (click)="selectedTab = 1">
|
||||
<a
|
||||
class="nav-link"
|
||||
[ngClass]="{ active: selectedTab === 1 }"
|
||||
role="tab"
|
||||
href="javascript:void(0)"
|
||||
>{{ 'AbpAccount::PersonalSettings' | abpLocalization }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div *ngIf="isProfileLoaded" class="col-12 col-md-9">
|
||||
<div class="tab-content" *ngIf="selectedTab === 0" [@fadeIn]>
|
||||
<div class="tab-pane active" role="tabpanel">
|
||||
<h4>
|
||||
{{ 'AbpIdentity::ChangePassword' | abpLocalization }}
|
||||
<hr />
|
||||
</h4>
|
||||
<abp-change-password-form
|
||||
*abpReplaceableTemplate="{ componentKey: changePasswordKey }"
|
||||
></abp-change-password-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-content" *ngIf="selectedTab === 1" [@fadeIn]>
|
||||
<div class="tab-pane active" role="tabpanel">
|
||||
<h4>
|
||||
{{ 'AbpIdentity::PersonalSettings' | abpLocalization }}
|
||||
<hr />
|
||||
</h4>
|
||||
<abp-personal-settings-form
|
||||
*abpReplaceableTemplate="{ componentKey: personalSettingsKey }"
|
||||
></abp-personal-settings-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,42 +0,0 @@
|
||||
import { fadeIn } from '@abp/ng.theme.shared';
|
||||
import { transition, trigger, useAnimation } from '@angular/animations';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { eAccountComponents } from '../../enums/components';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { GetProfile, ProfileState } from '@abp/ng.core';
|
||||
|
||||
@Component({
|
||||
selector: 'abp-manage-profile',
|
||||
templateUrl: './manage-profile.component.html',
|
||||
animations: [trigger('fadeIn', [transition(':enter', useAnimation(fadeIn))])],
|
||||
styles: [
|
||||
`
|
||||
.min-h-400 {
|
||||
min-height: 400px;
|
||||
}
|
||||
`,
|
||||
],
|
||||
})
|
||||
export class ManageProfileComponent implements OnInit {
|
||||
selectedTab = 0;
|
||||
|
||||
changePasswordKey = eAccountComponents.ChangePassword;
|
||||
|
||||
personalSettingsKey = eAccountComponents.PersonalSettings;
|
||||
|
||||
isProfileLoaded: boolean;
|
||||
|
||||
hideChangePasswordTab: boolean;
|
||||
|
||||
constructor(private store: Store) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.store.dispatch(new GetProfile()).subscribe(() => {
|
||||
this.isProfileLoaded = true;
|
||||
if (this.store.selectSnapshot(ProfileState.getProfile).isExternal) {
|
||||
this.hideChangePasswordTab = true;
|
||||
this.selectedTab = 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
<form validateOnSubmit *ngIf="form" [formGroup]="form" (ngSubmit)="submit()">
|
||||
<div class="form-group">
|
||||
<label for="username">{{ 'AbpIdentity::DisplayName:UserName' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input
|
||||
type="text"
|
||||
id="username"
|
||||
class="form-control"
|
||||
formControlName="userName"
|
||||
autofocus
|
||||
(keydown.space)="$event.preventDefault()"
|
||||
/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="name">{{ 'AbpIdentity::DisplayName:Name' | abpLocalization }}</label
|
||||
><input type="text" id="name" class="form-control" formControlName="name" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="surname">{{ 'AbpIdentity::DisplayName:Surname' | abpLocalization }}</label
|
||||
><input type="text" id="surname" class="form-control" formControlName="surname" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="email-address">{{ 'AbpIdentity::DisplayName:Email' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input type="text" id="email-address" class="form-control" formControlName="email" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="phone-number">{{ 'AbpIdentity::DisplayName:PhoneNumber' | abpLocalization }}</label
|
||||
><input type="text" id="phone-number" class="form-control" formControlName="phoneNumber" />
|
||||
</div>
|
||||
<abp-button
|
||||
buttonType="submit"
|
||||
iconClass="fa fa-check"
|
||||
buttonClass="btn btn-primary color-white"
|
||||
[loading]="inProgress"
|
||||
[disabled]="form?.invalid"
|
||||
>
|
||||
{{ 'AbpIdentity::Save' | abpLocalization }}</abp-button
|
||||
>
|
||||
</form>
|
||||
@ -1,57 +0,0 @@
|
||||
import { ProfileState, UpdateProfile } from '@abp/ng.core';
|
||||
import { ToasterService } from '@abp/ng.theme.shared';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { Account } from '../../models/account';
|
||||
|
||||
const { maxLength, required, email } = Validators;
|
||||
|
||||
@Component({
|
||||
selector: 'abp-personal-settings-form',
|
||||
templateUrl: './personal-settings.component.html',
|
||||
exportAs: 'abpPersonalSettingsForm',
|
||||
})
|
||||
export class PersonalSettingsComponent
|
||||
implements
|
||||
OnInit,
|
||||
Account.PersonalSettingsComponentInputs,
|
||||
Account.PersonalSettingsComponentOutputs {
|
||||
form: FormGroup;
|
||||
|
||||
inProgress: boolean;
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private store: Store,
|
||||
private toasterService: ToasterService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.buildForm();
|
||||
}
|
||||
|
||||
buildForm() {
|
||||
const profile = this.store.selectSnapshot(ProfileState.getProfile);
|
||||
|
||||
this.form = this.fb.group({
|
||||
userName: [profile.userName, [required, maxLength(256)]],
|
||||
email: [profile.email, [required, email, maxLength(256)]],
|
||||
name: [profile.name || '', [maxLength(64)]],
|
||||
surname: [profile.surname || '', [maxLength(64)]],
|
||||
phoneNumber: [profile.phoneNumber || '', [maxLength(16)]],
|
||||
});
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (this.form.invalid) return;
|
||||
this.inProgress = true;
|
||||
this.store
|
||||
.dispatch(new UpdateProfile(this.form.value))
|
||||
.pipe(finalize(() => (this.inProgress = false)))
|
||||
.subscribe(() => {
|
||||
this.toasterService.success('AbpAccount::PersonalSettingsSaved', 'Success', { life: 5000 });
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
<abp-auth-wrapper
|
||||
*abpReplaceableTemplate="{
|
||||
componentKey: authWrapperKey,
|
||||
inputs: {
|
||||
mainContentRef: { value: mainContentRef }
|
||||
}
|
||||
}"
|
||||
[mainContentRef]="mainContentRef"
|
||||
>
|
||||
</abp-auth-wrapper>
|
||||
<ng-template #mainContentRef>
|
||||
<h4>{{ 'AbpAccount::Register' | abpLocalization }}</h4>
|
||||
<strong>
|
||||
{{ 'AbpAccount::AlreadyRegistered' | abpLocalization }}
|
||||
<a class="text-decoration-none" routerLink="/account/login">{{
|
||||
'AbpAccount::Login' | abpLocalization
|
||||
}}</a>
|
||||
</strong>
|
||||
<form
|
||||
*ngIf="isSelfRegistrationEnabled"
|
||||
[formGroup]="form"
|
||||
(ngSubmit)="onSubmit()"
|
||||
validateOnSubmit
|
||||
class="mt-4"
|
||||
>
|
||||
<div class="form-group">
|
||||
<label for="input-user-name">{{ 'AbpAccount::UserName' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input
|
||||
autofocus
|
||||
type="text"
|
||||
id="input-user-name"
|
||||
class="form-control"
|
||||
formControlName="username"
|
||||
autocomplete="username"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-email-address">{{ 'AbpAccount::EmailAddress' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input type="email" id="input-email-address" class="form-control" formControlName="email" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="input-password">{{ 'AbpAccount::Password' | abpLocalization }}</label
|
||||
><span> * </span
|
||||
><input
|
||||
type="password"
|
||||
id="input-password"
|
||||
class="form-control"
|
||||
formControlName="password"
|
||||
autocomplete="current-password"
|
||||
/>
|
||||
</div>
|
||||
<abp-button
|
||||
[loading]="inProgress"
|
||||
buttonType="submit"
|
||||
name="Action"
|
||||
buttonClass="btn-block btn-lg mt-3 btn btn-primary"
|
||||
>
|
||||
{{ 'AbpAccount::Register' | abpLocalization }}
|
||||
</abp-button>
|
||||
</form>
|
||||
</ng-template>
|
||||
@ -1,93 +0,0 @@
|
||||
import { AuthService, ConfigState } from '@abp/ng.core';
|
||||
import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared';
|
||||
import { Component, Injector, OnInit } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { throwError } from 'rxjs';
|
||||
import { catchError, finalize, switchMap } from 'rxjs/operators';
|
||||
import snq from 'snq';
|
||||
import { RegisterRequest } from '../../models';
|
||||
import { AccountService } from '../../services/account.service';
|
||||
import { eAccountComponents } from '../../enums/components';
|
||||
const { maxLength, required, email } = Validators;
|
||||
|
||||
@Component({
|
||||
selector: 'abp-register',
|
||||
templateUrl: './register.component.html',
|
||||
})
|
||||
export class RegisterComponent implements OnInit {
|
||||
form: FormGroup;
|
||||
|
||||
inProgress: boolean;
|
||||
|
||||
isSelfRegistrationEnabled = true;
|
||||
|
||||
authWrapperKey = eAccountComponents.AuthWrapper;
|
||||
|
||||
constructor(
|
||||
private injector: Injector,
|
||||
private fb: FormBuilder,
|
||||
private accountService: AccountService,
|
||||
private oauthService: OAuthService,
|
||||
private store: Store,
|
||||
private toasterService: ToasterService,
|
||||
private authService: AuthService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.isSelfRegistrationEnabled =
|
||||
(
|
||||
this.store.selectSnapshot(
|
||||
ConfigState.getSetting('Abp.Account.IsSelfRegistrationEnabled'),
|
||||
) || ''
|
||||
).toLowerCase() !== 'false';
|
||||
if (!this.isSelfRegistrationEnabled) {
|
||||
this.toasterService.warn(
|
||||
{
|
||||
key: 'AbpAccount::SelfRegistrationDisabledMessage',
|
||||
defaultValue: 'Self registration is disabled.',
|
||||
},
|
||||
null,
|
||||
{ life: 10000 },
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.form = this.fb.group({
|
||||
username: ['', [required, maxLength(255)]],
|
||||
password: ['', [required, ...getPasswordValidators(this.injector)]],
|
||||
email: ['', [required, email]],
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.form.invalid) return;
|
||||
|
||||
this.inProgress = true;
|
||||
|
||||
const newUser = {
|
||||
userName: this.form.get('username').value,
|
||||
password: this.form.get('password').value,
|
||||
emailAddress: this.form.get('email').value,
|
||||
appName: 'Angular',
|
||||
} as RegisterRequest;
|
||||
|
||||
this.accountService
|
||||
.register(newUser)
|
||||
.pipe(
|
||||
switchMap(() => this.authService.login(newUser.userName, newUser.password)),
|
||||
catchError(err => {
|
||||
this.toasterService.error(
|
||||
snq(() => err.error.error_description) ||
|
||||
snq(() => err.error.error.message, 'AbpAccount::DefaultErrorMessage'),
|
||||
'Error',
|
||||
{ life: 7000 },
|
||||
);
|
||||
return throwError(err);
|
||||
}),
|
||||
finalize(() => (this.inProgress = false)),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
<ng-container *ngIf="(currentTenant$ | async) || {} as currentTenant">
|
||||
<div class="card shadow-sm rounded mb-3">
|
||||
<div class="card-body px-5">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<span style="font-size: 0.8em;" class="text-uppercase text-muted">{{
|
||||
'AbpUiMultiTenancy::Tenant' | abpLocalization
|
||||
}}</span
|
||||
><br />
|
||||
<h6 class="m-0 d-inline-block">
|
||||
<i>{{ currentTenant.name || ('AbpUiMultiTenancy::NotSelected' | abpLocalization) }}</i>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a
|
||||
id="AbpTenantSwitchLink"
|
||||
href="javascript:void(0);"
|
||||
class="btn btn-sm mt-3 btn-outline-primary"
|
||||
(click)="onSwitch()"
|
||||
>{{ 'AbpUiMultiTenancy::Switch' | abpLocalization }}</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy">
|
||||
<ng-template #abpHeader>
|
||||
<h5>Switch Tenant</h5>
|
||||
</ng-template>
|
||||
<ng-template #abpBody>
|
||||
<form (ngSubmit)="save()">
|
||||
<div class="mt-2">
|
||||
<div class="form-group">
|
||||
<label for="name">{{ 'AbpUiMultiTenancy::Name' | abpLocalization }}</label>
|
||||
<input
|
||||
[(ngModel)]="name"
|
||||
type="text"
|
||||
id="name"
|
||||
name="tenant"
|
||||
class="form-control"
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<p>{{ 'AbpUiMultiTenancy::SwitchTenantHint' | abpLocalization }}</p>
|
||||
</div>
|
||||
</form>
|
||||
</ng-template>
|
||||
<ng-template #abpFooter>
|
||||
<button #abpClose type="button" class="btn btn-secondary">
|
||||
{{ 'AbpTenantManagement::Cancel' | abpLocalization }}
|
||||
</button>
|
||||
<abp-button
|
||||
type="abp-button"
|
||||
iconClass="fa fa-check"
|
||||
(click)="save()"
|
||||
[disabled]="currentTenant?.name === name"
|
||||
>
|
||||
<span>{{ 'AbpTenantManagement::Save' | abpLocalization }}</span>
|
||||
</abp-button>
|
||||
</ng-template>
|
||||
</abp-modal>
|
||||
</ng-container>
|
||||
@ -1,69 +0,0 @@
|
||||
import { ABP, GetAppConfiguration, SessionStateService } from '@abp/ng.core';
|
||||
import { ToasterService } from '@abp/ng.theme.shared';
|
||||
import { Component } from '@angular/core';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { finalize, take } from 'rxjs/operators';
|
||||
import { Account } from '../../models/account';
|
||||
import { AccountService } from '../../services/account.service';
|
||||
|
||||
@Component({
|
||||
selector: 'abp-tenant-box',
|
||||
templateUrl: './tenant-box.component.html',
|
||||
})
|
||||
export class TenantBoxComponent
|
||||
implements Account.TenantBoxComponentInputs, Account.TenantBoxComponentOutputs {
|
||||
currentTenant$ = this.sessionState.getTenant$();
|
||||
|
||||
name: string;
|
||||
|
||||
isModalVisible: boolean;
|
||||
|
||||
modalBusy: boolean;
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private toasterService: ToasterService,
|
||||
private accountService: AccountService,
|
||||
private sessionState: SessionStateService,
|
||||
) {}
|
||||
|
||||
onSwitch() {
|
||||
const tenant = this.sessionState.getTenant;
|
||||
this.name = tenant?.name;
|
||||
this.isModalVisible = true;
|
||||
}
|
||||
|
||||
save() {
|
||||
if (!this.name) {
|
||||
this.setTenant(null);
|
||||
this.isModalVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.modalBusy = true;
|
||||
this.accountService
|
||||
.findTenant(this.name)
|
||||
.pipe(finalize(() => (this.modalBusy = false)))
|
||||
.subscribe(({ success, tenantId: id, name }) => {
|
||||
if (!success) {
|
||||
this.showError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.setTenant({ id, name });
|
||||
this.isModalVisible = false;
|
||||
});
|
||||
}
|
||||
|
||||
private setTenant(tenant: ABP.BasicItem) {
|
||||
this.sessionState.setTenant(tenant);
|
||||
return this.store.dispatch(new GetAppConfiguration());
|
||||
}
|
||||
|
||||
private showError() {
|
||||
this.toasterService.error('AbpUiMultiTenancy::GivenTenantIsNotAvailable', 'AbpUi::Error', {
|
||||
messageLocalizationParams: [this.name],
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
export const enum eAccountComponents {
|
||||
Login = 'Account.LoginComponent',
|
||||
Register = 'Account.RegisterComponent',
|
||||
ManageProfile = 'Account.ManageProfileComponent',
|
||||
TenantBox = 'Account.TenantBoxComponent',
|
||||
AuthWrapper = 'Account.AuthWrapperComponent',
|
||||
ChangePassword = 'Account.ChangePasswordComponent',
|
||||
PersonalSettings = 'Account.PersonalSettingsComponent',
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './components';
|
||||
@ -1,15 +0,0 @@
|
||||
import { AuthService } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationFlowGuard implements CanActivate {
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
canActivate() {
|
||||
if (this.authService.isInternalAuth) return true;
|
||||
|
||||
this.authService.initLogin();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
export * from './authentication-flow.guard';
|
||||
export * from './manage-profile.guard';
|
||||
@ -1,18 +0,0 @@
|
||||
import { EnvironmentService } from '@abp/ng.core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||
|
||||
@Injectable()
|
||||
export class ManageProfileGuard implements CanActivate {
|
||||
constructor(private environment: EnvironmentService) {}
|
||||
|
||||
canActivate(_: ActivatedRouteSnapshot, __: RouterStateSnapshot) {
|
||||
const env = this.environment.getEnvironment();
|
||||
if (env.oAuthConfig.responseType === 'code') {
|
||||
window.location.href = `${env.oAuthConfig.issuer}/Account/Manage?returnUrl=${window.location.href}`;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
import { TemplateRef } from '@angular/core';
|
||||
|
||||
export namespace Account {
|
||||
export interface AuthWrapperComponentInputs {
|
||||
readonly mainContentRef: TemplateRef<any>;
|
||||
readonly cancelContentRef?: TemplateRef<any>;
|
||||
}
|
||||
|
||||
//tslint:disable
|
||||
export interface AuthWrapperComponentOutputs {}
|
||||
export interface TenantBoxComponentInputs {}
|
||||
export interface TenantBoxComponentOutputs {}
|
||||
export interface PersonalSettingsComponentInputs {}
|
||||
export interface PersonalSettingsComponentOutputs {}
|
||||
export interface ChangePasswordComponentInputs {}
|
||||
export interface ChangePasswordComponentOutputs {}
|
||||
// tslint:enable
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
export * from './account';
|
||||
export * from './options';
|
||||
export * from './user';
|
||||
export * from './tenant';
|
||||
@ -1,3 +0,0 @@
|
||||
export interface Options {
|
||||
redirectUrl?: string;
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
export interface TenantIdResponse {
|
||||
success: boolean;
|
||||
tenantId: string;
|
||||
name: string;
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
export interface RegisterRequest {
|
||||
userName: string;
|
||||
emailAddress: string;
|
||||
password: string;
|
||||
appName?: string;
|
||||
}
|
||||
|
||||
export interface RegisterResponse {
|
||||
tenantId: string;
|
||||
userName: string;
|
||||
name: string;
|
||||
surname: string;
|
||||
email: string;
|
||||
emailConfirmed: boolean;
|
||||
phoneNumber: string;
|
||||
phoneNumberConfirmed: boolean;
|
||||
lockoutEnabled: boolean;
|
||||
lockoutEnd: string;
|
||||
concurrencyStamp: string;
|
||||
isDeleted: boolean;
|
||||
deleterId: string;
|
||||
deletionTime: string;
|
||||
lastModificationTime: string;
|
||||
lastModifierId: string;
|
||||
creationTime: string;
|
||||
creatorId: string;
|
||||
id: string;
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RestService, Rest } from '@abp/ng.core';
|
||||
import { RegisterResponse, RegisterRequest, TenantIdResponse } from '../models';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AccountService {
|
||||
apiName = 'AbpAccount';
|
||||
|
||||
constructor(private rest: RestService) {}
|
||||
|
||||
findTenant(tenantName: string): Observable<TenantIdResponse> {
|
||||
const request: Rest.Request<null> = {
|
||||
method: 'GET',
|
||||
url: `/api/abp/multi-tenancy/tenants/by-name/${tenantName}`,
|
||||
};
|
||||
|
||||
return this.rest.request<null, TenantIdResponse>(request, { apiName: this.apiName });
|
||||
}
|
||||
|
||||
register(body: RegisterRequest): Observable<RegisterResponse> {
|
||||
const request: Rest.Request<RegisterRequest> = {
|
||||
method: 'POST',
|
||||
url: '/api/account/register',
|
||||
body,
|
||||
};
|
||||
|
||||
return this.rest.request<RegisterRequest, RegisterResponse>(request, {
|
||||
skipHandleError: true,
|
||||
apiName: this.apiName,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './account.service';
|
||||
@ -1,38 +0,0 @@
|
||||
import { createHttpFactory, HttpMethod, SpectatorHttp } from '@ngneat/spectator/jest';
|
||||
import { AccountService } from '../services/account.service';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { RestService, CORE_OPTIONS } from '@abp/ng.core';
|
||||
import { RegisterRequest } from '../models/user';
|
||||
|
||||
describe('AccountService', () => {
|
||||
let spectator: SpectatorHttp<AccountService>;
|
||||
const createHttp = createHttpFactory({
|
||||
dataService: AccountService,
|
||||
providers: [RestService, { provide: CORE_OPTIONS, useValue: { environment: {} } }],
|
||||
mocks: [Store],
|
||||
});
|
||||
|
||||
beforeEach(() => (spectator = createHttp()));
|
||||
|
||||
it('should send a GET to find tenant', () => {
|
||||
spectator.inject(Store).selectSnapshot.andReturn('https://abp.io');
|
||||
spectator.service.findTenant('test').subscribe();
|
||||
spectator.expectOne(
|
||||
'https://abp.io/api/abp/multi-tenancy/tenants/by-name/test',
|
||||
HttpMethod.GET,
|
||||
);
|
||||
});
|
||||
|
||||
it('should send a POST to register API', () => {
|
||||
const mock = {
|
||||
userName: 'test',
|
||||
emailAddress: 'test@test.com',
|
||||
password: 'test1234',
|
||||
appName: 'Angular',
|
||||
} as RegisterRequest;
|
||||
spectator.inject(Store).selectSnapshot.andReturn('https://abp.io');
|
||||
spectator.service.register(mock).subscribe();
|
||||
const req = spectator.expectOne('https://abp.io/api/account/register', HttpMethod.POST);
|
||||
expect(req.request.body).toEqual(mock);
|
||||
});
|
||||
});
|
||||
@ -1 +0,0 @@
|
||||
export * from './options.token';
|
||||
@ -1,4 +0,0 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { Options } from '../models/options';
|
||||
|
||||
export const ACCOUNT_OPTIONS = new InjectionToken<Options>('ACCOUNT_OPTIONS');
|
||||
@ -1,8 +0,0 @@
|
||||
import { Options } from '../models/options';
|
||||
|
||||
export function accountOptionsFactory(options: Options) {
|
||||
return {
|
||||
redirectUrl: '/',
|
||||
...options,
|
||||
};
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
export * from './factory-utils';
|
||||
@ -1,7 +0,0 @@
|
||||
export * from './lib/account.module';
|
||||
export * from './lib/components';
|
||||
export * from './lib/enums';
|
||||
export * from './lib/guards';
|
||||
export * from './lib/models';
|
||||
export * from './lib/services';
|
||||
export * from './lib/tokens';
|
||||
@ -1,19 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.prod.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": ["dom", "es2018"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"fullTemplateTypeCheck": true,
|
||||
"strictInjectionParameters": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.prod.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["**/*.spec.ts", "**/*.d.ts"]
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
{
|
||||
"extends": "../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"abp",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"abp",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,32 +1,22 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
UrlTree,
|
||||
} from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CanActivate, UrlTree } from '@angular/router';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private oauthService: OAuthService, private injector: Injector) {}
|
||||
|
||||
canActivate(
|
||||
_: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot,
|
||||
): Observable<boolean> | boolean | UrlTree {
|
||||
const router = this.injector.get(Router);
|
||||
constructor(private oauthService: OAuthService, private authService: AuthService) {}
|
||||
|
||||
canActivate(): Observable<boolean> | boolean | UrlTree {
|
||||
const hasValidAccessToken = this.oauthService.hasValidAccessToken();
|
||||
if (hasValidAccessToken) {
|
||||
return hasValidAccessToken;
|
||||
}
|
||||
|
||||
router.navigate(['/account/login'], { state: { redirectUrl: state.url } });
|
||||
this.authService.initLogin();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue