mirror of https://github.com/abpframework/abp.git
committed by
GitHub
72 changed files with 932 additions and 2280 deletions
@ -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 { Injectable } from '@angular/core'; |
||||
import { |
import { CanActivate, UrlTree } from '@angular/router'; |
||||
ActivatedRouteSnapshot, |
|
||||
CanActivate, |
|
||||
Router, |
|
||||
RouterStateSnapshot, |
|
||||
UrlTree, |
|
||||
} from '@angular/router'; |
|
||||
import { OAuthService } from 'angular-oauth2-oidc'; |
import { OAuthService } from 'angular-oauth2-oidc'; |
||||
import { Observable } from 'rxjs'; |
import { Observable } from 'rxjs'; |
||||
|
import { AuthService } from '../services/auth.service'; |
||||
|
|
||||
@Injectable({ |
@Injectable({ |
||||
providedIn: 'root', |
providedIn: 'root', |
||||
}) |
}) |
||||
export class AuthGuard implements CanActivate { |
export class AuthGuard implements CanActivate { |
||||
constructor(private oauthService: OAuthService, private injector: Injector) {} |
constructor(private oauthService: OAuthService, private authService: AuthService) {} |
||||
|
|
||||
canActivate( |
|
||||
_: ActivatedRouteSnapshot, |
|
||||
state: RouterStateSnapshot, |
|
||||
): Observable<boolean> | boolean | UrlTree { |
|
||||
const router = this.injector.get(Router); |
|
||||
|
|
||||
|
canActivate(): Observable<boolean> | boolean | UrlTree { |
||||
const hasValidAccessToken = this.oauthService.hasValidAccessToken(); |
const hasValidAccessToken = this.oauthService.hasValidAccessToken(); |
||||
if (hasValidAccessToken) { |
if (hasValidAccessToken) { |
||||
return hasValidAccessToken; |
return hasValidAccessToken; |
||||
} |
} |
||||
|
|
||||
router.navigate(['/account/login'], { state: { redirectUrl: state.url } }); |
this.authService.initLogin(); |
||||
return true; |
return true; |
||||
} |
} |
||||
} |
} |
||||
|
|||||
File diff suppressed because it is too large
Loading…
Reference in new issue