mirror of https://github.com/abpframework/abp.git
committed by
GitHub
107 changed files with 3690 additions and 4412 deletions
@ -1,24 +0,0 @@ |
|||||
import { Config } from '../models/config'; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use ConfigStateService. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export class GetAppConfiguration { |
|
||||
static readonly type = '[Config] Get App Configuration'; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use EnvironmentService instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export class SetEnvironment { |
|
||||
static readonly type = '[Config] Set Environment'; |
|
||||
constructor(public environment: Config.Environment) {} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use EnvironmentService instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export class PatchConfigState { |
|
||||
static readonly type = '[Config] Set State'; |
|
||||
constructor(public state: Config.State) {} |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
export { GetAppConfiguration, SetEnvironment } from './config.actions'; |
|
||||
export * from './loader.actions'; |
|
||||
export * from './profile.actions'; |
|
||||
export * from './rest.actions'; |
|
||||
@ -1,11 +0,0 @@ |
|||||
import { HttpRequest } from '@angular/common/http'; |
|
||||
|
|
||||
export class StartLoader { |
|
||||
static readonly type = '[Loader] Start'; |
|
||||
constructor(public payload: HttpRequest<any>) {} |
|
||||
} |
|
||||
|
|
||||
export class StopLoader { |
|
||||
static readonly type = '[Loader] Stop'; |
|
||||
constructor(public payload: HttpRequest<any>) {} |
|
||||
} |
|
||||
@ -1,15 +0,0 @@ |
|||||
import { Profile } from '../models'; |
|
||||
|
|
||||
export class GetProfile { |
|
||||
static readonly type = '[Profile] Get'; |
|
||||
} |
|
||||
|
|
||||
export class UpdateProfile { |
|
||||
static readonly type = '[Profile] Update'; |
|
||||
constructor(public payload: Profile.Response) {} |
|
||||
} |
|
||||
|
|
||||
export class ChangePassword { |
|
||||
static readonly type = '[Profile] Change Password'; |
|
||||
constructor(public payload: Profile.ChangePasswordRequest) {} |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
import { HttpErrorResponse } from '@angular/common/http'; |
|
||||
|
|
||||
export class RestOccurError { |
|
||||
static readonly type = '[Rest] Error'; |
|
||||
constructor(public payload: HttpErrorResponse | any) {} |
|
||||
} |
|
||||
@ -1,65 +0,0 @@ |
|||||
import { ApplicationConfiguration } from './application-configuration'; |
|
||||
import { ABP } from './common'; |
|
||||
import { Environment as IEnvironment } from './environment'; |
|
||||
import { |
|
||||
LocalizationParam as ILocalizationParam, |
|
||||
LocalizationWithDefault as ILocalizationWithDefault, |
|
||||
} from './localization'; |
|
||||
|
|
||||
export namespace Config { |
|
||||
/** |
|
||||
* @deprecated Use ApplicationConfiguration.Response instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export type State = ApplicationConfiguration.Response & ABP.Root & { environment: IEnvironment }; |
|
||||
|
|
||||
export type Environment = IEnvironment; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use ApplicationInfo interface instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export interface Application { |
|
||||
name: string; |
|
||||
baseUrl?: string; |
|
||||
logoUrl?: string; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use ApiConfig interface instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export type ApiConfig = { |
|
||||
[key: string]: string; |
|
||||
url: string; |
|
||||
} & Partial<{ |
|
||||
rootNamespace: string; |
|
||||
}>; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use Apis interface instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export interface Apis { |
|
||||
[key: string]: ApiConfig; |
|
||||
default: ApiConfig; |
|
||||
} |
|
||||
|
|
||||
export type LocalizationWithDefault = ILocalizationWithDefault; |
|
||||
|
|
||||
export type LocalizationParam = ILocalizationParam; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use customMergeFn type instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export type customMergeFn = ( |
|
||||
localEnv: Partial<Config.Environment>, |
|
||||
remoteEnv: any, |
|
||||
) => Config.Environment; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use RemoteEnv interface instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
export interface RemoteEnv { |
|
||||
url: string; |
|
||||
mergeStrategy: 'deepmerge' | 'overwrite' | customMergeFn; |
|
||||
method?: string; |
|
||||
headers?: ABP.Dictionary<string>; |
|
||||
} |
|
||||
} |
|
||||
@ -1,28 +1,26 @@ |
|||||
import { ExtensibleObject } from './dtos'; |
import { ExtensibleObject } from './dtos'; |
||||
|
|
||||
export namespace Profile { |
export interface ChangePasswordInput { |
||||
export interface State { |
currentPassword: string; |
||||
profile: Response; |
newPassword: string; |
||||
} |
} |
||||
|
|
||||
export interface Response extends Partial<ExtensibleObject> { |
export interface ProfileDto extends ExtensibleObject { |
||||
userName: string; |
userName: string; |
||||
email: string; |
email: string; |
||||
name: string; |
name: string; |
||||
surname: string; |
surname: string; |
||||
phoneNumber: string; |
phoneNumber: string; |
||||
/** |
isExternal?: boolean; |
||||
* Following 4 fields are added as optional (for backward compatibility) on 17.08.2020 |
hasPassword?: boolean; |
||||
* Also, this interface extends `ExtensibleObject` as partial for extraProperties field. |
emailConfirmed?: boolean; |
||||
*/ |
phoneNumberConfirmed?: boolean; |
||||
isExternal?: boolean; |
} |
||||
hasPassword?: boolean; |
|
||||
emailConfirmed?: boolean; |
|
||||
phoneNumberConfirmed?: boolean; |
|
||||
} |
|
||||
|
|
||||
export interface ChangePasswordRequest { |
export interface UpdateProfileDto extends ExtensibleObject { |
||||
currentPassword: string; |
userName: string; |
||||
newPassword: string; |
email: string; |
||||
} |
name: string; |
||||
|
surname: string; |
||||
|
phoneNumber: string; |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,26 @@ |
|||||
|
import { HttpErrorResponse } from '@angular/common/http'; |
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { BehaviorSubject, Subject } from 'rxjs'; |
||||
|
|
||||
|
@Injectable({ providedIn: 'root' }) |
||||
|
export class HttpErrorReporterService { |
||||
|
private _reporter$ = new Subject(); |
||||
|
private _errors$ = new BehaviorSubject<HttpErrorResponse[]>([]); |
||||
|
|
||||
|
get reporter$() { |
||||
|
return this._reporter$.asObservable(); |
||||
|
} |
||||
|
|
||||
|
get errors$() { |
||||
|
return this._errors$.asObservable(); |
||||
|
} |
||||
|
|
||||
|
get errors() { |
||||
|
return this._errors$.value; |
||||
|
} |
||||
|
|
||||
|
reportError = (error: HttpErrorResponse) => { |
||||
|
this._reporter$.next(error); |
||||
|
this._errors$.next([...this.errors, error]); |
||||
|
}; |
||||
|
} |
||||
@ -1,28 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import { ProfileState } from '../states'; |
|
||||
import { Profile } from '../models'; |
|
||||
import { GetProfile, UpdateProfile, ChangePassword } from '../actions'; |
|
||||
|
|
||||
@Injectable({ |
|
||||
providedIn: 'root', |
|
||||
}) |
|
||||
export class ProfileStateService { |
|
||||
constructor(private store: Store) {} |
|
||||
|
|
||||
getProfile() { |
|
||||
return this.store.selectSnapshot(ProfileState.getProfile); |
|
||||
} |
|
||||
|
|
||||
dispatchGetProfile() { |
|
||||
return this.store.dispatch(new GetProfile()); |
|
||||
} |
|
||||
|
|
||||
dispatchUpdateProfile(...args: ConstructorParameters<typeof UpdateProfile>) { |
|
||||
return this.store.dispatch(new UpdateProfile(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchChangePassword(...args: ConstructorParameters<typeof ChangePassword>) { |
|
||||
return this.store.dispatch(new ChangePassword(...args)); |
|
||||
} |
|
||||
} |
|
||||
@ -1,264 +0,0 @@ |
|||||
import { HttpErrorResponse } from '@angular/common/http'; |
|
||||
import { Injectable } from '@angular/core'; |
|
||||
import { Action, createSelector, Selector, State, StateContext, Store } from '@ngxs/store'; |
|
||||
import compare from 'just-compare'; |
|
||||
import { throwError } from 'rxjs'; |
|
||||
import { catchError, distinctUntilChanged } from 'rxjs/operators'; |
|
||||
import { GetAppConfiguration, PatchConfigState, SetEnvironment } from '../actions/config.actions'; |
|
||||
import { RestOccurError } from '../actions/rest.actions'; |
|
||||
import { Config } from '../models/config'; |
|
||||
import { ConfigStateService } from '../services/config-state.service'; |
|
||||
import { EnvironmentService } from '../services/environment.service'; |
|
||||
import { interpolate } from '../utils/string-utils'; |
|
||||
|
|
||||
/** |
|
||||
* @deprecated Use ConfigStateService instead. To be deleted in v5.0. |
|
||||
*/ |
|
||||
@State<Config.State>({ |
|
||||
name: 'ConfigState', |
|
||||
defaults: {} as Config.State, |
|
||||
}) |
|
||||
@Injectable() |
|
||||
export class ConfigState { |
|
||||
@Selector() |
|
||||
static getAll(state: Config.State) { |
|
||||
return state; |
|
||||
} |
|
||||
|
|
||||
@Selector() |
|
||||
static getApplicationInfo(state: Config.State): Config.Application { |
|
||||
return state.environment.application || ({} as Config.Application); |
|
||||
} |
|
||||
|
|
||||
@Selector() |
|
||||
static getEnvironment(state: Config.State): Config.Environment { |
|
||||
return state.environment; |
|
||||
} |
|
||||
|
|
||||
static getOne(key: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|
||||
return state[key]; |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getDeep(keys: string[] | string) { |
|
||||
if (typeof keys === 'string') { |
|
||||
keys = keys.split('.'); |
|
||||
} |
|
||||
|
|
||||
if (!Array.isArray(keys)) { |
|
||||
throw new Error('The argument must be a dot string or an string array.'); |
|
||||
} |
|
||||
|
|
||||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|
||||
return (keys as string[]).reduce((acc, val) => { |
|
||||
if (acc) { |
|
||||
return acc[val]; |
|
||||
} |
|
||||
|
|
||||
return undefined; |
|
||||
}, state); |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getApiUrl(key?: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State): string => { |
|
||||
return (state.environment.apis[key || 'default'] || state.environment.apis.default).url; |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getFeature(key: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|
||||
return state.features.values?.[key]; |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getSetting(key: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|
||||
return state.setting.values?.[key]; |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getSettings(keyword?: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State) => { |
|
||||
const settings = state.setting.values || {}; |
|
||||
|
|
||||
if (!keyword) return settings; |
|
||||
|
|
||||
const keysFound = Object.keys(settings).filter(key => key.indexOf(keyword) > -1); |
|
||||
|
|
||||
return keysFound.reduce((acc, key) => { |
|
||||
acc[key] = settings[key]; |
|
||||
return acc; |
|
||||
}, {}); |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* @deprecated use PermissionService's getGrantedPolicyStream or getGrantedPolicy methods. |
|
||||
*/ |
|
||||
static getGrantedPolicy(key: string) { |
|
||||
const selector = createSelector([ConfigState], (state: Config.State): boolean => { |
|
||||
if (!key) return true; |
|
||||
const getPolicy = (k: string) => state.auth.grantedPolicies[k] || false; |
|
||||
|
|
||||
const orRegexp = /\|\|/g; |
|
||||
const andRegexp = /&&/g; |
|
||||
|
|
||||
// TODO: Allow combination of ANDs & ORs
|
|
||||
if (orRegexp.test(key)) { |
|
||||
const keys = key.split('||').filter(Boolean); |
|
||||
|
|
||||
if (keys.length < 2) return false; |
|
||||
|
|
||||
return keys.some(k => getPolicy(k.trim())); |
|
||||
} else if (andRegexp.test(key)) { |
|
||||
const keys = key.split('&&').filter(Boolean); |
|
||||
|
|
||||
if (keys.length < 2) return false; |
|
||||
|
|
||||
return keys.every(k => getPolicy(k.trim())); |
|
||||
} |
|
||||
|
|
||||
return getPolicy(key); |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getLocalizationResource(resourceName: string) { |
|
||||
const selector = createSelector( |
|
||||
[ConfigState], |
|
||||
( |
|
||||
state: Config.State, |
|
||||
): { |
|
||||
[key: string]: string; |
|
||||
} => { |
|
||||
return state.localization.values[resourceName]; |
|
||||
}, |
|
||||
); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
static getLocalization( |
|
||||
key: string | Config.LocalizationWithDefault, |
|
||||
...interpolateParams: string[] |
|
||||
) { |
|
||||
if (!key) key = ''; |
|
||||
let defaultValue: string; |
|
||||
|
|
||||
if (typeof key !== 'string') { |
|
||||
defaultValue = key.defaultValue; |
|
||||
key = key.key; |
|
||||
} |
|
||||
|
|
||||
const keys = key.split('::') as string[]; |
|
||||
const selector = createSelector([ConfigState], (state: Config.State): string => { |
|
||||
const warn = (message: string) => { |
|
||||
if (!state.environment.production) console.warn(message); |
|
||||
}; |
|
||||
|
|
||||
if (keys.length < 2) { |
|
||||
warn('The localization source separator (::) not found.'); |
|
||||
return defaultValue || (key as string); |
|
||||
} |
|
||||
if (!state.localization) return defaultValue || keys[1]; |
|
||||
|
|
||||
const sourceName = |
|
||||
keys[0] || |
|
||||
state.environment.localization?.defaultResourceName || |
|
||||
state.localization.defaultResourceName; |
|
||||
const sourceKey = keys[1]; |
|
||||
|
|
||||
if (sourceName === '_') { |
|
||||
return defaultValue || sourceKey; |
|
||||
} |
|
||||
|
|
||||
if (!sourceName) { |
|
||||
warn( |
|
||||
'Localization source name is not specified and the defaultResourceName was not defined!', |
|
||||
); |
|
||||
|
|
||||
return defaultValue || sourceKey; |
|
||||
} |
|
||||
|
|
||||
const source = state.localization.values[sourceName]; |
|
||||
if (!source) { |
|
||||
warn('Could not find localization source: ' + sourceName); |
|
||||
return defaultValue || sourceKey; |
|
||||
} |
|
||||
|
|
||||
let localization = source[sourceKey]; |
|
||||
if (typeof localization === 'undefined') { |
|
||||
return defaultValue || sourceKey; |
|
||||
} |
|
||||
|
|
||||
interpolateParams = interpolateParams.filter(params => params != null); |
|
||||
if (localization) localization = interpolate(localization, interpolateParams); |
|
||||
|
|
||||
if (typeof localization !== 'string') localization = ''; |
|
||||
|
|
||||
return localization || defaultValue || (key as string); |
|
||||
}); |
|
||||
|
|
||||
return selector; |
|
||||
} |
|
||||
|
|
||||
constructor( |
|
||||
private store: Store, |
|
||||
private environmentService: EnvironmentService, |
|
||||
private configState: ConfigStateService, |
|
||||
) { |
|
||||
this.syncConfigState(); |
|
||||
this.syncEnvironment(); |
|
||||
} |
|
||||
|
|
||||
private syncConfigState() { |
|
||||
this.configState |
|
||||
.createOnUpdateStream(state => state) |
|
||||
.pipe(distinctUntilChanged(compare)) |
|
||||
.subscribe(config => this.store.dispatch(new PatchConfigState(config as any))); |
|
||||
} |
|
||||
|
|
||||
private syncEnvironment() { |
|
||||
this.environmentService |
|
||||
.createOnUpdateStream(state => state) |
|
||||
.pipe(distinctUntilChanged(compare)) |
|
||||
.subscribe(env => this.store.dispatch(new PatchConfigState({ environment: env } as any))); |
|
||||
} |
|
||||
|
|
||||
@Action(GetAppConfiguration) |
|
||||
addData({ patchState, dispatch }: StateContext<Config.State>) { |
|
||||
const apiName = 'default'; |
|
||||
const api = this.store.selectSnapshot(ConfigState.getApiUrl(apiName)); |
|
||||
return this.configState.refreshAppState().pipe( |
|
||||
catchError((err: HttpErrorResponse) => { |
|
||||
dispatch(new RestOccurError(err)); |
|
||||
return throwError(err); |
|
||||
}), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(SetEnvironment) |
|
||||
setEnvironment(_, { environment }: SetEnvironment) { |
|
||||
return this.environmentService.setState(environment); |
|
||||
} |
|
||||
|
|
||||
@Action(PatchConfigState) |
|
||||
setConfig({ patchState, getState }: StateContext<Config.State>, { state }: PatchConfigState) { |
|
||||
patchState({ ...getState(), ...state }); |
|
||||
} |
|
||||
} |
|
||||
@ -1,2 +0,0 @@ |
|||||
export * from './config.state'; |
|
||||
export * from './profile.state'; |
|
||||
@ -1,47 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|
||||
import { tap } from 'rxjs/operators'; |
|
||||
import { ChangePassword, GetProfile, UpdateProfile } from '../actions/profile.actions'; |
|
||||
import { Profile } from '../models/profile'; |
|
||||
import { ProfileService } from '../services/profile.service'; |
|
||||
|
|
||||
@State<Profile.State>({ |
|
||||
name: 'ProfileState', |
|
||||
defaults: {} as Profile.State, |
|
||||
}) |
|
||||
@Injectable() |
|
||||
export class ProfileState { |
|
||||
@Selector() |
|
||||
static getProfile({ profile }: Profile.State): Profile.Response { |
|
||||
return profile; |
|
||||
} |
|
||||
|
|
||||
constructor(private profileService: ProfileService) {} |
|
||||
|
|
||||
@Action(GetProfile) |
|
||||
getProfile({ patchState }: StateContext<Profile.State>) { |
|
||||
return this.profileService.get().pipe( |
|
||||
tap(profile => |
|
||||
patchState({ |
|
||||
profile, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(UpdateProfile) |
|
||||
updateProfile({ patchState }: StateContext<Profile.State>, { payload }: UpdateProfile) { |
|
||||
return this.profileService.update(payload).pipe( |
|
||||
tap(profile => |
|
||||
patchState({ |
|
||||
profile, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(ChangePassword) |
|
||||
changePassword(_, { payload }: ChangePassword) { |
|
||||
return this.profileService.changePassword(payload, true); |
|
||||
} |
|
||||
} |
|
||||
@ -1,57 +0,0 @@ |
|||||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|
||||
import { ProfileStateService } from '../services/profile-state.service'; |
|
||||
import { ProfileState } from '../states/profile.state'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import * as ProfileActions from '../actions'; |
|
||||
|
|
||||
describe('ProfileStateService', () => { |
|
||||
let service: ProfileStateService; |
|
||||
let spectator: SpectatorService<ProfileStateService>; |
|
||||
let store: SpyObject<Store>; |
|
||||
|
|
||||
const createService = createServiceFactory({ service: ProfileStateService, mocks: [Store] }); |
|
||||
beforeEach(() => { |
|
||||
spectator = createService(); |
|
||||
service = spectator.service; |
|
||||
store = spectator.inject(Store); |
|
||||
}); |
|
||||
test('should have the all ProfileState static methods', () => { |
|
||||
const reg = /(?<=static )(.*)(?=\()/gm; |
|
||||
ProfileState.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(service[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const isDynamicSelector = ProfileState[fnName].name !== 'memoized'; |
|
||||
|
|
||||
if (isDynamicSelector) { |
|
||||
ProfileState[fnName] = jest.fn((...args) => args); |
|
||||
service[fnName]('test', 0, {}); |
|
||||
expect(ProfileState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|
||||
} else { |
|
||||
service[fnName](); |
|
||||
expect(spy).toHaveBeenCalledWith(ProfileState[fnName]); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
test('should have a dispatch method for every ProfileState action', () => { |
|
||||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|
||||
ProfileStateService.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(ProfileActions[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'dispatch'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const params = Array.from(new Array(ProfileActions[fnName].length)); |
|
||||
|
|
||||
service[`dispatch${fnName}`](...params); |
|
||||
expect(spy).toHaveBeenCalledWith(new ProfileActions[fnName](...params)); |
|
||||
}); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,74 +0,0 @@ |
|||||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|
||||
import { Session } from '../models/session'; |
|
||||
import { ProfileService } from '../services'; |
|
||||
import { ProfileState } from '../states'; |
|
||||
import { GetAppConfiguration } from '../actions/config.actions'; |
|
||||
import { of } from 'rxjs'; |
|
||||
import { Profile } from '../models/profile'; |
|
||||
|
|
||||
export class DummyClass {} |
|
||||
|
|
||||
export const PROFILE_STATE_DATA = { |
|
||||
profile: { userName: 'admin', email: 'info@abp.io', name: 'Admin' }, |
|
||||
} as Profile.State; |
|
||||
|
|
||||
describe('ProfileState', () => { |
|
||||
let spectator: SpectatorService<DummyClass>; |
|
||||
let state: ProfileState; |
|
||||
let profileService: SpyObject<ProfileService>; |
|
||||
let patchedData; |
|
||||
const patchState = jest.fn(data => (patchedData = data)); |
|
||||
|
|
||||
const createService = createServiceFactory({ |
|
||||
service: DummyClass, |
|
||||
mocks: [ProfileService], |
|
||||
}); |
|
||||
|
|
||||
beforeEach(() => { |
|
||||
spectator = createService(); |
|
||||
profileService = spectator.inject(ProfileService); |
|
||||
state = new ProfileState(profileService); |
|
||||
}); |
|
||||
|
|
||||
describe('#getProfile', () => { |
|
||||
it('should return the current language', () => { |
|
||||
expect(ProfileState.getProfile(PROFILE_STATE_DATA)).toEqual(PROFILE_STATE_DATA.profile); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
describe('#GetProfile', () => { |
|
||||
it('should call the profile service get method and update the state', () => { |
|
||||
const mockData = { userName: 'test', email: 'test@abp.io' }; |
|
||||
const spy = jest.spyOn(profileService, 'get'); |
|
||||
spy.mockReturnValue(of(mockData as any)); |
|
||||
|
|
||||
state.getProfile({ patchState } as any).subscribe(); |
|
||||
|
|
||||
expect(patchedData).toEqual({ profile: mockData }); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
describe('#UpdateProfile', () => { |
|
||||
it('should call the profile service update method and update the state', () => { |
|
||||
const mockData = { userName: 'test2', email: 'test@abp.io' }; |
|
||||
const spy = jest.spyOn(profileService, 'update'); |
|
||||
spy.mockReturnValue(of(mockData as any)); |
|
||||
|
|
||||
state.updateProfile({ patchState } as any, { payload: mockData as any }).subscribe(); |
|
||||
|
|
||||
expect(patchedData).toEqual({ profile: mockData }); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
describe('#ChangePassword', () => { |
|
||||
it('should call the profile service changePassword method', () => { |
|
||||
const mockData = { currentPassword: 'test123', newPassword: 'test123' }; |
|
||||
const spy = jest.spyOn(profileService, 'changePassword'); |
|
||||
spy.mockReturnValue(of(null)); |
|
||||
|
|
||||
state.changePassword(null, { payload: mockData }).subscribe(); |
|
||||
|
|
||||
expect(spy).toHaveBeenCalledWith(mockData, true); |
|
||||
}); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,64 +0,0 @@ |
|||||
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) {} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './identity.actions'; |
|
||||
@ -1,12 +0,0 @@ |
|||||
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[]; |
|
||||
} |
|
||||
} |
|
||||
@ -1,82 +0,0 @@ |
|||||
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)); |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './identity-state.service'; |
|
||||
@ -1,138 +0,0 @@ |
|||||
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, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './identity.state'; |
|
||||
@ -1,58 +0,0 @@ |
|||||
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)); |
|
||||
}); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './permission-management.actions'; |
|
||||
@ -1,11 +0,0 @@ |
|||||
import { ProviderInfoDto, UpdatePermissionsDto } from '../proxy/models'; |
|
||||
|
|
||||
export class GetPermissions { |
|
||||
static readonly type = '[PermissionManagement] Get Permissions'; |
|
||||
constructor(public payload: ProviderInfoDto) {} |
|
||||
} |
|
||||
|
|
||||
export class UpdatePermissions { |
|
||||
static readonly type = '[PermissionManagement] Update Permissions'; |
|
||||
constructor(public payload: ProviderInfoDto & UpdatePermissionsDto) {} |
|
||||
} |
|
||||
@ -1,13 +1,11 @@ |
|||||
import { CoreModule } from '@abp/ng.core'; |
import { CoreModule } from '@abp/ng.core'; |
||||
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
import { ThemeSharedModule } from '@abp/ng.theme.shared'; |
||||
import { NgModule } from '@angular/core'; |
import { NgModule } from '@angular/core'; |
||||
import { NgxsModule } from '@ngxs/store'; |
|
||||
import { PermissionManagementComponent } from './components/permission-management.component'; |
import { PermissionManagementComponent } from './components/permission-management.component'; |
||||
import { PermissionManagementState } from './states/permission-management.state'; |
|
||||
|
|
||||
@NgModule({ |
@NgModule({ |
||||
declarations: [PermissionManagementComponent], |
declarations: [PermissionManagementComponent], |
||||
imports: [CoreModule, ThemeSharedModule, NgxsModule.forFeature([PermissionManagementState])], |
imports: [CoreModule, ThemeSharedModule], |
||||
exports: [PermissionManagementComponent], |
exports: [PermissionManagementComponent], |
||||
}) |
}) |
||||
export class PermissionManagementModule {} |
export class PermissionManagementModule {} |
||||
|
|||||
@ -1 +0,0 @@ |
|||||
export * from './permission-management-state.service'; |
|
||||
@ -1,27 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import { PermissionManagementState } from '../states/permission-management.state'; |
|
||||
import { PermissionManagement } from '../models'; |
|
||||
import { GetPermissions, UpdatePermissions } from '../actions'; |
|
||||
|
|
||||
@Injectable({ |
|
||||
providedIn: 'root', |
|
||||
}) |
|
||||
export class PermissionManagementStateService { |
|
||||
constructor(private store: Store) {} |
|
||||
|
|
||||
getPermissionGroups() { |
|
||||
return this.store.selectSnapshot(PermissionManagementState.getPermissionGroups); |
|
||||
} |
|
||||
getEntityDisplayName() { |
|
||||
return this.store.selectSnapshot(PermissionManagementState.getEntityDisplayName); |
|
||||
} |
|
||||
|
|
||||
dispatchGetPermissions(...args: ConstructorParameters<typeof GetPermissions>) { |
|
||||
return this.store.dispatch(new GetPermissions(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchUpdatePermissions(...args: ConstructorParameters<typeof UpdatePermissions>) { |
|
||||
return this.store.dispatch(new UpdatePermissions(...args)); |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './permission-management.state'; |
|
||||
@ -1,47 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|
||||
import { tap } from 'rxjs/operators'; |
|
||||
import { GetPermissions, UpdatePermissions } from '../actions/permission-management.actions'; |
|
||||
import { PermissionManagement } from '../models/permission-management'; |
|
||||
import { ProviderInfoDto } from '../proxy/models'; |
|
||||
import { PermissionsService } from '../proxy/permissions.service'; |
|
||||
|
|
||||
@State<PermissionManagement.State>({ |
|
||||
name: 'PermissionManagementState', |
|
||||
defaults: { permissionRes: {} } as PermissionManagement.State, |
|
||||
}) |
|
||||
@Injectable() |
|
||||
export class PermissionManagementState { |
|
||||
@Selector() |
|
||||
static getPermissionGroups({ permissionRes }: PermissionManagement.State) { |
|
||||
return permissionRes.groups || []; |
|
||||
} |
|
||||
|
|
||||
@Selector() |
|
||||
static getEntityDisplayName({ permissionRes }: PermissionManagement.State): string { |
|
||||
return permissionRes.entityDisplayName; |
|
||||
} |
|
||||
|
|
||||
constructor(private service: PermissionsService) {} |
|
||||
|
|
||||
@Action(GetPermissions) |
|
||||
permissionManagementGet( |
|
||||
{ patchState }: StateContext<PermissionManagement.State>, |
|
||||
{ payload: { providerKey, providerName } = {} as ProviderInfoDto }: GetPermissions, |
|
||||
) { |
|
||||
return this.service.get(providerName, providerKey).pipe( |
|
||||
tap(permissionResponse => |
|
||||
patchState({ |
|
||||
permissionRes: permissionResponse, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(UpdatePermissions) |
|
||||
permissionManagementUpdate(_, { payload }: UpdatePermissions) { |
|
||||
return this.service.update(payload.providerName, payload.providerKey, { |
|
||||
permissions: payload.permissions, |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
@ -1,60 +0,0 @@ |
|||||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|
||||
import { PermissionManagementStateService } from '../services/permission-management-state.service'; |
|
||||
import { PermissionManagementState } from '../states/permission-management.state'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import * as PermissionManagementActions from '../actions'; |
|
||||
|
|
||||
describe('PermissionManagementStateService', () => { |
|
||||
let service: PermissionManagementStateService; |
|
||||
let spectator: SpectatorService<PermissionManagementStateService>; |
|
||||
let store: SpyObject<Store>; |
|
||||
|
|
||||
const createService = createServiceFactory({ |
|
||||
service: PermissionManagementStateService, |
|
||||
mocks: [Store], |
|
||||
}); |
|
||||
beforeEach(() => { |
|
||||
spectator = createService(); |
|
||||
service = spectator.service; |
|
||||
store = spectator.inject(Store); |
|
||||
}); |
|
||||
test('should have the all PermissionManagementState static methods', () => { |
|
||||
const reg = /(?<=static )(.*)(?=\()/gm; |
|
||||
PermissionManagementState.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(service[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const isDynamicSelector = PermissionManagementState[fnName].name !== 'memoized'; |
|
||||
|
|
||||
if (isDynamicSelector) { |
|
||||
PermissionManagementState[fnName] = jest.fn((...args) => args); |
|
||||
service[fnName]('test', 0, {}); |
|
||||
expect(PermissionManagementState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|
||||
} else { |
|
||||
service[fnName](); |
|
||||
expect(spy).toHaveBeenCalledWith(PermissionManagementState[fnName]); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
test('should have a dispatch method for every PermissionManagementState action', () => { |
|
||||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|
||||
PermissionManagementStateService.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(PermissionManagementActions[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'dispatch'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const params = Array.from(new Array(PermissionManagementActions[fnName].length)); |
|
||||
|
|
||||
service[`dispatch${fnName}`](...params); |
|
||||
expect(spy).toHaveBeenCalledWith(new PermissionManagementActions[fnName](...params)); |
|
||||
}); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,12 +1,5 @@ |
|||||
/* |
|
||||
* Public API Surface of permission-management |
|
||||
*/ |
|
||||
|
|
||||
export * from './lib/permission-management.module'; |
|
||||
export * from './lib/actions'; |
|
||||
export * from './lib/components'; |
export * from './lib/components'; |
||||
export * from './lib/enums/components'; |
export * from './lib/enums/components'; |
||||
export * from './lib/models'; |
export * from './lib/models'; |
||||
export * from './lib/services'; |
export * from './lib/permission-management.module'; |
||||
export * from './lib/states'; |
|
||||
export * from './lib/proxy'; |
export * from './lib/proxy'; |
||||
|
|||||
@ -1 +0,0 @@ |
|||||
export * from './setting-management.actions'; |
|
||||
@ -1,6 +0,0 @@ |
|||||
import { ABP } from '@abp/ng.core'; |
|
||||
|
|
||||
export class SetSelectedSettingTab { |
|
||||
static readonly type = '[SettingManagement] Set Selected Tab'; |
|
||||
constructor(public payload: ABP.Tab) {} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './setting-management'; |
|
||||
@ -1,7 +0,0 @@ |
|||||
import { ABP } from '@abp/ng.core'; |
|
||||
|
|
||||
export namespace SettingManagement { |
|
||||
export interface State { |
|
||||
selectedTab?: ABP.Tab; |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './setting-management.state'; |
|
||||
@ -1,26 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|
||||
import { SetSelectedSettingTab } from '../actions/setting-management.actions'; |
|
||||
import { SettingManagement } from '../models/setting-management'; |
|
||||
|
|
||||
@State<SettingManagement.State>({ |
|
||||
name: 'SettingManagementState', |
|
||||
defaults: {}, |
|
||||
}) |
|
||||
@Injectable() |
|
||||
export class SettingManagementState { |
|
||||
@Selector() |
|
||||
static getSelectedTab({ selectedTab }: SettingManagement.State) { |
|
||||
return selectedTab; |
|
||||
} |
|
||||
|
|
||||
@Action(SetSelectedSettingTab) |
|
||||
settingManagementAction( |
|
||||
{ patchState }: StateContext<SettingManagement.State>, |
|
||||
{ payload }: SetSelectedSettingTab, |
|
||||
) { |
|
||||
patchState({ |
|
||||
selectedTab: payload, |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './tenant-management.actions'; |
|
||||
@ -1,26 +0,0 @@ |
|||||
import { GetTenantsInput, TenantCreateDto, TenantUpdateDto } from '../proxy/models'; |
|
||||
|
|
||||
export class GetTenants { |
|
||||
static readonly type = '[TenantManagement] Get Tenant'; |
|
||||
constructor(public payload?: GetTenantsInput) {} |
|
||||
} |
|
||||
|
|
||||
export class GetTenantById { |
|
||||
static readonly type = '[TenantManagement] Get Tenant By Id'; |
|
||||
constructor(public payload: string) {} |
|
||||
} |
|
||||
|
|
||||
export class CreateTenant { |
|
||||
static readonly type = '[TenantManagement] Create Tenant'; |
|
||||
constructor(public payload: TenantCreateDto) {} |
|
||||
} |
|
||||
|
|
||||
export class UpdateTenant { |
|
||||
static readonly type = '[TenantManagement] Update Tenant'; |
|
||||
constructor(public payload: TenantUpdateDto & { id: string }) {} |
|
||||
} |
|
||||
|
|
||||
export class DeleteTenant { |
|
||||
static readonly type = '[TenantManagement] Delete Tenant'; |
|
||||
constructor(public payload: string) {} |
|
||||
} |
|
||||
File diff suppressed because it is too large
@ -1 +0,0 @@ |
|||||
export * from './tenant-management-state.service'; |
|
||||
@ -1,41 +0,0 @@ |
|||||
import { Injectable } from '@angular/core'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import { TenantManagementState } from '../states/tenant-management.state'; |
|
||||
import { ABP } from '@abp/ng.core'; |
|
||||
import { GetTenants, GetTenantById, CreateTenant, UpdateTenant, DeleteTenant } from '../actions'; |
|
||||
import { TenantManagement } from '../models'; |
|
||||
|
|
||||
@Injectable({ |
|
||||
providedIn: 'root', |
|
||||
}) |
|
||||
export class TenantManagementStateService { |
|
||||
constructor(private store: Store) {} |
|
||||
|
|
||||
get() { |
|
||||
return this.store.selectSnapshot(TenantManagementState.get); |
|
||||
} |
|
||||
|
|
||||
getTenantsTotalCount() { |
|
||||
return this.store.selectSnapshot(TenantManagementState.getTenantsTotalCount); |
|
||||
} |
|
||||
|
|
||||
dispatchGetTenants(...args: ConstructorParameters<typeof GetTenants>) { |
|
||||
return this.store.dispatch(new GetTenants(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchGetTenantById(...args: ConstructorParameters<typeof GetTenantById>) { |
|
||||
return this.store.dispatch(new GetTenantById(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchCreateTenant(...args: ConstructorParameters<typeof CreateTenant>) { |
|
||||
return this.store.dispatch(new CreateTenant(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchUpdateTenant(...args: ConstructorParameters<typeof UpdateTenant>) { |
|
||||
return this.store.dispatch(new UpdateTenant(...args)); |
|
||||
} |
|
||||
|
|
||||
dispatchDeleteTenant(...args: ConstructorParameters<typeof DeleteTenant>) { |
|
||||
return this.store.dispatch(new DeleteTenant(...args)); |
|
||||
} |
|
||||
} |
|
||||
@ -1 +0,0 @@ |
|||||
export * from './tenant-management.state'; |
|
||||
@ -1,70 +0,0 @@ |
|||||
import { ABP, PagedResultDto } from '@abp/ng.core'; |
|
||||
import { Action, Selector, State, StateContext } from '@ngxs/store'; |
|
||||
import { tap } from 'rxjs/operators'; |
|
||||
import { |
|
||||
CreateTenant, |
|
||||
DeleteTenant, |
|
||||
GetTenantById, |
|
||||
GetTenants, |
|
||||
UpdateTenant, |
|
||||
} from '../actions/tenant-management.actions'; |
|
||||
import { TenantManagement } from '../models/tenant-management'; |
|
||||
import { Injectable } from '@angular/core'; |
|
||||
import { TenantService } from '../proxy/tenant.service'; |
|
||||
import { TenantDto } from '../proxy/models'; |
|
||||
|
|
||||
@State<TenantManagement.State>({ |
|
||||
name: 'TenantManagementState', |
|
||||
defaults: { result: {}, selectedItem: {} } as TenantManagement.State, |
|
||||
}) |
|
||||
@Injectable() |
|
||||
export class TenantManagementState { |
|
||||
@Selector() |
|
||||
static get({ result }: TenantManagement.State): TenantDto[] { |
|
||||
return result.items || []; |
|
||||
} |
|
||||
|
|
||||
@Selector() |
|
||||
static getTenantsTotalCount({ result }: TenantManagement.State): number { |
|
||||
return result.totalCount; |
|
||||
} |
|
||||
|
|
||||
constructor(private service: TenantService) {} |
|
||||
|
|
||||
@Action(GetTenants) |
|
||||
get({ patchState }: StateContext<TenantManagement.State>, { payload }: GetTenants) { |
|
||||
return this.service.getList(payload).pipe( |
|
||||
tap(result => |
|
||||
patchState({ |
|
||||
result, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(GetTenantById) |
|
||||
getById({ patchState }: StateContext<TenantManagement.State>, { payload }: GetTenantById) { |
|
||||
return this.service.get(payload).pipe( |
|
||||
tap(selectedItem => |
|
||||
patchState({ |
|
||||
selectedItem, |
|
||||
}), |
|
||||
), |
|
||||
); |
|
||||
} |
|
||||
|
|
||||
@Action(DeleteTenant) |
|
||||
delete(_, { payload }: DeleteTenant) { |
|
||||
return this.service.delete(payload); |
|
||||
} |
|
||||
|
|
||||
@Action(CreateTenant) |
|
||||
add(_, { payload }: CreateTenant) { |
|
||||
return this.service.create(payload); |
|
||||
} |
|
||||
|
|
||||
@Action(UpdateTenant) |
|
||||
update({ getState }: StateContext<TenantManagement.State>, { payload }: UpdateTenant) { |
|
||||
return this.service.update(payload.id, { ...getState().selectedItem, ...payload }); |
|
||||
} |
|
||||
} |
|
||||
@ -1,61 +0,0 @@ |
|||||
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest'; |
|
||||
import { TenantManagementStateService } from '../services/tenant-management-state.service'; |
|
||||
import { TenantManagementState } from '../states/tenant-management.state'; |
|
||||
import { Store } from '@ngxs/store'; |
|
||||
import * as TenantManagementActions from '../actions'; |
|
||||
|
|
||||
describe('TenantManagementStateService', () => { |
|
||||
let service: TenantManagementStateService; |
|
||||
let spectator: SpectatorService<TenantManagementStateService>; |
|
||||
let store: SpyObject<Store>; |
|
||||
|
|
||||
const createService = createServiceFactory({ |
|
||||
service: TenantManagementStateService, |
|
||||
mocks: [Store], |
|
||||
}); |
|
||||
beforeEach(() => { |
|
||||
spectator = createService(); |
|
||||
service = spectator.service; |
|
||||
store = spectator.inject(Store); |
|
||||
}); |
|
||||
|
|
||||
test('should have the all TenantManagementState static methods', () => { |
|
||||
const reg = /(?<=static )(.*)(?=\()/gm; |
|
||||
TenantManagementState.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(service[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'selectSnapshot'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const isDynamicSelector = TenantManagementState[fnName].name !== 'memoized'; |
|
||||
|
|
||||
if (isDynamicSelector) { |
|
||||
TenantManagementState[fnName] = jest.fn((...args) => args); |
|
||||
service[fnName]('test', 0, {}); |
|
||||
expect(TenantManagementState[fnName]).toHaveBeenCalledWith('test', 0, {}); |
|
||||
} else { |
|
||||
service[fnName](); |
|
||||
expect(spy).toHaveBeenCalledWith(TenantManagementState[fnName]); |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
test('should have a dispatch method for every TenantManagementState action', () => { |
|
||||
const reg = /(?<=dispatch)(\w+)(?=\()/gm; |
|
||||
TenantManagementStateService.toString() |
|
||||
.match(reg) |
|
||||
.forEach(fnName => { |
|
||||
expect(TenantManagementActions[fnName]).toBeTruthy(); |
|
||||
|
|
||||
const spy = jest.spyOn(store, 'dispatch'); |
|
||||
spy.mockClear(); |
|
||||
|
|
||||
const params = Array.from(new Array(TenantManagementActions[fnName].length)); |
|
||||
|
|
||||
service[`dispatch${fnName}`](...params); |
|
||||
expect(spy).toHaveBeenCalledWith(new TenantManagementActions[fnName](...params)); |
|
||||
}); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,10 +1,7 @@ |
|||||
export * from './lib/actions'; |
|
||||
export * from './lib/components'; |
export * from './lib/components'; |
||||
export * from './lib/enums'; |
export * from './lib/enums'; |
||||
export * from './lib/guards'; |
export * from './lib/guards'; |
||||
export * from './lib/models'; |
export * from './lib/models'; |
||||
export * from './lib/proxy'; |
export * from './lib/proxy'; |
||||
export * from './lib/services'; |
|
||||
export * from './lib/states'; |
|
||||
export * from './lib/tenant-management.module'; |
export * from './lib/tenant-management.module'; |
||||
export * from './lib/tokens'; |
export * from './lib/tokens'; |
||||
|
|||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue