mirror of https://github.com/abpframework/abp.git
62 changed files with 6292 additions and 1 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.identity </h1> |
||||
|
|
||||
|
[docs.abp.io](https://docs.abp.io) |
||||
@ -0,0 +1,7 @@ |
|||||
|
{ |
||||
|
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../../dist/packages/identity/config", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
export * from './policy-names'; |
||||
|
export * from './route-names'; |
||||
@ -0,0 +1,5 @@ |
|||||
|
export const enum eIdentityPolicyNames { |
||||
|
IdentityManagement = 'AbpIdentity.Roles || AbpIdentity.Users', |
||||
|
Roles = 'AbpIdentity.Roles', |
||||
|
Users = 'AbpIdentity.Users', |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
export const enum eIdentityRouteNames { |
||||
|
IdentityManagement = 'AbpIdentity::Menu:IdentityManagement', |
||||
|
Roles = 'AbpIdentity::Roles', |
||||
|
Users = 'AbpIdentity::Users', |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
import { ModuleWithProviders, NgModule } from '@angular/core'; |
||||
|
import { IDENTITY_ROUTE_PROVIDERS } from './providers/route.provider'; |
||||
|
|
||||
|
@NgModule() |
||||
|
export class IdentityConfigModule { |
||||
|
static forRoot(): ModuleWithProviders<IdentityConfigModule> { |
||||
|
return { |
||||
|
ngModule: IdentityConfigModule, |
||||
|
providers: [IDENTITY_ROUTE_PROVIDERS], |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './route.provider'; |
||||
@ -0,0 +1,39 @@ |
|||||
|
import { eLayoutType, RoutesService } from '@abp/ng.core'; |
||||
|
import { eThemeSharedRouteNames } from '@abp/ng.theme.shared'; |
||||
|
import { APP_INITIALIZER } from '@angular/core'; |
||||
|
import { eIdentityPolicyNames } from '../enums/policy-names'; |
||||
|
import { eIdentityRouteNames } from '../enums/route-names'; |
||||
|
|
||||
|
export const IDENTITY_ROUTE_PROVIDERS = [ |
||||
|
{ provide: APP_INITIALIZER, useFactory: configureRoutes, deps: [RoutesService], multi: true }, |
||||
|
]; |
||||
|
|
||||
|
export function configureRoutes(routesService: RoutesService) { |
||||
|
return () => { |
||||
|
routesService.add([ |
||||
|
{ |
||||
|
path: undefined, |
||||
|
name: eIdentityRouteNames.IdentityManagement, |
||||
|
parentName: eThemeSharedRouteNames.Administration, |
||||
|
requiredPolicy: eIdentityPolicyNames.IdentityManagement, |
||||
|
iconClass: 'fa fa-id-card-o', |
||||
|
layout: eLayoutType.application, |
||||
|
order: 1, |
||||
|
}, |
||||
|
{ |
||||
|
path: '/identity/roles', |
||||
|
name: eIdentityRouteNames.Roles, |
||||
|
parentName: eIdentityRouteNames.IdentityManagement, |
||||
|
requiredPolicy: eIdentityPolicyNames.Roles, |
||||
|
order: 1, |
||||
|
}, |
||||
|
{ |
||||
|
path: '/identity/users', |
||||
|
name: eIdentityRouteNames.Users, |
||||
|
parentName: eIdentityRouteNames.IdentityManagement, |
||||
|
requiredPolicy: eIdentityPolicyNames.Users, |
||||
|
order: 2, |
||||
|
}, |
||||
|
]); |
||||
|
}; |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
export * from './enums'; |
||||
|
export * from './identity-config.module'; |
||||
|
export * from './providers'; |
||||
@ -0,0 +1,20 @@ |
|||||
|
module.exports = { |
||||
|
displayName: 'identity', |
||||
|
preset: '../../jest.preset.js', |
||||
|
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], |
||||
|
globals: { |
||||
|
'ts-jest': { |
||||
|
tsconfig: '<rootDir>/tsconfig.spec.json', |
||||
|
stringifyContentPathRegex: '\\.(html|svg)$', |
||||
|
}, |
||||
|
}, |
||||
|
coverageDirectory: '../../coverage/packages/identity', |
||||
|
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,11 @@ |
|||||
|
{ |
||||
|
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json", |
||||
|
"dest": "../../dist/packages/identity", |
||||
|
"lib": { |
||||
|
"entryFile": "src/public-api.ts" |
||||
|
}, |
||||
|
"allowedNonPeerDependencies": [ |
||||
|
"@abp/ng.theme.shared", |
||||
|
"@abp/ng.permission-management" |
||||
|
] |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"name": "@abp/ng.identity", |
||||
|
"version": "4.4.0", |
||||
|
"homepage": "https://abp.io", |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "https://github.com/abpframework/abp.git" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@abp/ng.permission-management": "~4.4.0", |
||||
|
"@abp/ng.theme.shared": "~4.4.0", |
||||
|
"tslib": "^2.0.0" |
||||
|
}, |
||||
|
"publishConfig": { |
||||
|
"access": "public" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
import { Identity } from '../models/identity'; |
||||
|
import { ABP, PagedAndSortedResultRequestDto } from '@abp/ng.core'; |
||||
|
import { |
||||
|
GetIdentityUsersInput, |
||||
|
IdentityRoleCreateDto, |
||||
|
IdentityRoleUpdateDto, |
||||
|
IdentityUserCreateDto, |
||||
|
IdentityUserUpdateDto, |
||||
|
} from '../proxy/identity/models'; |
||||
|
|
||||
|
export class GetRoles { |
||||
|
static readonly type = '[Identity] Get Roles'; |
||||
|
constructor(public payload?: PagedAndSortedResultRequestDto) {} |
||||
|
} |
||||
|
|
||||
|
export class GetRoleById { |
||||
|
static readonly type = '[Identity] Get Role By Id'; |
||||
|
constructor(public payload: string) {} |
||||
|
} |
||||
|
|
||||
|
export class DeleteRole { |
||||
|
static readonly type = '[Identity] Delete Role'; |
||||
|
constructor(public payload: string) {} |
||||
|
} |
||||
|
|
||||
|
export class CreateRole { |
||||
|
static readonly type = '[Identity] Create Role'; |
||||
|
constructor(public payload: IdentityRoleCreateDto) {} |
||||
|
} |
||||
|
|
||||
|
export class UpdateRole { |
||||
|
static readonly type = '[Identity] Update Role'; |
||||
|
constructor(public payload: IdentityRoleUpdateDto & { id: string }) {} |
||||
|
} |
||||
|
|
||||
|
export class GetUsers { |
||||
|
static readonly type = '[Identity] Get Users'; |
||||
|
constructor(public payload?: GetIdentityUsersInput) {} |
||||
|
} |
||||
|
|
||||
|
export class GetUserById { |
||||
|
static readonly type = '[Identity] Get User By Id'; |
||||
|
constructor(public payload: string) {} |
||||
|
} |
||||
|
|
||||
|
export class DeleteUser { |
||||
|
static readonly type = '[Identity] Delete User'; |
||||
|
constructor(public payload: string) {} |
||||
|
} |
||||
|
|
||||
|
export class CreateUser { |
||||
|
static readonly type = '[Identity] Create User'; |
||||
|
constructor(public payload: IdentityUserCreateDto) {} |
||||
|
} |
||||
|
|
||||
|
export class UpdateUser { |
||||
|
static readonly type = '[Identity] Update User'; |
||||
|
constructor(public payload: IdentityUserUpdateDto & { id: string }) {} |
||||
|
} |
||||
|
|
||||
|
export class GetUserRoles { |
||||
|
static readonly type = '[Identity] Get User Roles'; |
||||
|
constructor(public payload: string) {} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './identity.actions'; |
||||
@ -0,0 +1,2 @@ |
|||||
|
export * from './roles/roles.component'; |
||||
|
export * from './users/users.component'; |
||||
@ -0,0 +1,60 @@ |
|||||
|
<div id="identity-roles-wrapper" class="card"> |
||||
|
<div class="card-header"> |
||||
|
<div class="row"> |
||||
|
<div class="col col-md-6"> |
||||
|
<h5 class="card-title">{{ 'AbpIdentity::Roles' | abpLocalization }}</h5> |
||||
|
</div> |
||||
|
<div class="text-right col col-md-6"> |
||||
|
<abp-page-toolbar [record]="data$ | async"></abp-page-toolbar> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="card-body"> |
||||
|
<abp-extensible-table |
||||
|
[data]="data$ | async" |
||||
|
[recordsTotal]="totalCount$ | async" |
||||
|
[list]="list" |
||||
|
></abp-extensible-table> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy"> |
||||
|
<ng-template #abpHeader> |
||||
|
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewRole') | abpLocalization }}</h3> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpBody> |
||||
|
<form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit> |
||||
|
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form> |
||||
|
</form> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpFooter> |
||||
|
<button type="button" class="btn btn-secondary" abpClose> |
||||
|
{{ 'AbpIdentity::Cancel' | abpLocalization }} |
||||
|
</button> |
||||
|
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{ |
||||
|
'AbpIdentity::Save' | abpLocalization |
||||
|
}}</abp-button> |
||||
|
</ng-template> |
||||
|
</abp-modal> |
||||
|
|
||||
|
<abp-permission-management |
||||
|
#abpPermissionManagement="abpPermissionManagement" |
||||
|
*abpReplaceableTemplate=" |
||||
|
{ |
||||
|
inputs: { |
||||
|
providerName: { value: 'R' }, |
||||
|
providerKey: { value: providerKey }, |
||||
|
visible: { value: visiblePermissions, twoWay: true }, |
||||
|
hideBadges: { value: true } |
||||
|
}, |
||||
|
outputs: { visibleChange: onVisiblePermissionChange }, |
||||
|
componentKey: permissionManagementKey |
||||
|
}; |
||||
|
let init = initTemplate |
||||
|
" |
||||
|
(abpInit)="init(abpPermissionManagement)" |
||||
|
> |
||||
|
</abp-permission-management> |
||||
@ -0,0 +1,142 @@ |
|||||
|
import { ListService, PagedAndSortedResultRequestDto } from '@abp/ng.core'; |
||||
|
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; |
||||
|
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared'; |
||||
|
import { |
||||
|
EXTENSIONS_IDENTIFIER, |
||||
|
FormPropData, |
||||
|
generateFormFromProps, |
||||
|
} from '@abp/ng.theme.shared/extensions'; |
||||
|
import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; |
||||
|
import { FormGroup } from '@angular/forms'; |
||||
|
import { Select, Store } from '@ngxs/store'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { finalize, pluck } from 'rxjs/operators'; |
||||
|
import { |
||||
|
CreateRole, |
||||
|
DeleteRole, |
||||
|
GetRoleById, |
||||
|
GetRoles, |
||||
|
UpdateRole, |
||||
|
} from '../../actions/identity.actions'; |
||||
|
import { eIdentityComponents } from '../../enums/components'; |
||||
|
import { IdentityRoleDto } from '../../proxy/identity/models'; |
||||
|
import { IdentityState } from '../../states/identity.state'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'abp-roles', |
||||
|
templateUrl: './roles.component.html', |
||||
|
providers: [ |
||||
|
ListService, |
||||
|
{ |
||||
|
provide: EXTENSIONS_IDENTIFIER, |
||||
|
useValue: eIdentityComponents.Roles, |
||||
|
}, |
||||
|
], |
||||
|
}) |
||||
|
export class RolesComponent implements OnInit { |
||||
|
@Select(IdentityState.getRoles) |
||||
|
data$: Observable<IdentityRoleDto[]>; |
||||
|
|
||||
|
@Select(IdentityState.getRolesTotalCount) |
||||
|
totalCount$: Observable<number>; |
||||
|
|
||||
|
form: FormGroup; |
||||
|
|
||||
|
selected: IdentityRoleDto; |
||||
|
|
||||
|
isModalVisible: boolean; |
||||
|
|
||||
|
visiblePermissions = false; |
||||
|
|
||||
|
providerKey: string; |
||||
|
|
||||
|
modalBusy = false; |
||||
|
|
||||
|
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; |
||||
|
|
||||
|
onVisiblePermissionChange = event => { |
||||
|
this.visiblePermissions = event; |
||||
|
}; |
||||
|
|
||||
|
constructor( |
||||
|
public readonly list: ListService<PagedAndSortedResultRequestDto>, |
||||
|
protected confirmationService: ConfirmationService, |
||||
|
protected store: Store, |
||||
|
protected injector: Injector, |
||||
|
) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.hookToQuery(); |
||||
|
} |
||||
|
|
||||
|
buildForm() { |
||||
|
const data = new FormPropData(this.injector, this.selected); |
||||
|
this.form = generateFormFromProps(data); |
||||
|
} |
||||
|
|
||||
|
openModal() { |
||||
|
this.buildForm(); |
||||
|
this.isModalVisible = true; |
||||
|
} |
||||
|
|
||||
|
add() { |
||||
|
this.selected = {} as IdentityRoleDto; |
||||
|
this.openModal(); |
||||
|
} |
||||
|
|
||||
|
edit(id: string) { |
||||
|
this.store |
||||
|
.dispatch(new GetRoleById(id)) |
||||
|
.pipe(pluck('IdentityState', 'selectedRole')) |
||||
|
.subscribe(selectedRole => { |
||||
|
this.selected = selectedRole; |
||||
|
this.openModal(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
save() { |
||||
|
if (!this.form.valid) return; |
||||
|
this.modalBusy = true; |
||||
|
|
||||
|
this.store |
||||
|
.dispatch( |
||||
|
this.selected.id |
||||
|
? new UpdateRole({ ...this.selected, ...this.form.value, id: this.selected.id }) |
||||
|
: new CreateRole(this.form.value), |
||||
|
) |
||||
|
.pipe(finalize(() => (this.modalBusy = false))) |
||||
|
.subscribe(() => { |
||||
|
this.isModalVisible = false; |
||||
|
this.list.get(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
delete(id: string, name: string) { |
||||
|
this.confirmationService |
||||
|
.warn('AbpIdentity::RoleDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { |
||||
|
messageLocalizationParams: [name], |
||||
|
}) |
||||
|
.subscribe((status: Confirmation.Status) => { |
||||
|
if (status === Confirmation.Status.confirm) { |
||||
|
this.store.dispatch(new DeleteRole(id)).subscribe(() => this.list.get()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private hookToQuery() { |
||||
|
this.list.hookToQuery(query => this.store.dispatch(new GetRoles(query))).subscribe(); |
||||
|
} |
||||
|
|
||||
|
openPermissionsModal(providerKey: string) { |
||||
|
this.providerKey = providerKey; |
||||
|
setTimeout(() => { |
||||
|
this.visiblePermissions = true; |
||||
|
}, 0); |
||||
|
} |
||||
|
|
||||
|
sort(data) { |
||||
|
const { prop, dir } = data.sorts[0]; |
||||
|
this.list.sortKey = prop; |
||||
|
this.list.sortOrder = dir; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,102 @@ |
|||||
|
<div id="identity-roles-wrapper" class="card"> |
||||
|
<div class="card-header"> |
||||
|
<div class="row"> |
||||
|
<div class="col col-md-6"> |
||||
|
<h5 class="card-title">{{ 'AbpIdentity::Users' | abpLocalization }}</h5> |
||||
|
</div> |
||||
|
<div class="text-right col col-md-6"> |
||||
|
<abp-page-toolbar [record]="data$ | async"></abp-page-toolbar> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card-body"> |
||||
|
<div id="data-tables-table-filter" class="data-tables-filter"> |
||||
|
<div class="input-group"> |
||||
|
<input |
||||
|
type="search" |
||||
|
class="form-control" |
||||
|
[placeholder]="'AbpUi::PagerSearch' | abpLocalization" |
||||
|
[(ngModel)]="list.filter" |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<abp-extensible-table |
||||
|
[data]="data$ | async" |
||||
|
[recordsTotal]="totalCount$ | async" |
||||
|
[list]="list" |
||||
|
></abp-extensible-table> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<abp-modal size="md" [(visible)]="isModalVisible" [busy]="modalBusy"> |
||||
|
<ng-template #abpHeader> |
||||
|
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpBody> |
||||
|
<ng-template #loaderRef |
||||
|
><div class="text-center"><i class="fa fa-pulse fa-spinner"></i></div |
||||
|
></ng-template> |
||||
|
|
||||
|
<form *ngIf="form; else loaderRef" [formGroup]="form" (ngSubmit)="save()"> |
||||
|
<ul ngbNav #nav="ngbNav" class="nav-tabs"> |
||||
|
<li ngbNavItem> |
||||
|
<a ngbNavLink>{{ 'AbpIdentity::UserInformations' | abpLocalization }}</a> |
||||
|
<ng-template ngbNavContent> |
||||
|
<abp-extensible-form [selectedRecord]="selected"></abp-extensible-form> |
||||
|
</ng-template> |
||||
|
</li> |
||||
|
|
||||
|
<li ngbNavItem> |
||||
|
<a ngbNavLink>{{ 'AbpIdentity::Roles' | abpLocalization }}</a> |
||||
|
<ng-template ngbNavContent> |
||||
|
<div |
||||
|
*ngFor="let roleGroup of roleGroups; let i = index; trackBy: trackByFn" |
||||
|
class="custom-checkbox custom-control mb-2" |
||||
|
> |
||||
|
<input |
||||
|
type="checkbox" |
||||
|
class="custom-control-input" |
||||
|
[attr.id]="'roles-' + i" |
||||
|
[formControl]="roleGroup.controls[roles[i].name]" |
||||
|
/> |
||||
|
<label class="custom-control-label" [attr.for]="'roles-' + i">{{ |
||||
|
roles[i].name |
||||
|
}}</label> |
||||
|
</div> |
||||
|
</ng-template> |
||||
|
</li> |
||||
|
</ul> |
||||
|
|
||||
|
<div class="mt-2 fade-in-top" [ngbNavOutlet]="nav"></div> |
||||
|
</form> |
||||
|
</ng-template> |
||||
|
|
||||
|
<ng-template #abpFooter> |
||||
|
<button type="button" class="btn btn-secondary" abpClose> |
||||
|
{{ 'AbpIdentity::Cancel' | abpLocalization }} |
||||
|
</button> |
||||
|
<abp-button iconClass="fa fa-check" [disabled]="form?.invalid" (click)="save()">{{ |
||||
|
'AbpIdentity::Save' | abpLocalization |
||||
|
}}</abp-button> |
||||
|
</ng-template> |
||||
|
</abp-modal> |
||||
|
|
||||
|
<abp-permission-management |
||||
|
#abpPermissionManagement="abpPermissionManagement" |
||||
|
*abpReplaceableTemplate=" |
||||
|
{ |
||||
|
inputs: { |
||||
|
providerName: { value: 'U' }, |
||||
|
providerKey: { value: providerKey }, |
||||
|
visible: { value: visiblePermissions, twoWay: true } |
||||
|
}, |
||||
|
outputs: { visibleChange: onVisiblePermissionChange }, |
||||
|
componentKey: permissionManagementKey |
||||
|
}; |
||||
|
let init = initTemplate |
||||
|
" |
||||
|
(abpInit)="init(abpPermissionManagement)" |
||||
|
> |
||||
|
</abp-permission-management> |
||||
@ -0,0 +1,211 @@ |
|||||
|
import { ListService } from '@abp/ng.core'; |
||||
|
import { ePermissionManagementComponents } from '@abp/ng.permission-management'; |
||||
|
import { Confirmation, ConfirmationService } from '@abp/ng.theme.shared'; |
||||
|
import { |
||||
|
EXTENSIONS_IDENTIFIER, |
||||
|
FormPropData, |
||||
|
generateFormFromProps, |
||||
|
} from '@abp/ng.theme.shared/extensions'; |
||||
|
import { |
||||
|
Component, |
||||
|
Injector, |
||||
|
OnInit, |
||||
|
TemplateRef, |
||||
|
TrackByFunction, |
||||
|
ViewChild, |
||||
|
} from '@angular/core'; |
||||
|
import { AbstractControl, FormArray, FormBuilder, FormGroup } from '@angular/forms'; |
||||
|
import { Select, Store } from '@ngxs/store'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { finalize, pluck, switchMap, take } from 'rxjs/operators'; |
||||
|
import snq from 'snq'; |
||||
|
import { |
||||
|
CreateUser, |
||||
|
DeleteUser, |
||||
|
GetUserById, |
||||
|
GetUserRoles, |
||||
|
GetUsers, |
||||
|
UpdateUser, |
||||
|
} from '../../actions/identity.actions'; |
||||
|
import { eIdentityComponents } from '../../enums/components'; |
||||
|
import { Identity } from '../../models/identity'; |
||||
|
import { IdentityUserService } from '../../proxy/identity/identity-user.service'; |
||||
|
import { |
||||
|
GetIdentityUsersInput, |
||||
|
IdentityRoleDto, |
||||
|
IdentityUserDto, |
||||
|
} from '../../proxy/identity/models'; |
||||
|
import { IdentityState } from '../../states/identity.state'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'abp-users', |
||||
|
templateUrl: './users.component.html', |
||||
|
providers: [ |
||||
|
ListService, |
||||
|
{ |
||||
|
provide: EXTENSIONS_IDENTIFIER, |
||||
|
useValue: eIdentityComponents.Users, |
||||
|
}, |
||||
|
], |
||||
|
}) |
||||
|
export class UsersComponent implements OnInit { |
||||
|
@Select(IdentityState.getUsers) |
||||
|
data$: Observable<IdentityUserDto[]>; |
||||
|
|
||||
|
@Select(IdentityState.getUsersTotalCount) |
||||
|
totalCount$: Observable<number>; |
||||
|
|
||||
|
@ViewChild('modalContent', { static: false }) |
||||
|
modalContent: TemplateRef<any>; |
||||
|
|
||||
|
form: FormGroup; |
||||
|
|
||||
|
selected: IdentityUserDto; |
||||
|
|
||||
|
selectedUserRoles: IdentityRoleDto[]; |
||||
|
|
||||
|
roles: IdentityRoleDto[]; |
||||
|
|
||||
|
visiblePermissions = false; |
||||
|
|
||||
|
providerKey: string; |
||||
|
|
||||
|
isModalVisible: boolean; |
||||
|
|
||||
|
modalBusy = false; |
||||
|
|
||||
|
permissionManagementKey = ePermissionManagementComponents.PermissionManagement; |
||||
|
|
||||
|
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; |
||||
|
|
||||
|
onVisiblePermissionChange = event => { |
||||
|
this.visiblePermissions = event; |
||||
|
}; |
||||
|
|
||||
|
get roleGroups(): FormGroup[] { |
||||
|
return snq(() => (this.form.get('roleNames') as FormArray).controls as FormGroup[], []); |
||||
|
} |
||||
|
|
||||
|
constructor( |
||||
|
public readonly list: ListService<GetIdentityUsersInput>, |
||||
|
protected confirmationService: ConfirmationService, |
||||
|
protected userService: IdentityUserService, |
||||
|
protected fb: FormBuilder, |
||||
|
protected store: Store, |
||||
|
protected injector: Injector, |
||||
|
) {} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.hookToQuery(); |
||||
|
} |
||||
|
|
||||
|
buildForm() { |
||||
|
const data = new FormPropData(this.injector, this.selected); |
||||
|
this.form = generateFormFromProps(data); |
||||
|
|
||||
|
this.userService.getAssignableRoles().subscribe(({ items }) => { |
||||
|
this.roles = items; |
||||
|
this.form.addControl( |
||||
|
'roleNames', |
||||
|
this.fb.array( |
||||
|
this.roles.map(role => |
||||
|
this.fb.group({ |
||||
|
[role.name]: [ |
||||
|
this.selected.id |
||||
|
? !!snq(() => this.selectedUserRoles.find(userRole => userRole.id === role.id)) |
||||
|
: role.isDefault, |
||||
|
], |
||||
|
}), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
openModal() { |
||||
|
this.buildForm(); |
||||
|
this.isModalVisible = true; |
||||
|
} |
||||
|
|
||||
|
add() { |
||||
|
this.selected = {} as IdentityUserDto; |
||||
|
this.selectedUserRoles = [] as IdentityRoleDto[]; |
||||
|
this.openModal(); |
||||
|
} |
||||
|
|
||||
|
edit(id: string) { |
||||
|
this.store |
||||
|
.dispatch(new GetUserById(id)) |
||||
|
.pipe( |
||||
|
switchMap(() => this.store.dispatch(new GetUserRoles(id))), |
||||
|
pluck('IdentityState'), |
||||
|
take(1), |
||||
|
) |
||||
|
.subscribe((state: Identity.State) => { |
||||
|
this.selected = state.selectedUser; |
||||
|
this.selectedUserRoles = state.selectedUserRoles || []; |
||||
|
this.openModal(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
save() { |
||||
|
if (!this.form.valid || this.modalBusy) return; |
||||
|
this.modalBusy = true; |
||||
|
|
||||
|
const { roleNames } = this.form.value; |
||||
|
const mappedRoleNames = snq( |
||||
|
() => |
||||
|
roleNames.filter(role => !!role[Object.keys(role)[0]]).map(role => Object.keys(role)[0]), |
||||
|
[], |
||||
|
); |
||||
|
|
||||
|
this.store |
||||
|
.dispatch( |
||||
|
this.selected.id |
||||
|
? new UpdateUser({ |
||||
|
...this.selected, |
||||
|
...this.form.value, |
||||
|
id: this.selected.id, |
||||
|
roleNames: mappedRoleNames, |
||||
|
}) |
||||
|
: new CreateUser({ |
||||
|
...this.form.value, |
||||
|
roleNames: mappedRoleNames, |
||||
|
}), |
||||
|
) |
||||
|
.pipe(finalize(() => (this.modalBusy = false))) |
||||
|
.subscribe(() => { |
||||
|
this.isModalVisible = false; |
||||
|
this.list.get(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
delete(id: string, userName: string) { |
||||
|
this.confirmationService |
||||
|
.warn('AbpIdentity::UserDeletionConfirmationMessage', 'AbpIdentity::AreYouSure', { |
||||
|
messageLocalizationParams: [userName], |
||||
|
}) |
||||
|
.subscribe((status: Confirmation.Status) => { |
||||
|
if (status === Confirmation.Status.confirm) { |
||||
|
this.store.dispatch(new DeleteUser(id)).subscribe(() => this.list.get()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
sort(data) { |
||||
|
const { prop, dir } = data.sorts[0]; |
||||
|
this.list.sortKey = prop; |
||||
|
this.list.sortOrder = dir; |
||||
|
} |
||||
|
|
||||
|
private hookToQuery() { |
||||
|
this.list.hookToQuery(query => this.store.dispatch(new GetUsers(query))).subscribe(); |
||||
|
} |
||||
|
|
||||
|
openPermissionsModal(providerKey: string) { |
||||
|
this.providerKey = providerKey; |
||||
|
setTimeout(() => { |
||||
|
this.visiblePermissions = true; |
||||
|
}, 0); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
import { EntityAction } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { RolesComponent } from '../components/roles/roles.component'; |
||||
|
import { IdentityRoleDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_ROLES_ENTITY_ACTIONS = EntityAction.createMany<IdentityRoleDto>([ |
||||
|
{ |
||||
|
text: 'AbpIdentity::Edit', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(RolesComponent); |
||||
|
component.edit(data.record.id); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Roles.Update', |
||||
|
}, |
||||
|
{ |
||||
|
text: 'AbpIdentity::Permissions', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(RolesComponent); |
||||
|
component.openPermissionsModal(data.record.name); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Roles.ManagePermissions', |
||||
|
}, |
||||
|
{ |
||||
|
text: 'AbpIdentity::Delete', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(RolesComponent); |
||||
|
component.delete(data.record.id, data.record.name); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Roles.Delete', |
||||
|
visible: data => !data.record.isStatic, |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,32 @@ |
|||||
|
import { LocalizationService } from '@abp/ng.core'; |
||||
|
import { EntityProp, ePropType } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { of } from 'rxjs'; |
||||
|
import { IdentityRoleDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_ROLES_ENTITY_PROPS = EntityProp.createMany<IdentityRoleDto>([ |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'name', |
||||
|
displayName: 'AbpIdentity::RoleName', |
||||
|
sortable: true, |
||||
|
valueResolver: data => { |
||||
|
const l10n = data.getInjected(LocalizationService); |
||||
|
const t = l10n.instant.bind(l10n); |
||||
|
const { isDefault, isPublic, name } = data.record; |
||||
|
|
||||
|
return of( |
||||
|
name + |
||||
|
(isDefault |
||||
|
? `<span class="badge badge-pill badge-success ml-1">${t( |
||||
|
'AbpIdentity::DisplayName:IsDefault', |
||||
|
)}</span>` |
||||
|
: '') + |
||||
|
(isPublic |
||||
|
? `<span class="badge badge-pill badge-info ml-1">${t( |
||||
|
'AbpIdentity::DisplayName:IsPublic', |
||||
|
)}</span>` |
||||
|
: ''), |
||||
|
); |
||||
|
}, |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,30 @@ |
|||||
|
import { ePropType, FormProp, PropData } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { Validators } from '@angular/forms'; |
||||
|
import { IdentityRoleDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_ROLES_CREATE_FORM_PROPS = FormProp.createMany<IdentityRoleDto>([ |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'name', |
||||
|
displayName: 'AbpIdentity::RoleName', |
||||
|
id: 'role-name', |
||||
|
disabled: (data: PropData<IdentityRoleDto>) => data.record && data.record.isStatic, |
||||
|
validators: () => [Validators.required], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.Boolean, |
||||
|
name: 'isDefault', |
||||
|
displayName: 'AbpIdentity::DisplayName:IsDefault', |
||||
|
id: 'role-is-default', |
||||
|
defaultValue: false, |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.Boolean, |
||||
|
name: 'isPublic', |
||||
|
displayName: 'AbpIdentity::DisplayName:IsPublic', |
||||
|
id: 'role-is-public', |
||||
|
defaultValue: false, |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
export const DEFAULT_ROLES_EDIT_FORM_PROPS = DEFAULT_ROLES_CREATE_FORM_PROPS; |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { ToolbarAction } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { RolesComponent } from '../components/roles/roles.component'; |
||||
|
import { IdentityRoleDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_ROLES_TOOLBAR_ACTIONS = ToolbarAction.createMany<IdentityRoleDto[]>([ |
||||
|
{ |
||||
|
text: 'AbpIdentity::NewRole', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(RolesComponent); |
||||
|
component.add(); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Roles.Create', |
||||
|
icon: 'fa fa-plus', |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,30 @@ |
|||||
|
import { EntityAction } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { UsersComponent } from '../components/users/users.component'; |
||||
|
import { IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_USERS_ENTITY_ACTIONS = EntityAction.createMany<IdentityUserDto>([ |
||||
|
{ |
||||
|
text: 'AbpIdentity::Edit', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(UsersComponent); |
||||
|
component.edit(data.record.id); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Users.Update', |
||||
|
}, |
||||
|
{ |
||||
|
text: 'AbpIdentity::Permissions', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(UsersComponent); |
||||
|
component.openPermissionsModal(data.record.id); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Users.ManagePermissions', |
||||
|
}, |
||||
|
{ |
||||
|
text: 'AbpIdentity::Delete', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(UsersComponent); |
||||
|
component.delete(data.record.id, data.record.name || data.record.userName); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Users.Delete', |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,26 @@ |
|||||
|
import { EntityProp, ePropType } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_USERS_ENTITY_PROPS = EntityProp.createMany<IdentityUserDto>([ |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'userName', |
||||
|
displayName: 'AbpIdentity::UserName', |
||||
|
sortable: true, |
||||
|
columnWidth: 250, |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'email', |
||||
|
displayName: 'AbpIdentity::EmailAddress', |
||||
|
sortable: true, |
||||
|
columnWidth: 250, |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'phoneNumber', |
||||
|
displayName: 'AbpIdentity::PhoneNumber', |
||||
|
sortable: true, |
||||
|
columnWidth: 250, |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,61 @@ |
|||||
|
import { getPasswordValidators } from '@abp/ng.theme.shared'; |
||||
|
import { ePropType, FormProp } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { Validators } from '@angular/forms'; |
||||
|
import { IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_USERS_CREATE_FORM_PROPS = FormProp.createMany<IdentityUserDto>([ |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'userName', |
||||
|
displayName: 'AbpIdentity::UserName', |
||||
|
id: 'user-name', |
||||
|
validators: () => [Validators.required, Validators.maxLength(256)], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.Password, |
||||
|
name: 'password', |
||||
|
displayName: 'AbpIdentity::Password', |
||||
|
id: 'password', |
||||
|
autocomplete: 'new-password', |
||||
|
validators: data => [Validators.required, ...getPasswordValidators({ get: data.getInjected })], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'name', |
||||
|
displayName: 'AbpIdentity::DisplayName:Name', |
||||
|
id: 'name', |
||||
|
validators: () => [Validators.maxLength(64)], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'surname', |
||||
|
displayName: 'AbpIdentity::DisplayName:Surname', |
||||
|
id: 'surname', |
||||
|
validators: () => [Validators.maxLength(64)], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.Email, |
||||
|
name: 'email', |
||||
|
displayName: 'AbpIdentity::EmailAddress', |
||||
|
id: 'email', |
||||
|
validators: () => [Validators.required, Validators.maxLength(256), Validators.email], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.String, |
||||
|
name: 'phoneNumber', |
||||
|
displayName: 'AbpIdentity::PhoneNumber', |
||||
|
id: 'phone-number', |
||||
|
validators: () => [Validators.maxLength(16)], |
||||
|
}, |
||||
|
{ |
||||
|
type: ePropType.Boolean, |
||||
|
name: 'lockoutEnabled', |
||||
|
displayName: 'AbpIdentity::DisplayName:LockoutEnabled', |
||||
|
id: 'lockout-checkbox', |
||||
|
defaultValue: true, |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
export const DEFAULT_USERS_EDIT_FORM_PROPS = DEFAULT_USERS_CREATE_FORM_PROPS.filter( |
||||
|
prop => prop.name !== 'password', |
||||
|
); |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { ToolbarAction } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { UsersComponent } from '../components/users/users.component'; |
||||
|
import { IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_USERS_TOOLBAR_ACTIONS = ToolbarAction.createMany<IdentityUserDto[]>([ |
||||
|
{ |
||||
|
text: 'AbpIdentity::NewUser', |
||||
|
action: data => { |
||||
|
const component = data.getInjected(UsersComponent); |
||||
|
component.add(); |
||||
|
}, |
||||
|
permission: 'AbpIdentity.Users.Create', |
||||
|
icon: 'fa fa-plus', |
||||
|
}, |
||||
|
]); |
||||
@ -0,0 +1,4 @@ |
|||||
|
export const enum eIdentityComponents { |
||||
|
Roles = 'Identity.RolesComponent', |
||||
|
Users = 'Identity.UsersComponent', |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './components'; |
||||
@ -0,0 +1,91 @@ |
|||||
|
import { ConfigStateService } from '@abp/ng.core'; |
||||
|
import { |
||||
|
ExtensionsService, |
||||
|
getObjectExtensionEntitiesFromStore, |
||||
|
mapEntitiesToContributors, |
||||
|
mergeWithDefaultActions, |
||||
|
mergeWithDefaultProps, |
||||
|
} from '@abp/ng.theme.shared/extensions'; |
||||
|
import { Injectable, Injector } from '@angular/core'; |
||||
|
import { CanActivate } from '@angular/router'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { map, mapTo, tap } from 'rxjs/operators'; |
||||
|
import { eIdentityComponents } from '../enums/components'; |
||||
|
import { |
||||
|
IdentityCreateFormPropContributors, |
||||
|
IdentityEditFormPropContributors, |
||||
|
IdentityEntityActionContributors, |
||||
|
IdentityEntityPropContributors, |
||||
|
IdentityToolbarActionContributors, |
||||
|
} from '../models/config-options'; |
||||
|
import { |
||||
|
DEFAULT_IDENTITY_CREATE_FORM_PROPS, |
||||
|
DEFAULT_IDENTITY_EDIT_FORM_PROPS, |
||||
|
DEFAULT_IDENTITY_ENTITY_ACTIONS, |
||||
|
DEFAULT_IDENTITY_ENTITY_PROPS, |
||||
|
DEFAULT_IDENTITY_TOOLBAR_ACTIONS, |
||||
|
IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_ENTITY_ACTION_CONTRIBUTORS, |
||||
|
IDENTITY_ENTITY_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS, |
||||
|
} from '../tokens/extensions.token'; |
||||
|
|
||||
|
@Injectable() |
||||
|
export class IdentityExtensionsGuard implements CanActivate { |
||||
|
constructor(private injector: Injector) {} |
||||
|
|
||||
|
canActivate(): Observable<boolean> { |
||||
|
const extensions: ExtensionsService = this.injector.get(ExtensionsService); |
||||
|
const actionContributors: IdentityEntityActionContributors = |
||||
|
this.injector.get(IDENTITY_ENTITY_ACTION_CONTRIBUTORS, null) || {}; |
||||
|
const toolbarContributors: IdentityToolbarActionContributors = |
||||
|
this.injector.get(IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS, null) || {}; |
||||
|
const propContributors: IdentityEntityPropContributors = |
||||
|
this.injector.get(IDENTITY_ENTITY_PROP_CONTRIBUTORS, null) || {}; |
||||
|
const createFormContributors: IdentityCreateFormPropContributors = |
||||
|
this.injector.get(IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS, null) || {}; |
||||
|
const editFormContributors: IdentityEditFormPropContributors = |
||||
|
this.injector.get(IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS, null) || {}; |
||||
|
|
||||
|
const configState = this.injector.get(ConfigStateService); |
||||
|
return getObjectExtensionEntitiesFromStore(configState, 'Identity').pipe( |
||||
|
map(entities => ({ |
||||
|
[eIdentityComponents.Roles]: entities.Role, |
||||
|
[eIdentityComponents.Users]: entities.User, |
||||
|
})), |
||||
|
mapEntitiesToContributors(configState, 'AbpIdentity'), |
||||
|
tap(objectExtensionContributors => { |
||||
|
mergeWithDefaultActions( |
||||
|
extensions.entityActions, |
||||
|
DEFAULT_IDENTITY_ENTITY_ACTIONS, |
||||
|
actionContributors, |
||||
|
); |
||||
|
mergeWithDefaultActions( |
||||
|
extensions.toolbarActions, |
||||
|
DEFAULT_IDENTITY_TOOLBAR_ACTIONS, |
||||
|
toolbarContributors, |
||||
|
); |
||||
|
mergeWithDefaultProps( |
||||
|
extensions.entityProps, |
||||
|
DEFAULT_IDENTITY_ENTITY_PROPS, |
||||
|
objectExtensionContributors.prop, |
||||
|
propContributors, |
||||
|
); |
||||
|
mergeWithDefaultProps( |
||||
|
extensions.createFormProps, |
||||
|
DEFAULT_IDENTITY_CREATE_FORM_PROPS, |
||||
|
objectExtensionContributors.createForm, |
||||
|
createFormContributors, |
||||
|
); |
||||
|
mergeWithDefaultProps( |
||||
|
extensions.editFormProps, |
||||
|
DEFAULT_IDENTITY_EDIT_FORM_PROPS, |
||||
|
objectExtensionContributors.editForm, |
||||
|
editFormContributors, |
||||
|
); |
||||
|
}), |
||||
|
mapTo(true), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './extensions.guard'; |
||||
@ -0,0 +1,52 @@ |
|||||
|
import { |
||||
|
AuthGuard, |
||||
|
DynamicLayoutComponent, |
||||
|
PermissionGuard, |
||||
|
ReplaceableComponents, |
||||
|
ReplaceableRouteContainerComponent, |
||||
|
} from '@abp/ng.core'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||
|
import { RolesComponent } from './components/roles/roles.component'; |
||||
|
import { UsersComponent } from './components/users/users.component'; |
||||
|
import { eIdentityComponents } from './enums/components'; |
||||
|
import { IdentityExtensionsGuard } from './guards/extensions.guard'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ path: '', redirectTo: 'roles', pathMatch: 'full' }, |
||||
|
{ |
||||
|
path: '', |
||||
|
component: DynamicLayoutComponent, |
||||
|
canActivate: [AuthGuard, PermissionGuard, IdentityExtensionsGuard], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: 'roles', |
||||
|
component: ReplaceableRouteContainerComponent, |
||||
|
data: { |
||||
|
requiredPolicy: 'AbpIdentity.Roles', |
||||
|
replaceableComponent: { |
||||
|
key: eIdentityComponents.Roles, |
||||
|
defaultComponent: RolesComponent, |
||||
|
} as ReplaceableComponents.RouteData<RolesComponent>, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
path: 'users', |
||||
|
component: ReplaceableRouteContainerComponent, |
||||
|
data: { |
||||
|
requiredPolicy: 'AbpIdentity.Users', |
||||
|
replaceableComponent: { |
||||
|
key: eIdentityComponents.Users, |
||||
|
defaultComponent: UsersComponent, |
||||
|
} as ReplaceableComponents.RouteData<UsersComponent>, |
||||
|
}, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
}) |
||||
|
export class IdentityRoutingModule {} |
||||
@ -0,0 +1,71 @@ |
|||||
|
import { CoreModule, LazyModuleFactory } from '@abp/ng.core'; |
||||
|
import { PermissionManagementModule } from '@abp/ng.permission-management'; |
||||
|
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
||||
|
import { UiExtensionsModule } from '@abp/ng.theme.shared/extensions'; |
||||
|
import { ModuleWithProviders, NgModule, NgModuleFactory } from '@angular/core'; |
||||
|
import { NgbDropdownModule, NgbNavModule } from '@ng-bootstrap/ng-bootstrap'; |
||||
|
import { NgxValidateCoreModule } from '@ngx-validate/core'; |
||||
|
import { NgxsModule } from '@ngxs/store'; |
||||
|
import { RolesComponent } from './components/roles/roles.component'; |
||||
|
import { UsersComponent } from './components/users/users.component'; |
||||
|
import { IdentityExtensionsGuard } from './guards/extensions.guard'; |
||||
|
import { IdentityRoutingModule } from './identity-routing.module'; |
||||
|
import { IdentityConfigOptions } from './models/config-options'; |
||||
|
import { IdentityState } from './states/identity.state'; |
||||
|
import { |
||||
|
IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_ENTITY_ACTION_CONTRIBUTORS, |
||||
|
IDENTITY_ENTITY_PROP_CONTRIBUTORS, |
||||
|
IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS, |
||||
|
} from './tokens/extensions.token'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [RolesComponent, UsersComponent], |
||||
|
exports: [RolesComponent, UsersComponent], |
||||
|
imports: [ |
||||
|
NgxsModule.forFeature([IdentityState]), |
||||
|
CoreModule, |
||||
|
IdentityRoutingModule, |
||||
|
NgbNavModule, |
||||
|
ThemeSharedModule, |
||||
|
UiExtensionsModule, |
||||
|
NgbDropdownModule, |
||||
|
PermissionManagementModule, |
||||
|
NgxValidateCoreModule, |
||||
|
], |
||||
|
}) |
||||
|
export class IdentityModule { |
||||
|
static forChild(options: IdentityConfigOptions = {}): ModuleWithProviders<IdentityModule> { |
||||
|
return { |
||||
|
ngModule: IdentityModule, |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: IDENTITY_ENTITY_ACTION_CONTRIBUTORS, |
||||
|
useValue: options.entityActionContributors, |
||||
|
}, |
||||
|
{ |
||||
|
provide: IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS, |
||||
|
useValue: options.toolbarActionContributors, |
||||
|
}, |
||||
|
{ |
||||
|
provide: IDENTITY_ENTITY_PROP_CONTRIBUTORS, |
||||
|
useValue: options.entityPropContributors, |
||||
|
}, |
||||
|
{ |
||||
|
provide: IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS, |
||||
|
useValue: options.createFormPropContributors, |
||||
|
}, |
||||
|
{ |
||||
|
provide: IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS, |
||||
|
useValue: options.editFormPropContributors, |
||||
|
}, |
||||
|
IdentityExtensionsGuard, |
||||
|
], |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
static forLazy(options: IdentityConfigOptions = {}): NgModuleFactory<IdentityModule> { |
||||
|
return new LazyModuleFactory(IdentityModule.forChild(options)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
import { |
||||
|
CreateFormPropContributorCallback, |
||||
|
EditFormPropContributorCallback, |
||||
|
EntityActionContributorCallback, |
||||
|
EntityPropContributorCallback, |
||||
|
ToolbarActionContributorCallback, |
||||
|
} from '@abp/ng.theme.shared/extensions'; |
||||
|
import { eIdentityComponents } from '../enums/components'; |
||||
|
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export type IdentityEntityActionContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EntityActionContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EntityActionContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
|
||||
|
export type IdentityToolbarActionContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: ToolbarActionContributorCallback<IdentityRoleDto[]>[]; |
||||
|
[eIdentityComponents.Users]: ToolbarActionContributorCallback<IdentityUserDto[]>[]; |
||||
|
}>; |
||||
|
|
||||
|
export type IdentityEntityPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EntityPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EntityPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
|
||||
|
export type IdentityCreateFormPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: CreateFormPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: CreateFormPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
|
||||
|
export type IdentityEditFormPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EditFormPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EditFormPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
|
||||
|
export interface IdentityConfigOptions { |
||||
|
entityActionContributors?: IdentityEntityActionContributors; |
||||
|
toolbarActionContributors?: IdentityToolbarActionContributors; |
||||
|
entityPropContributors?: IdentityEntityPropContributors; |
||||
|
createFormPropContributors?: IdentityCreateFormPropContributors; |
||||
|
editFormPropContributors?: IdentityEditFormPropContributors; |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
import { PagedResultDto } from '@abp/ng.core'; |
||||
|
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export namespace Identity { |
||||
|
export interface State { |
||||
|
roles: PagedResultDto<IdentityRoleDto>; |
||||
|
users: PagedResultDto<IdentityUserDto>; |
||||
|
selectedRole: IdentityRoleDto; |
||||
|
selectedUser: IdentityUserDto; |
||||
|
selectedUserRoles: IdentityRoleDto[]; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
export * from './config-options'; |
||||
|
export * from './identity'; |
||||
File diff suppressed because it is too large
@ -0,0 +1,58 @@ |
|||||
|
import type { ListResultDto, PagedAndSortedResultRequestDto, PagedResultDto } from '@abp/ng.core'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import type { IdentityRoleCreateDto, IdentityRoleDto, IdentityRoleUpdateDto } from './models'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class IdentityRoleService { |
||||
|
apiName = 'AbpIdentity'; |
||||
|
|
||||
|
create = (input: IdentityRoleCreateDto) => |
||||
|
this.restService.request<any, IdentityRoleDto>({ |
||||
|
method: 'POST', |
||||
|
url: '/api/identity/roles', |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
delete = (id: string) => |
||||
|
this.restService.request<any, void>({ |
||||
|
method: 'DELETE', |
||||
|
url: `/api/identity/roles/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
get = (id: string) => |
||||
|
this.restService.request<any, IdentityRoleDto>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/roles/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getAllList = () => |
||||
|
this.restService.request<any, ListResultDto<IdentityRoleDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/roles/all', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getList = (input: PagedAndSortedResultRequestDto) => |
||||
|
this.restService.request<any, PagedResultDto<IdentityRoleDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/roles', |
||||
|
params: { sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
update = (id: string, input: IdentityRoleUpdateDto) => |
||||
|
this.restService.request<any, IdentityRoleDto>({ |
||||
|
method: 'PUT', |
||||
|
url: `/api/identity/roles/${id}`, |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
import type { UserLookupCountInputDto, UserLookupSearchInputDto } from './models'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import type { ListResultDto } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import type { UserData } from '../users/models'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class IdentityUserLookupService { |
||||
|
apiName = 'AbpIdentity'; |
||||
|
|
||||
|
findById = (id: string) => |
||||
|
this.restService.request<any, UserData>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/users/lookup/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
findByUserName = (userName: string) => |
||||
|
this.restService.request<any, UserData>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/users/lookup/by-username/${userName}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getCount = (input: UserLookupCountInputDto) => |
||||
|
this.restService.request<any, number>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/users/lookup/count', |
||||
|
params: { filter: input.filter }, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
search = (input: UserLookupSearchInputDto) => |
||||
|
this.restService.request<any, ListResultDto<UserData>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/users/lookup/search', |
||||
|
params: { filter: input.filter, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1,93 @@ |
|||||
|
import type { |
||||
|
GetIdentityUsersInput, |
||||
|
IdentityRoleDto, |
||||
|
IdentityUserCreateDto, |
||||
|
IdentityUserDto, |
||||
|
IdentityUserUpdateDto, |
||||
|
IdentityUserUpdateRolesDto } from './models'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import type { ListResultDto, PagedResultDto } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class IdentityUserService { |
||||
|
apiName = 'AbpIdentity'; |
||||
|
|
||||
|
create = (input: IdentityUserCreateDto) => |
||||
|
this.restService.request<any, IdentityUserDto>({ |
||||
|
method: 'POST', |
||||
|
url: '/api/identity/users', |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
delete = (id: string) => |
||||
|
this.restService.request<any, void>({ |
||||
|
method: 'DELETE', |
||||
|
url: `/api/identity/users/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
findByEmail = (email: string) => |
||||
|
this.restService.request<any, IdentityUserDto>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/users/by-email/${email}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
findByUsername = (username: string) => |
||||
|
this.restService.request<any, IdentityUserDto>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/users/by-username/{userName}', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
get = (id: string) => |
||||
|
this.restService.request<any, IdentityUserDto>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/users/${id}`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getAssignableRoles = () => |
||||
|
this.restService.request<any, ListResultDto<IdentityRoleDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/users/assignable-roles', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getList = (input: GetIdentityUsersInput) => |
||||
|
this.restService.request<any, PagedResultDto<IdentityUserDto>>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/users', |
||||
|
params: { filter: input.filter, sorting: input.sorting, skipCount: input.skipCount, maxResultCount: input.maxResultCount }, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
getRoles = (id: string) => |
||||
|
this.restService.request<any, ListResultDto<IdentityRoleDto>>({ |
||||
|
method: 'GET', |
||||
|
url: `/api/identity/users/${id}/roles`, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
update = (id: string, input: IdentityUserUpdateDto) => |
||||
|
this.restService.request<any, IdentityUserDto>({ |
||||
|
method: 'PUT', |
||||
|
url: `/api/identity/users/${id}`, |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
updateRoles = (id: string, input: IdentityUserUpdateRolesDto) => |
||||
|
this.restService.request<any, void>({ |
||||
|
method: 'PUT', |
||||
|
url: `/api/identity/users/${id}/roles`, |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
export * from './identity-role.service'; |
||||
|
export * from './identity-user-lookup.service'; |
||||
|
export * from './identity-user.service'; |
||||
|
export * from './models'; |
||||
|
export * from './profile.service'; |
||||
@ -0,0 +1,95 @@ |
|||||
|
import type { ExtensibleEntityDto, ExtensibleFullAuditedEntityDto, ExtensibleObject, PagedAndSortedResultRequestDto } from '@abp/ng.core'; |
||||
|
|
||||
|
export interface ChangePasswordInput { |
||||
|
currentPassword: string; |
||||
|
newPassword: string; |
||||
|
} |
||||
|
|
||||
|
export interface GetIdentityUsersInput extends PagedAndSortedResultRequestDto { |
||||
|
filter: string; |
||||
|
} |
||||
|
|
||||
|
// tslint:disable-next-line: no-empty-interface
|
||||
|
export interface IdentityRoleCreateDto extends IdentityRoleCreateOrUpdateDtoBase { |
||||
|
} |
||||
|
|
||||
|
export interface IdentityRoleCreateOrUpdateDtoBase extends ExtensibleObject { |
||||
|
name: string; |
||||
|
isDefault: boolean; |
||||
|
isPublic: boolean; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityRoleDto extends ExtensibleEntityDto<string> { |
||||
|
name: string; |
||||
|
isDefault: boolean; |
||||
|
isStatic: boolean; |
||||
|
isPublic: boolean; |
||||
|
concurrencyStamp: string; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityRoleUpdateDto extends IdentityRoleCreateOrUpdateDtoBase { |
||||
|
concurrencyStamp: string; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityUserCreateDto extends IdentityUserCreateOrUpdateDtoBase { |
||||
|
password: string; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityUserCreateOrUpdateDtoBase extends ExtensibleObject { |
||||
|
userName: string; |
||||
|
name: string; |
||||
|
surname: string; |
||||
|
email: string; |
||||
|
phoneNumber: string; |
||||
|
lockoutEnabled: boolean; |
||||
|
roleNames: string[]; |
||||
|
} |
||||
|
|
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityUserUpdateDto extends IdentityUserCreateOrUpdateDtoBase { |
||||
|
password: string; |
||||
|
concurrencyStamp: string; |
||||
|
} |
||||
|
|
||||
|
export interface IdentityUserUpdateRolesDto { |
||||
|
roleNames: string[]; |
||||
|
} |
||||
|
|
||||
|
export interface ProfileDto extends ExtensibleObject { |
||||
|
userName: string; |
||||
|
email: string; |
||||
|
name: string; |
||||
|
surname: string; |
||||
|
phoneNumber: string; |
||||
|
isExternal: boolean; |
||||
|
hasPassword: boolean; |
||||
|
} |
||||
|
|
||||
|
export interface UpdateProfileDto extends ExtensibleObject { |
||||
|
userName: string; |
||||
|
email: string; |
||||
|
name: string; |
||||
|
surname: string; |
||||
|
phoneNumber: string; |
||||
|
} |
||||
|
|
||||
|
export interface UserLookupCountInputDto { |
||||
|
filter: string; |
||||
|
} |
||||
|
|
||||
|
export interface UserLookupSearchInputDto extends PagedAndSortedResultRequestDto { |
||||
|
filter: string; |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
import type { ChangePasswordInput, ProfileDto, UpdateProfileDto } from './models'; |
||||
|
import { RestService } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class ProfileService { |
||||
|
apiName = 'AbpIdentity'; |
||||
|
|
||||
|
changePassword = (input: ChangePasswordInput) => |
||||
|
this.restService.request<any, void>({ |
||||
|
method: 'POST', |
||||
|
url: '/api/identity/my-profile/change-password', |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
get = () => |
||||
|
this.restService.request<any, ProfileDto>({ |
||||
|
method: 'GET', |
||||
|
url: '/api/identity/my-profile', |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
update = (input: UpdateProfileDto) => |
||||
|
this.restService.request<any, ProfileDto>({ |
||||
|
method: 'PUT', |
||||
|
url: '/api/identity/my-profile', |
||||
|
body: input, |
||||
|
}, |
||||
|
{ apiName: this.apiName }); |
||||
|
|
||||
|
constructor(private restService: RestService) {} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './models'; |
||||
@ -0,0 +1,12 @@ |
|||||
|
|
||||
|
export interface UserData { |
||||
|
id: string; |
||||
|
tenantId?: string; |
||||
|
userName: string; |
||||
|
name: string; |
||||
|
surname: string; |
||||
|
email: string; |
||||
|
emailConfirmed: boolean; |
||||
|
phoneNumber: string; |
||||
|
phoneNumberConfirmed: boolean; |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
import { ABP } from '@abp/ng.core'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Store } from '@ngxs/store'; |
||||
|
import { |
||||
|
CreateRole, |
||||
|
CreateUser, |
||||
|
DeleteRole, |
||||
|
DeleteUser, |
||||
|
GetRoleById, |
||||
|
GetRoles, |
||||
|
GetUserById, |
||||
|
GetUsers, |
||||
|
UpdateRole, |
||||
|
UpdateUser, |
||||
|
GetUserRoles, |
||||
|
} from '../actions/identity.actions'; |
||||
|
import { Identity } from '../models/identity'; |
||||
|
import { IdentityState } from '../states/identity.state'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root', |
||||
|
}) |
||||
|
export class IdentityStateService { |
||||
|
constructor(private store: Store) {} |
||||
|
|
||||
|
getRoles() { |
||||
|
return this.store.selectSnapshot(IdentityState.getRoles); |
||||
|
} |
||||
|
getRolesTotalCount() { |
||||
|
return this.store.selectSnapshot(IdentityState.getRolesTotalCount); |
||||
|
} |
||||
|
getUsers() { |
||||
|
return this.store.selectSnapshot(IdentityState.getUsers); |
||||
|
} |
||||
|
getUsersTotalCount() { |
||||
|
return this.store.selectSnapshot(IdentityState.getUsersTotalCount); |
||||
|
} |
||||
|
|
||||
|
dispatchGetRoles(...args: ConstructorParameters<typeof GetRoles>) { |
||||
|
return this.store.dispatch(new GetRoles(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchGetRoleById(...args: ConstructorParameters<typeof GetRoleById>) { |
||||
|
return this.store.dispatch(new GetRoleById(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchDeleteRole(...args: ConstructorParameters<typeof DeleteRole>) { |
||||
|
return this.store.dispatch(new DeleteRole(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchCreateRole(...args: ConstructorParameters<typeof CreateRole>) { |
||||
|
return this.store.dispatch(new CreateRole(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchUpdateRole(...args: ConstructorParameters<typeof UpdateRole>) { |
||||
|
return this.store.dispatch(new UpdateRole(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchGetUsers(...args: ConstructorParameters<typeof GetUsers>) { |
||||
|
return this.store.dispatch(new GetUsers(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchGetUserById(...args: ConstructorParameters<typeof GetUserById>) { |
||||
|
return this.store.dispatch(new GetUserById(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchDeleteUser(...args: ConstructorParameters<typeof DeleteUser>) { |
||||
|
return this.store.dispatch(new DeleteUser(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchCreateUser(...args: ConstructorParameters<typeof CreateUser>) { |
||||
|
return this.store.dispatch(new CreateUser(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchUpdateUser(...args: ConstructorParameters<typeof UpdateUser>) { |
||||
|
return this.store.dispatch(new UpdateUser(...args)); |
||||
|
} |
||||
|
|
||||
|
dispatchGetUserRoles(...args: ConstructorParameters<typeof GetUserRoles>) { |
||||
|
return this.store.dispatch(new GetUserRoles(...args)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './identity-state.service'; |
||||
@ -0,0 +1,138 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
||||
|
import { pluck, tap } from 'rxjs/operators'; |
||||
|
import { |
||||
|
CreateRole, |
||||
|
CreateUser, |
||||
|
DeleteRole, |
||||
|
DeleteUser, |
||||
|
GetRoleById, |
||||
|
GetRoles, |
||||
|
GetUserById, |
||||
|
GetUserRoles, |
||||
|
GetUsers, |
||||
|
UpdateRole, |
||||
|
UpdateUser, |
||||
|
} from '../actions/identity.actions'; |
||||
|
import { Identity } from '../models/identity'; |
||||
|
import { IdentityRoleService } from '../proxy/identity/identity-role.service'; |
||||
|
import { IdentityUserService } from '../proxy/identity/identity-user.service'; |
||||
|
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
@State<Identity.State>({ |
||||
|
name: 'IdentityState', |
||||
|
defaults: { roles: {}, selectedRole: {}, users: {}, selectedUser: {} } as Identity.State, |
||||
|
}) |
||||
|
@Injectable() |
||||
|
export class IdentityState { |
||||
|
@Selector() |
||||
|
static getRoles({ roles }: Identity.State): IdentityRoleDto[] { |
||||
|
return roles.items || []; |
||||
|
} |
||||
|
|
||||
|
@Selector() |
||||
|
static getRolesTotalCount({ roles }: Identity.State): number { |
||||
|
return roles.totalCount || 0; |
||||
|
} |
||||
|
|
||||
|
@Selector() |
||||
|
static getUsers({ users }: Identity.State): IdentityUserDto[] { |
||||
|
return users.items || []; |
||||
|
} |
||||
|
|
||||
|
@Selector() |
||||
|
static getUsersTotalCount({ users }: Identity.State): number { |
||||
|
return users.totalCount || 0; |
||||
|
} |
||||
|
|
||||
|
constructor( |
||||
|
private identityUserService: IdentityUserService, |
||||
|
private identityRoleService: IdentityRoleService, |
||||
|
) {} |
||||
|
|
||||
|
@Action(GetRoles) |
||||
|
getRoles({ patchState }: StateContext<Identity.State>, { payload }: GetRoles) { |
||||
|
return this.identityRoleService.getList(payload).pipe( |
||||
|
tap(roles => |
||||
|
patchState({ |
||||
|
roles, |
||||
|
}), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@Action(GetRoleById) |
||||
|
getRole({ patchState }: StateContext<Identity.State>, { payload }: GetRoleById) { |
||||
|
return this.identityRoleService.get(payload).pipe( |
||||
|
tap(selectedRole => |
||||
|
patchState({ |
||||
|
selectedRole, |
||||
|
}), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@Action(DeleteRole) |
||||
|
deleteRole(_, { payload }: GetRoleById) { |
||||
|
return this.identityRoleService.delete(payload); |
||||
|
} |
||||
|
|
||||
|
@Action(CreateRole) |
||||
|
addRole(_, { payload }: CreateRole) { |
||||
|
return this.identityRoleService.create(payload); |
||||
|
} |
||||
|
|
||||
|
@Action(UpdateRole) |
||||
|
updateRole({ getState }: StateContext<Identity.State>, { payload }: UpdateRole) { |
||||
|
return this.identityRoleService.update(payload.id, { ...getState().selectedRole, ...payload }); |
||||
|
} |
||||
|
|
||||
|
@Action(GetUsers) |
||||
|
getUsers({ patchState }: StateContext<Identity.State>, { payload }: GetUsers) { |
||||
|
return this.identityUserService.getList(payload).pipe( |
||||
|
tap(users => |
||||
|
patchState({ |
||||
|
users, |
||||
|
}), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@Action(GetUserById) |
||||
|
getUser({ patchState }: StateContext<Identity.State>, { payload }: GetUserById) { |
||||
|
return this.identityUserService.get(payload).pipe( |
||||
|
tap(selectedUser => |
||||
|
patchState({ |
||||
|
selectedUser, |
||||
|
}), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
@Action(DeleteUser) |
||||
|
deleteUser(_, { payload }: GetUserById) { |
||||
|
return this.identityUserService.delete(payload); |
||||
|
} |
||||
|
|
||||
|
@Action(CreateUser) |
||||
|
addUser(_, { payload }: CreateUser) { |
||||
|
return this.identityUserService.create(payload); |
||||
|
} |
||||
|
|
||||
|
@Action(UpdateUser) |
||||
|
updateUser({ getState }: StateContext<Identity.State>, { payload }: UpdateUser) { |
||||
|
return this.identityUserService.update(payload.id, { ...getState().selectedUser, ...payload }); |
||||
|
} |
||||
|
|
||||
|
@Action(GetUserRoles) |
||||
|
getUserRoles({ patchState }: StateContext<Identity.State>, { payload }: GetUserRoles) { |
||||
|
return this.identityUserService.getRoles(payload).pipe( |
||||
|
pluck('items'), |
||||
|
tap(selectedUserRoles => |
||||
|
patchState({ |
||||
|
selectedUserRoles, |
||||
|
}), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './identity.state'; |
||||
@ -0,0 +1,58 @@ |
|||||
|
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
||||
|
import { IdentityStateService } from '../services/identity-state.service'; |
||||
|
import { IdentityState } from '../states/identity.state'; |
||||
|
import { Store } from '@ngxs/store'; |
||||
|
import * as IdentityActions from '../actions/identity.actions'; |
||||
|
|
||||
|
describe('IdentityStateService', () => { |
||||
|
let service: IdentityStateService; |
||||
|
let spectator: SpectatorService<IdentityStateService>; |
||||
|
let store: SpyObject<Store>; |
||||
|
|
||||
|
const createService = createServiceFactory({ service: IdentityStateService, mocks: [Store] }); |
||||
|
beforeEach(() => { |
||||
|
spectator = createService(); |
||||
|
service = spectator.service; |
||||
|
store = spectator.inject(Store); |
||||
|
}); |
||||
|
|
||||
|
test('should have the all IdentityState static methods', () => { |
||||
|
const reg = /(?<=static )(.*)(?=\()/gm; |
||||
|
IdentityState.toString() |
||||
|
.match(reg) |
||||
|
.forEach(fnName => { |
||||
|
expect(service[fnName]).toBeTruthy(); |
||||
|
|
||||
|
const spy = jest.spyOn(store, 'selectSnapshot'); |
||||
|
spy.mockClear(); |
||||
|
|
||||
|
const isDynamicSelector = IdentityState[fnName].name !== 'memoized'; |
||||
|
|
||||
|
if (isDynamicSelector) { |
||||
|
IdentityState[fnName] = jest.fn((...args) => args); |
||||
|
service[fnName]('test', 0, {}); |
||||
|
expect(IdentityState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
||||
|
} else { |
||||
|
service[fnName](); |
||||
|
expect(spy).toHaveBeenCalledWith(IdentityState[fnName]); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
test('should have a dispatch method for every IdentityState action', () => { |
||||
|
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
||||
|
IdentityStateService.toString() |
||||
|
.match(reg) |
||||
|
.forEach(fnName => { |
||||
|
expect(IdentityActions[fnName]).toBeTruthy(); |
||||
|
|
||||
|
const spy = jest.spyOn(store, 'dispatch'); |
||||
|
spy.mockClear(); |
||||
|
|
||||
|
const params = Array.from(new Array(IdentityActions[fnName].length)); |
||||
|
|
||||
|
service[`dispatch${fnName}`](...params); |
||||
|
expect(spy).toHaveBeenCalledWith(new IdentityActions[fnName](...params)); |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,91 @@ |
|||||
|
import { |
||||
|
CreateFormPropContributorCallback, |
||||
|
EditFormPropContributorCallback, |
||||
|
EntityActionContributorCallback, |
||||
|
EntityPropContributorCallback, |
||||
|
ToolbarActionContributorCallback, |
||||
|
} from '@abp/ng.theme.shared/extensions'; |
||||
|
import { InjectionToken } from '@angular/core'; |
||||
|
import { DEFAULT_ROLES_ENTITY_ACTIONS } from '../defaults/default-roles-entity-actions'; |
||||
|
import { DEFAULT_ROLES_ENTITY_PROPS } from '../defaults/default-roles-entity-props'; |
||||
|
import { |
||||
|
DEFAULT_ROLES_CREATE_FORM_PROPS, |
||||
|
DEFAULT_ROLES_EDIT_FORM_PROPS, |
||||
|
} from '../defaults/default-roles-form-props'; |
||||
|
import { DEFAULT_ROLES_TOOLBAR_ACTIONS } from '../defaults/default-roles-toolbar-actions'; |
||||
|
import { DEFAULT_USERS_ENTITY_ACTIONS } from '../defaults/default-users-entity-actions'; |
||||
|
import { DEFAULT_USERS_ENTITY_PROPS } from '../defaults/default-users-entity-props'; |
||||
|
import { |
||||
|
DEFAULT_USERS_CREATE_FORM_PROPS, |
||||
|
DEFAULT_USERS_EDIT_FORM_PROPS, |
||||
|
} from '../defaults/default-users-form-props'; |
||||
|
import { DEFAULT_USERS_TOOLBAR_ACTIONS } from '../defaults/default-users-toolbar-actions'; |
||||
|
import { eIdentityComponents } from '../enums/components'; |
||||
|
import { IdentityRoleDto, IdentityUserDto } from '../proxy/identity/models'; |
||||
|
|
||||
|
export const DEFAULT_IDENTITY_ENTITY_ACTIONS = { |
||||
|
[eIdentityComponents.Roles]: DEFAULT_ROLES_ENTITY_ACTIONS, |
||||
|
[eIdentityComponents.Users]: DEFAULT_USERS_ENTITY_ACTIONS, |
||||
|
}; |
||||
|
|
||||
|
export const DEFAULT_IDENTITY_TOOLBAR_ACTIONS = { |
||||
|
[eIdentityComponents.Roles]: DEFAULT_ROLES_TOOLBAR_ACTIONS, |
||||
|
[eIdentityComponents.Users]: DEFAULT_USERS_TOOLBAR_ACTIONS, |
||||
|
}; |
||||
|
|
||||
|
export const DEFAULT_IDENTITY_ENTITY_PROPS = { |
||||
|
[eIdentityComponents.Roles]: DEFAULT_ROLES_ENTITY_PROPS, |
||||
|
[eIdentityComponents.Users]: DEFAULT_USERS_ENTITY_PROPS, |
||||
|
}; |
||||
|
|
||||
|
export const DEFAULT_IDENTITY_CREATE_FORM_PROPS = { |
||||
|
[eIdentityComponents.Roles]: DEFAULT_ROLES_CREATE_FORM_PROPS, |
||||
|
[eIdentityComponents.Users]: DEFAULT_USERS_CREATE_FORM_PROPS, |
||||
|
}; |
||||
|
|
||||
|
export const DEFAULT_IDENTITY_EDIT_FORM_PROPS = { |
||||
|
[eIdentityComponents.Roles]: DEFAULT_ROLES_EDIT_FORM_PROPS, |
||||
|
[eIdentityComponents.Users]: DEFAULT_USERS_EDIT_FORM_PROPS, |
||||
|
}; |
||||
|
|
||||
|
export const IDENTITY_ENTITY_ACTION_CONTRIBUTORS = new InjectionToken<EntityActionContributors>( |
||||
|
'IDENTITY_ENTITY_ACTION_CONTRIBUTORS', |
||||
|
); |
||||
|
|
||||
|
export const IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS = new InjectionToken<ToolbarActionContributors>( |
||||
|
'IDENTITY_TOOLBAR_ACTION_CONTRIBUTORS', |
||||
|
); |
||||
|
|
||||
|
export const IDENTITY_ENTITY_PROP_CONTRIBUTORS = new InjectionToken<EntityPropContributors>( |
||||
|
'IDENTITY_ENTITY_PROP_CONTRIBUTORS', |
||||
|
); |
||||
|
|
||||
|
export const IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS = new InjectionToken<CreateFormPropContributors>( |
||||
|
'IDENTITY_CREATE_FORM_PROP_CONTRIBUTORS', |
||||
|
); |
||||
|
|
||||
|
export const IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS = new InjectionToken<EditFormPropContributors>( |
||||
|
'IDENTITY_EDIT_FORM_PROP_CONTRIBUTORS', |
||||
|
); |
||||
|
|
||||
|
// Fix for TS4023 -> https://github.com/microsoft/TypeScript/issues/9944#issuecomment-254693497
|
||||
|
type EntityActionContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EntityActionContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EntityActionContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
type ToolbarActionContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: ToolbarActionContributorCallback<IdentityRoleDto[]>[]; |
||||
|
[eIdentityComponents.Users]: ToolbarActionContributorCallback<IdentityUserDto[]>[]; |
||||
|
}>; |
||||
|
type EntityPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EntityPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EntityPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
type CreateFormPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: CreateFormPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: CreateFormPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
|
type EditFormPropContributors = Partial<{ |
||||
|
[eIdentityComponents.Roles]: EditFormPropContributorCallback<IdentityRoleDto>[]; |
||||
|
[eIdentityComponents.Users]: EditFormPropContributorCallback<IdentityUserDto>[]; |
||||
|
}>; |
||||
@ -0,0 +1 @@ |
|||||
|
export * from './extensions.token'; |
||||
@ -0,0 +1,11 @@ |
|||||
|
export * from './lib/actions'; |
||||
|
export * from './lib/components'; |
||||
|
export * from './lib/enums'; |
||||
|
export * from './lib/guards'; |
||||
|
export * from './lib/identity.module'; |
||||
|
export * from './lib/models'; |
||||
|
export * from './lib/proxy/identity'; |
||||
|
export * from './lib/proxy/users'; |
||||
|
export * from './lib/services'; |
||||
|
export * from './lib/states'; |
||||
|
export * from './lib/tokens'; |
||||
@ -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