mirror of https://github.com/abpframework/abp.git
71 changed files with 6769 additions and 13 deletions
@ -0,0 +1,36 @@ |
|||
{ |
|||
"extends": ["../../.eslintrc.json"], |
|||
"ignorePatterns": ["!**/*"], |
|||
"overrides": [ |
|||
{ |
|||
"files": ["*.ts"], |
|||
"extends": [ |
|||
"plugin:@nrwl/nx/angular", |
|||
"plugin:@angular-eslint/template/process-inline-templates" |
|||
], |
|||
"rules": { |
|||
"@angular-eslint/directive-selector": [ |
|||
"error", |
|||
{ |
|||
"type": "attribute", |
|||
"prefix": "abp", |
|||
"style": "camelCase" |
|||
} |
|||
], |
|||
"@angular-eslint/component-selector": [ |
|||
"error", |
|||
{ |
|||
"type": "element", |
|||
"prefix": "abp", |
|||
"style": "kebab-case" |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"files": ["*.html"], |
|||
"extends": ["plugin:@nrwl/nx/angular-template"], |
|||
"rules": {} |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<h1> @abp/ng.account </h1> |
|||
|
|||
[docs.abp.io](https://docs.abp.io) |
|||
@ -0,0 +1,7 @@ |
|||
{ |
|||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../../dist/packages/account/config", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import { Injector, ModuleWithProviders, NgModule } from '@angular/core'; |
|||
import { NAVIGATE_TO_MANAGE_PROFILE } from '@abp/ng.core'; |
|||
import { ACCOUNT_ROUTE_PROVIDERS } from './providers/route.provider'; |
|||
import { navigateToManageProfileFactory } from './utils/factories'; |
|||
|
|||
@NgModule() |
|||
export class AccountConfigModule { |
|||
static forRoot(): ModuleWithProviders<AccountConfigModule> { |
|||
return { |
|||
ngModule: AccountConfigModule, |
|||
providers: [ |
|||
ACCOUNT_ROUTE_PROVIDERS, |
|||
{ |
|||
provide: NAVIGATE_TO_MANAGE_PROFILE, |
|||
useFactory: navigateToManageProfileFactory, |
|||
deps: [Injector], |
|||
}, |
|||
], |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route-names'; |
|||
@ -0,0 +1,8 @@ |
|||
export const enum eAccountRouteNames { |
|||
Account = 'AbpAccount::Menu:Account', |
|||
Login = 'AbpAccount::Login', |
|||
Register = 'AbpAccount::Register', |
|||
ManageProfile = 'AbpAccount::MyAccount', |
|||
ForgotPassword = 'AbpAccount::ForgotPassword', |
|||
ResetPassword = 'AbpAccount::ResetPassword', |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './route.provider'; |
|||
@ -0,0 +1,52 @@ |
|||
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(routes: RoutesService) { |
|||
return () => { |
|||
routes.add([ |
|||
{ |
|||
path: undefined, |
|||
name: eAccountRouteNames.Account, |
|||
invisible: true, |
|||
layout: eLayoutType.account, |
|||
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', |
|||
name: eAccountRouteNames.ManageProfile, |
|||
parentName: eAccountRouteNames.Account, |
|||
layout: eLayoutType.application, |
|||
order: 3, |
|||
}, |
|||
{ |
|||
path: '/account/forgot-password', |
|||
parentName: eAccountRouteNames.Account, |
|||
name: eAccountRouteNames.ForgotPassword, |
|||
invisible: true, |
|||
}, |
|||
{ |
|||
path: '/account/reset-password', |
|||
parentName: eAccountRouteNames.Account, |
|||
name: eAccountRouteNames.ResetPassword, |
|||
invisible: true, |
|||
}, |
|||
]); |
|||
}; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export * from './account-config.module'; |
|||
export * from './enums'; |
|||
export * from './providers'; |
|||
@ -0,0 +1,13 @@ |
|||
import { Injector } from '@angular/core'; |
|||
import { RoutesService } from '@abp/ng.core'; |
|||
import { Router } from '@angular/router'; |
|||
import { eAccountRouteNames } from '../enums/route-names'; |
|||
|
|||
export function navigateToManageProfileFactory(injector: Injector) { |
|||
return () => { |
|||
const router = injector.get(Router); |
|||
const routes = injector.get(RoutesService); |
|||
const { path } = routes.find(item => item.name === eAccountRouteNames.ManageProfile); |
|||
router.navigateByUrl(path); |
|||
}; |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
module.exports = { |
|||
displayName: 'account', |
|||
preset: '../../jest.preset.js', |
|||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], |
|||
globals: { |
|||
'ts-jest': { |
|||
tsconfig: '<rootDir>/tsconfig.spec.json', |
|||
stringifyContentPathRegex: '\\.(html|svg)$', |
|||
}, |
|||
}, |
|||
coverageDirectory: '../../coverage/packages/account', |
|||
transform: { |
|||
'^.+\\.(ts|js|html)$': 'jest-preset-angular', |
|||
}, |
|||
snapshotSerializers: [ |
|||
'jest-preset-angular/build/serializers/no-ng-attributes', |
|||
'jest-preset-angular/build/serializers/ng-snapshot', |
|||
'jest-preset-angular/build/serializers/html-comment', |
|||
], |
|||
}; |
|||
@ -0,0 +1,8 @@ |
|||
{ |
|||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
|||
"dest": "../../dist/packages/account", |
|||
"lib": { |
|||
"entryFile": "src/public-api.ts" |
|||
}, |
|||
"allowedNonPeerDependencies": ["@abp/ng.theme.shared"] |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
{ |
|||
"name": "@abp/ng.account", |
|||
"version": "4.4.0", |
|||
"homepage": "https://abp.io", |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/abpframework/abp.git" |
|||
}, |
|||
"dependencies": { |
|||
"@abp/ng.theme.shared": "~4.4.0", |
|||
"tslib": "^2.0.0" |
|||
}, |
|||
"publishConfig": { |
|||
"access": "public" |
|||
} |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
import { |
|||
AuthGuard, |
|||
DynamicLayoutComponent, |
|||
ReplaceableComponents, |
|||
ReplaceableRouteContainerComponent, |
|||
} from '@abp/ng.core'; |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component'; |
|||
import { LoginComponent } from './components/login/login.component'; |
|||
import { ManageProfileComponent } from './components/manage-profile/manage-profile.component'; |
|||
import { RegisterComponent } from './components/register/register.component'; |
|||
import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; |
|||
import { eAccountComponents } from './enums/components'; |
|||
import { AuthenticationFlowGuard } from './guards/authentication-flow.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: 'forgot-password', |
|||
component: ReplaceableRouteContainerComponent, |
|||
canActivate: [AuthenticationFlowGuard], |
|||
data: { |
|||
replaceableComponent: { |
|||
key: eAccountComponents.ForgotPassword, |
|||
defaultComponent: ForgotPasswordComponent, |
|||
} as ReplaceableComponents.RouteData<ForgotPasswordComponent>, |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'reset-password', |
|||
component: ReplaceableRouteContainerComponent, |
|||
canActivate: [], |
|||
data: { |
|||
tenantBoxVisible: false, |
|||
replaceableComponent: { |
|||
key: eAccountComponents.ResetPassword, |
|||
defaultComponent: ResetPasswordComponent, |
|||
} as ReplaceableComponents.RouteData<ResetPasswordComponent>, |
|||
}, |
|||
}, |
|||
{ |
|||
path: 'manage', |
|||
component: ReplaceableRouteContainerComponent, |
|||
canActivate: [AuthGuard], |
|||
data: { |
|||
replaceableComponent: { |
|||
key: eAccountComponents.ManageProfile, |
|||
defaultComponent: ManageProfileComponent, |
|||
} as ReplaceableComponents.RouteData<ManageProfileComponent>, |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule], |
|||
}) |
|||
export class AccountRoutingModule {} |
|||
@ -0,0 +1,59 @@ |
|||
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 { 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 { AccountConfigOptions } from './models/config-options'; |
|||
import { ACCOUNT_CONFIG_OPTIONS } from './tokens/config-options.token'; |
|||
import { accountConfigOptionsFactory } from './utils/factory-utils'; |
|||
import { AuthenticationFlowGuard } from './guards/authentication-flow.guard'; |
|||
import { ForgotPasswordComponent } from './components/forgot-password/forgot-password.component'; |
|||
import { ResetPasswordComponent } from './components/reset-password/reset-password.component'; |
|||
|
|||
const declarations = [ |
|||
LoginComponent, |
|||
RegisterComponent, |
|||
ChangePasswordComponent, |
|||
ManageProfileComponent, |
|||
PersonalSettingsComponent, |
|||
ForgotPasswordComponent, |
|||
ResetPasswordComponent, |
|||
]; |
|||
|
|||
@NgModule({ |
|||
declarations: [...declarations], |
|||
imports: [ |
|||
CoreModule, |
|||
AccountRoutingModule, |
|||
ThemeSharedModule, |
|||
NgbDropdownModule, |
|||
NgxValidateCoreModule, |
|||
], |
|||
exports: [...declarations], |
|||
}) |
|||
export class AccountModule { |
|||
static forChild(options = {} as AccountConfigOptions): ModuleWithProviders<AccountModule> { |
|||
return { |
|||
ngModule: AccountModule, |
|||
providers: [ |
|||
AuthenticationFlowGuard, |
|||
{ provide: ACCOUNT_CONFIG_OPTIONS, useValue: options }, |
|||
{ |
|||
provide: 'ACCOUNT_OPTIONS', |
|||
useFactory: accountConfigOptionsFactory, |
|||
deps: [ACCOUNT_CONFIG_OPTIONS], |
|||
}, |
|||
], |
|||
}; |
|||
} |
|||
|
|||
static forLazy(options = {} as AccountConfigOptions): NgModuleFactory<AccountModule> { |
|||
return new LazyModuleFactory(AccountModule.forChild(options)); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
<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> |
|||
@ -0,0 +1,99 @@ |
|||
import { Profile, ProfileService } from '@abp/ng.core'; |
|||
import { getPasswordValidators, ToasterService } from '@abp/ng.theme.shared'; |
|||
import { Component, Injector, Input, OnInit } from '@angular/core'; |
|||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; |
|||
import { comparePasswords, Validation } from '@ngx-validate/core'; |
|||
import { finalize } from 'rxjs/operators'; |
|||
import snq from 'snq'; |
|||
import { Account } from '../../models/account'; |
|||
import { ManageProfileStateService } from '../../services/manage-profile.state.service'; |
|||
|
|||
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 fb: FormBuilder, |
|||
private injector: Injector, |
|||
private toasterService: ToasterService, |
|||
private profileService: ProfileService, |
|||
private manageProfileState: ManageProfileStateService, |
|||
) {} |
|||
|
|||
ngOnInit(): void { |
|||
this.hideCurrentPassword = !this.manageProfileState.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.profileService |
|||
.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'), |
|||
); |
|||
}, |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
<h4>{{ 'AbpAccount::ForgotPassword' | abpLocalization }}</h4> |
|||
|
|||
<form |
|||
*ngIf="!isEmailSent; else emailSentTemplate" |
|||
[formGroup]="form" |
|||
(ngSubmit)="onSubmit()" |
|||
validateOnSubmit |
|||
> |
|||
<p>{{ 'AbpAccount::SendPasswordResetLink_Information' | abpLocalization }}</p> |
|||
<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> |
|||
<abp-button |
|||
class="d-block" |
|||
buttonClass="mt-2 mb-3 btn btn-primary btn-block" |
|||
[loading]="inProgress" |
|||
buttonType="submit" |
|||
[disabled]="form?.invalid" |
|||
> |
|||
{{ 'AbpAccount::Submit' | abpLocalization }} |
|||
</abp-button> |
|||
<a routerLink="/account/login" |
|||
><i class="fa fa-long-arrow-left mr-1"></i>{{ 'AbpAccount::Login' | abpLocalization }}</a |
|||
> |
|||
</form> |
|||
|
|||
<ng-template #emailSentTemplate> |
|||
<p> |
|||
{{ 'AbpAccount::PasswordResetMailSentMessage' | abpLocalization }} |
|||
</p> |
|||
|
|||
<a routerLink="/account/login"> |
|||
<button class="d-block mt-2 mb-3 btn btn-primary btn-block"> |
|||
<i class="fa fa-long-arrow-left mr-1"></i> |
|||
{{ 'AbpAccount::BackToLogin' | abpLocalization }} |
|||
</button> |
|||
</a> |
|||
</ng-template> |
|||
@ -0,0 +1,35 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { finalize } from 'rxjs/operators'; |
|||
import { AccountService } from '../../proxy/account/account.service'; |
|||
|
|||
@Component({ |
|||
selector: 'abp-forgot-password', |
|||
templateUrl: 'forgot-password.component.html', |
|||
}) |
|||
export class ForgotPasswordComponent { |
|||
form: FormGroup; |
|||
|
|||
inProgress: boolean; |
|||
|
|||
isEmailSent = false; |
|||
|
|||
constructor(private fb: FormBuilder, private accountService: AccountService) { |
|||
this.form = this.fb.group({ |
|||
email: ['', [Validators.required, Validators.email]], |
|||
}); |
|||
} |
|||
|
|||
onSubmit() { |
|||
if (this.form.invalid) return; |
|||
|
|||
this.inProgress = true; |
|||
|
|||
this.accountService |
|||
.sendPasswordResetCode({ email: this.form.get('email').value, appName: 'Angular' }) |
|||
.pipe(finalize(() => (this.inProgress = false))) |
|||
.subscribe(() => { |
|||
this.isEmailSent = true; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
export * from './change-password/change-password.component'; |
|||
export * from './forgot-password/forgot-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 './reset-password/reset-password.component'; |
|||
@ -0,0 +1,60 @@ |
|||
<h4>{{ 'AbpAccount::Login' | abpLocalization }}</h4> |
|||
<strong *ngIf="isSelfRegistrationEnabled"> |
|||
{{ 'AbpAccount::AreYouANewUser' | abpLocalization }} |
|||
<a class="text-decoration-none" routerLink="/account/register" queryParamsHandling="preserve">{{ |
|||
'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="row"> |
|||
<div class="col"> |
|||
<label class="custom-checkbox custom-control mb-2" for="login-input-remember-me"> |
|||
<input |
|||
class="form-check-input" |
|||
type="checkbox" |
|||
id="login-input-remember-me" |
|||
formControlName="rememberMe" |
|||
/> |
|||
{{ 'AbpAccount::RememberMe' | abpLocalization }} |
|||
</label> |
|||
</div> |
|||
<div class="text-right col"> |
|||
<a routerLink="/account/forgot-password">{{ |
|||
'AbpAccount::ForgotPassword' | abpLocalization |
|||
}}</a> |
|||
</div> |
|||
</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> |
|||
@ -0,0 +1,80 @@ |
|||
import { ConfigStateService, AuthService } from '@abp/ng.core'; |
|||
import { 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 { throwError } from 'rxjs'; |
|||
import { catchError, finalize } from 'rxjs/operators'; |
|||
import snq from 'snq'; |
|||
import { eAccountComponents } from '../../enums/components'; |
|||
import { getRedirectUrl } from '../../utils/auth-utils'; |
|||
|
|||
const { maxLength, 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( |
|||
protected injector: Injector, |
|||
protected fb: FormBuilder, |
|||
protected toasterService: ToasterService, |
|||
protected authService: AuthService, |
|||
protected configState: ConfigStateService, |
|||
) {} |
|||
|
|||
ngOnInit() { |
|||
this.init(); |
|||
this.buildForm(); |
|||
} |
|||
|
|||
protected init() { |
|||
this.isSelfRegistrationEnabled = |
|||
( |
|||
(this.configState.getSetting('Abp.Account.IsSelfRegistrationEnabled') as string) || '' |
|||
).toLowerCase() !== 'false'; |
|||
} |
|||
|
|||
protected buildForm() { |
|||
this.form = this.fb.group({ |
|||
username: ['', [required, maxLength(255)]], |
|||
password: ['', [required, maxLength(128)]], |
|||
rememberMe: [false], |
|||
}); |
|||
} |
|||
|
|||
onSubmit() { |
|||
if (this.form.invalid) return; |
|||
|
|||
this.inProgress = true; |
|||
|
|||
const { username, password, rememberMe } = this.form.value; |
|||
|
|||
const redirectUrl = getRedirectUrl(this.injector); |
|||
|
|||
this.authService |
|||
.login({ username, password, rememberMe, redirectUrl }) |
|||
.pipe( |
|||
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(); |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
<div id="AbpContentToolbar"></div> |
|||
|
|||
<div class="card border-0 shadow-sm min-h-400" [abpLoading]="!(profile$ | async)"> |
|||
<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 && (profile$ | async)" |
|||
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="profile$ | async" 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> |
|||
@ -0,0 +1,45 @@ |
|||
import { Profile, ProfileService } from '@abp/ng.core'; |
|||
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 { ManageProfileStateService } from '../../services/manage-profile.state.service'; |
|||
|
|||
@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; |
|||
|
|||
profile$ = this.manageProfileState.getProfile$(); |
|||
|
|||
hideChangePasswordTab: boolean; |
|||
|
|||
constructor( |
|||
protected profileService: ProfileService, |
|||
protected manageProfileState: ManageProfileStateService, |
|||
) {} |
|||
|
|||
ngOnInit() { |
|||
this.profileService.get().subscribe(profile => { |
|||
this.manageProfileState.setProfile(profile); |
|||
if (profile.isExternal) { |
|||
this.hideChangePasswordTab = true; |
|||
this.selectedTab = 1; |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
<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> |
|||
@ -0,0 +1,58 @@ |
|||
import { ProfileService } 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 { finalize } from 'rxjs/operators'; |
|||
import { Account } from '../../models/account'; |
|||
import { ManageProfileStateService } from '../../services/manage-profile.state.service'; |
|||
|
|||
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 toasterService: ToasterService, |
|||
private profileService: ProfileService, |
|||
private manageProfileState: ManageProfileStateService, |
|||
) {} |
|||
|
|||
ngOnInit() { |
|||
this.buildForm(); |
|||
} |
|||
|
|||
buildForm() { |
|||
const profile = this.manageProfileState.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.profileService |
|||
.update(this.form.value) |
|||
.pipe(finalize(() => (this.inProgress = false))) |
|||
.subscribe(profile => { |
|||
this.manageProfileState.setProfile(profile); |
|||
this.toasterService.success('AbpAccount::PersonalSettingsSaved', 'Success', { life: 5000 }); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
<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> |
|||
@ -0,0 +1,102 @@ |
|||
import { AuthService, ConfigStateService } 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 { throwError } from 'rxjs'; |
|||
import { catchError, finalize, switchMap } from 'rxjs/operators'; |
|||
import snq from 'snq'; |
|||
import { eAccountComponents } from '../../enums/components'; |
|||
import { AccountService } from '../../proxy/account/account.service'; |
|||
import { RegisterDto } from '../../proxy/account/models'; |
|||
import { getRedirectUrl } from '../../utils/auth-utils'; |
|||
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( |
|||
protected fb: FormBuilder, |
|||
protected accountService: AccountService, |
|||
protected configState: ConfigStateService, |
|||
protected toasterService: ToasterService, |
|||
protected authService: AuthService, |
|||
protected injector: Injector, |
|||
) {} |
|||
|
|||
ngOnInit() { |
|||
this.init(); |
|||
this.buildForm(); |
|||
} |
|||
|
|||
protected init() { |
|||
this.isSelfRegistrationEnabled = |
|||
(this.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; |
|||
} |
|||
} |
|||
|
|||
protected buildForm() { |
|||
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 RegisterDto; |
|||
|
|||
this.accountService |
|||
.register(newUser) |
|||
.pipe( |
|||
switchMap(() => |
|||
this.authService.login({ |
|||
username: newUser.userName, |
|||
password: newUser.password, |
|||
redirectUrl: getRedirectUrl(this.injector), |
|||
}), |
|||
), |
|||
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(); |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
<h4>{{ 'AbpAccount::ResetPassword' | abpLocalization }}</h4> |
|||
|
|||
<form |
|||
*ngIf="!isPasswordReset; else passwordResetTemplate" |
|||
[formGroup]="form" |
|||
[mapErrorsFn]="mapErrorsFn" |
|||
(ngSubmit)="onSubmit()" |
|||
validateOnSubmit |
|||
> |
|||
<p>{{ 'AbpAccount::ResetPassword_Information' | abpLocalization }}</p> |
|||
<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" /> |
|||
</div> |
|||
<div class="form-group"> |
|||
<label for="input-confirm-password">{{ 'AbpAccount::ConfirmPassword' | abpLocalization }}</label |
|||
><span> * </span> |
|||
<input |
|||
type="password" |
|||
id="input-confirm-password" |
|||
class="form-control" |
|||
formControlName="confirmPassword" |
|||
/> |
|||
</div> |
|||
<button class="mr-2 btn btn-secondary" type="button" routerLink="/account/login"> |
|||
{{ 'AbpAccount::Cancel' | abpLocalization }} |
|||
</button> |
|||
<abp-button |
|||
buttonType="submit" |
|||
buttonClass="mr-2 btn btn-primary" |
|||
[loading]="inProgress" |
|||
(click)="onSubmit()" |
|||
> |
|||
{{ 'AbpAccount::Submit' | abpLocalization }} |
|||
</abp-button> |
|||
</form> |
|||
|
|||
<ng-template #passwordResetTemplate> |
|||
<p> |
|||
{{ 'AbpAccount::YourPasswordIsSuccessfullyReset' | abpLocalization }} |
|||
</p> |
|||
|
|||
<a routerLink="/account/login"> |
|||
<button class="d-block mt-2 mb-3 btn btn-primary"> |
|||
{{ 'AbpAccount::BackToLogin' | abpLocalization }} |
|||
</button> |
|||
</a> |
|||
</ng-template> |
|||
@ -0,0 +1,70 @@ |
|||
import { getPasswordValidators } from '@abp/ng.theme.shared'; |
|||
import { Component, Injector, OnInit } from '@angular/core'; |
|||
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; |
|||
import { ActivatedRoute, Router } from '@angular/router'; |
|||
import { comparePasswords, Validation } from '@ngx-validate/core'; |
|||
import { finalize } from 'rxjs/operators'; |
|||
import { AccountService } from '../../proxy/account/account.service'; |
|||
|
|||
const PASSWORD_FIELDS = ['password', 'confirmPassword']; |
|||
|
|||
@Component({ |
|||
selector: 'abp-reset-password', |
|||
templateUrl: './reset-password.component.html', |
|||
}) |
|||
export class ResetPasswordComponent implements OnInit { |
|||
form: FormGroup; |
|||
|
|||
inProgress = false; |
|||
|
|||
isPasswordReset = false; |
|||
|
|||
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 fb: FormBuilder, |
|||
private accountService: AccountService, |
|||
private route: ActivatedRoute, |
|||
private router: Router, |
|||
private injector: Injector, |
|||
) {} |
|||
|
|||
ngOnInit(): void { |
|||
this.route.queryParams.subscribe(({ userId, resetToken }) => { |
|||
if (!userId || !resetToken) this.router.navigateByUrl('/account/login'); |
|||
|
|||
this.form = this.fb.group( |
|||
{ |
|||
userId: [userId, [Validators.required]], |
|||
resetToken: [resetToken, [Validators.required]], |
|||
password: ['', [Validators.required, ...getPasswordValidators(this.injector)]], |
|||
confirmPassword: ['', [Validators.required, ...getPasswordValidators(this.injector)]], |
|||
}, |
|||
{ |
|||
validators: [comparePasswords(PASSWORD_FIELDS)], |
|||
}, |
|||
); |
|||
}); |
|||
} |
|||
|
|||
onSubmit() { |
|||
if (this.form.invalid || this.inProgress) return; |
|||
|
|||
this.inProgress = true; |
|||
|
|||
this.accountService |
|||
.resetPassword({ |
|||
userId: this.form.get('userId').value, |
|||
resetToken: this.form.get('resetToken').value, |
|||
password: this.form.get('password').value, |
|||
}) |
|||
.pipe(finalize(() => (this.inProgress = false))) |
|||
.subscribe(() => { |
|||
this.isPasswordReset = true; |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
export const enum eAccountComponents { |
|||
Login = 'Account.LoginComponent', |
|||
Register = 'Account.RegisterComponent', |
|||
ForgotPassword = 'Account.ForgotPasswordComponent', |
|||
ResetPassword = 'Account.ResetPasswordComponent', |
|||
ManageProfile = 'Account.ManageProfileComponent', |
|||
TenantBox = 'Account.TenantBoxComponent', |
|||
AuthWrapper = 'Account.AuthWrapperComponent', |
|||
ChangePassword = 'Account.ChangePasswordComponent', |
|||
PersonalSettings = 'Account.PersonalSettingsComponent', |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './components'; |
|||
@ -0,0 +1,15 @@ |
|||
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.navigateToLogin(); |
|||
return false; |
|||
} |
|||
} |
|||
@ -0,0 +1 @@ |
|||
export * from './authentication-flow.guard'; |
|||
@ -0,0 +1,12 @@ |
|||
import { TemplateRef } from '@angular/core'; |
|||
|
|||
export namespace Account { |
|||
//tslint:disable
|
|||
export interface TenantBoxComponentInputs {} |
|||
export interface TenantBoxComponentOutputs {} |
|||
export interface PersonalSettingsComponentInputs {} |
|||
export interface PersonalSettingsComponentOutputs {} |
|||
export interface ChangePasswordComponentInputs {} |
|||
export interface ChangePasswordComponentOutputs {} |
|||
// tslint:enable
|
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
export interface AccountConfigOptions { |
|||
redirectUrl?: string; |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export * from './account'; |
|||
export * from './config-options'; |
|||
@ -0,0 +1,17 @@ |
|||
# Proxy Generation Output |
|||
|
|||
This directory includes the output of the latest proxy generation. |
|||
The files and folders in it will be overwritten when proxy generation is run again. |
|||
Therefore, please do not place your own content in this folder. |
|||
|
|||
In addition, `generate-proxy.json` works like a lock file. |
|||
It includes information used by the proxy generator, so please do not delete or modify it. |
|||
|
|||
Finally, the name of the files and folders should not be changed for two reasons: |
|||
- Proxy generator will keep creating them at those paths and you will have multiple copies of the same content. |
|||
- ABP Suite generates files which include imports from this folder. |
|||
|
|||
> **Important Notice:** If you are building a module and are planning to publish to npm, |
|||
> some of the generated proxies are likely to be exported from public-api.ts file. In such a case, |
|||
> please make sure you export files directly and not from barrel exports. In other words, |
|||
> do not include index.ts exports in your public-api.ts exports. |
|||
@ -0,0 +1,37 @@ |
|||
import type { RegisterDto, ResetPasswordDto, SendPasswordResetCodeDto } from './models'; |
|||
import { RestService } from '@abp/ng.core'; |
|||
import { Injectable } from '@angular/core'; |
|||
import type { IdentityUserDto } from '../identity/models'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class AccountService { |
|||
apiName = 'AbpAccount'; |
|||
|
|||
register = (input: RegisterDto) => |
|||
this.restService.request<any, IdentityUserDto>({ |
|||
method: 'POST', |
|||
url: '/api/account/register', |
|||
body: input, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
resetPassword = (input: ResetPasswordDto) => |
|||
this.restService.request<any, void>({ |
|||
method: 'POST', |
|||
url: '/api/account/reset-password', |
|||
body: input, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
sendPasswordResetCode = (input: SendPasswordResetCodeDto) => |
|||
this.restService.request<any, void>({ |
|||
method: 'POST', |
|||
url: '/api/account/send-password-reset-code', |
|||
body: input, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
constructor(private restService: RestService) {} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
import * as Web from './web'; |
|||
export * from './account.service'; |
|||
export * from './models'; |
|||
export { Web }; |
|||
@ -0,0 +1,21 @@ |
|||
import type { ExtensibleObject } from '@abp/ng.core'; |
|||
|
|||
export interface RegisterDto extends ExtensibleObject { |
|||
userName: string; |
|||
emailAddress: string; |
|||
password: string; |
|||
appName: string; |
|||
} |
|||
|
|||
export interface ResetPasswordDto { |
|||
userId?: string; |
|||
resetToken: string; |
|||
password: string; |
|||
} |
|||
|
|||
export interface SendPasswordResetCodeDto { |
|||
email: string; |
|||
appName: string; |
|||
returnUrl?: string; |
|||
returnUrlHash?: string; |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
import type { AbpLoginResult, UserLoginInfo } from './models/models'; |
|||
import { RestService } from '@abp/ng.core'; |
|||
import { Injectable } from '@angular/core'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root', |
|||
}) |
|||
export class AccountService { |
|||
apiName = 'AbpAccount'; |
|||
|
|||
checkPasswordByLogin = (login: UserLoginInfo) => |
|||
this.restService.request<any, AbpLoginResult>({ |
|||
method: 'POST', |
|||
url: '/api/account/check-password', |
|||
body: login, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
loginByLogin = (login: UserLoginInfo) => |
|||
this.restService.request<any, AbpLoginResult>({ |
|||
method: 'POST', |
|||
url: '/api/account/login', |
|||
body: login, |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
logout = () => |
|||
this.restService.request<any, void>({ |
|||
method: 'GET', |
|||
url: '/api/account/logout', |
|||
}, |
|||
{ apiName: this.apiName }); |
|||
|
|||
constructor(private restService: RestService) {} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
import * as Models from './models'; |
|||
export * from './account.service'; |
|||
export { Models }; |
|||
@ -0,0 +1,2 @@ |
|||
export * from './login-result-type.enum'; |
|||
export * from './models'; |
|||
@ -0,0 +1,11 @@ |
|||
import { mapEnumToOptions } from '@abp/ng.core'; |
|||
|
|||
export enum LoginResultType { |
|||
Success = 1, |
|||
InvalidUserNameOrPassword = 2, |
|||
NotAllowed = 3, |
|||
LockedOut = 4, |
|||
RequiresTwoFactor = 5, |
|||
} |
|||
|
|||
export const loginResultTypeOptions = mapEnumToOptions(LoginResultType); |
|||
@ -0,0 +1,12 @@ |
|||
import type { LoginResultType } from './login-result-type.enum'; |
|||
|
|||
export interface AbpLoginResult { |
|||
result: LoginResultType; |
|||
description?: string; |
|||
} |
|||
|
|||
export interface UserLoginInfo { |
|||
userNameOrEmailAddress: string; |
|||
password: string; |
|||
rememberMe: boolean; |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
import * as Controllers from './controllers'; |
|||
export { Controllers }; |
|||
@ -0,0 +1,2 @@ |
|||
import * as Account from './account'; |
|||
export { Account }; |
|||
@ -0,0 +1,2 @@ |
|||
import * as Areas from './areas'; |
|||
export { Areas }; |
|||
File diff suppressed because it is too large
@ -0,0 +1 @@ |
|||
export * from './models'; |
|||
@ -0,0 +1,15 @@ |
|||
import type { ExtensibleFullAuditedEntityDto } from '@abp/ng.core'; |
|||
|
|||
export interface IdentityUserDto extends ExtensibleFullAuditedEntityDto<string> { |
|||
tenantId?: string; |
|||
userName?: string; |
|||
name?: string; |
|||
surname?: string; |
|||
email?: string; |
|||
emailConfirmed: boolean; |
|||
phoneNumber?: string; |
|||
phoneNumberConfirmed: boolean; |
|||
lockoutEnabled: boolean; |
|||
lockoutEnd?: string; |
|||
concurrencyStamp?: string; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
import * as Account from './account'; |
|||
import * as Identity from './identity'; |
|||
export { Account, Identity }; |
|||
@ -0,0 +1 @@ |
|||
export * from './manage-profile.state.service'; |
|||
@ -0,0 +1,28 @@ |
|||
import { Injectable } from '@angular/core'; |
|||
import { InternalStore, Profile } from '@abp/ng.core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
export interface ManageProfileState { |
|||
profile: Profile.Response; |
|||
} |
|||
|
|||
@Injectable({ providedIn: 'root' }) |
|||
export class ManageProfileStateService { |
|||
private readonly store = new InternalStore({} as ManageProfileState); |
|||
|
|||
get createOnUpdateStream() { |
|||
return this.store.sliceUpdate; |
|||
} |
|||
|
|||
getProfile$(): Observable<Profile.Response> { |
|||
return this.store.sliceState(state => state.profile); |
|||
} |
|||
|
|||
getProfile(): Profile.Response { |
|||
return this.store.state.profile; |
|||
} |
|||
|
|||
setProfile(profile: Profile.Response) { |
|||
this.store.patch({ profile }); |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
import { InjectionToken } from '@angular/core'; |
|||
import { AccountConfigOptions } from '../models/config-options'; |
|||
|
|||
export const ACCOUNT_CONFIG_OPTIONS = new InjectionToken<AccountConfigOptions>( |
|||
'ACCOUNT_CONFIG_OPTIONS', |
|||
); |
|||
@ -0,0 +1 @@ |
|||
export * from './config-options.token'; |
|||
@ -0,0 +1,9 @@ |
|||
import { Injector } from '@angular/core'; |
|||
import { ActivatedRoute } from '@angular/router'; |
|||
import { ACCOUNT_CONFIG_OPTIONS } from '../tokens/config-options.token'; |
|||
|
|||
export function getRedirectUrl(injector: Injector) { |
|||
const route = injector.get(ActivatedRoute); |
|||
const options = injector.get(ACCOUNT_CONFIG_OPTIONS); |
|||
return route.snapshot.queryParams.returnUrl || options.redirectUrl || '/'; |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
import { AccountConfigOptions } from '../models/config-options'; |
|||
|
|||
export function accountConfigOptionsFactory(options: AccountConfigOptions) { |
|||
return { |
|||
redirectUrl: '/', |
|||
...options, |
|||
}; |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
export * from './auth-utils'; |
|||
export * from './factory-utils'; |
|||
@ -0,0 +1,9 @@ |
|||
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'; |
|||
export * from './lib/proxy/account'; |
|||
export * from './lib/proxy/identity'; |
|||
@ -0,0 +1 @@ |
|||
import 'jest-preset-angular/setup-jest'; |
|||
@ -0,0 +1,13 @@ |
|||
{ |
|||
"extends": "../../tsconfig.base.json", |
|||
"files": [], |
|||
"include": [], |
|||
"references": [ |
|||
{ |
|||
"path": "./tsconfig.lib.json" |
|||
}, |
|||
{ |
|||
"path": "./tsconfig.spec.json" |
|||
} |
|||
] |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
{ |
|||
"extends": "./tsconfig.json", |
|||
"compilerOptions": { |
|||
"outDir": "../../dist/out-tsc", |
|||
"target": "es2015", |
|||
"declaration": true, |
|||
"declarationMap": true, |
|||
"inlineSources": true, |
|||
"types": [], |
|||
"lib": ["dom", "es2018"] |
|||
}, |
|||
"exclude": ["src/test-setup.ts", "**/*.spec.ts"], |
|||
"include": ["**/*.ts"] |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
/* To learn more about this file see: https://angular.io/config/tsconfig. */ |
|||
{ |
|||
"extends": "./tsconfig.lib.json", |
|||
"compilerOptions": { |
|||
"declarationMap": false |
|||
}, |
|||
"angularCompilerOptions": { |
|||
"compilationMode": "partial", |
|||
"enableIvy": false |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
{ |
|||
"extends": "./tsconfig.json", |
|||
"compilerOptions": { |
|||
"outDir": "../../dist/out-tsc", |
|||
"module": "commonjs", |
|||
"types": ["jest", "node"] |
|||
}, |
|||
"files": ["src/test-setup.ts"], |
|||
"include": ["**/*.spec.ts", "**/*.d.ts"] |
|||
} |
|||
Loading…
Reference in new issue