mirror of https://github.com/Squidex/squidex.git
16 changed files with 544 additions and 269 deletions
@ -0,0 +1,159 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { IMock, It, Mock, Times } from 'typemoq'; |
||||
|
|
||||
|
import { RulesState } from './rules.state'; |
||||
|
|
||||
|
import { |
||||
|
AppsState, |
||||
|
AuthService, |
||||
|
DialogService, |
||||
|
DateTime, |
||||
|
RuleDto, |
||||
|
RulesService, |
||||
|
Version, |
||||
|
Versioned, |
||||
|
CreateRuleDto, |
||||
|
UpdateRuleDto |
||||
|
} from '@app/shared'; |
||||
|
|
||||
|
describe('RulesState', () => { |
||||
|
const app = 'my-app'; |
||||
|
const creation = DateTime.today(); |
||||
|
const creator = 'not-me'; |
||||
|
const modified = DateTime.now(); |
||||
|
const modifier = 'me'; |
||||
|
const version = new Version('1'); |
||||
|
const newVersion = new Version('2'); |
||||
|
|
||||
|
const oldRules = [ |
||||
|
new RuleDto('id1', creator, creator, creation, creation, version, false, {}, 'trigger1', {}, 'action1'), |
||||
|
new RuleDto('id2', creator, creator, creation, creation, version, true, {}, 'trigger2', {}, 'action2') |
||||
|
]; |
||||
|
|
||||
|
let dialogs: IMock<DialogService>; |
||||
|
let appsState: IMock<AppsState>; |
||||
|
let authService: IMock<AuthService>; |
||||
|
let rulesService: IMock<RulesService>; |
||||
|
let rulesState: RulesState; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
dialogs = Mock.ofType<DialogService>(); |
||||
|
|
||||
|
authService = Mock.ofType<AuthService>(); |
||||
|
|
||||
|
authService.setup(x => x.user) |
||||
|
.returns(() => <any>{ id: '1', token: modifier }); |
||||
|
|
||||
|
appsState = Mock.ofType<AppsState>(); |
||||
|
|
||||
|
appsState.setup(x => x.appName) |
||||
|
.returns(() => app); |
||||
|
|
||||
|
rulesService = Mock.ofType<RulesService>(); |
||||
|
|
||||
|
rulesService.setup(x => x.getRules(app)) |
||||
|
.returns(() => Observable.of(oldRules)); |
||||
|
|
||||
|
rulesState = new RulesState(appsState.object, authService.object, dialogs.object, rulesService.object); |
||||
|
rulesState.load().subscribe(); |
||||
|
}); |
||||
|
|
||||
|
it('should load rules', () => { |
||||
|
expect(rulesState.snapshot.rules.values).toEqual(oldRules); |
||||
|
|
||||
|
dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.never()); |
||||
|
}); |
||||
|
|
||||
|
it('should show notification on load when flag is true', () => { |
||||
|
rulesState.load(true).subscribe(); |
||||
|
|
||||
|
dialogs.verify(x => x.notifyInfo(It.isAnyString()), Times.once()); |
||||
|
}); |
||||
|
|
||||
|
it('should add rule to snapshot when created', () => { |
||||
|
const newRule = new RuleDto('id3', creator, creator, creation, creation, version, false, {}, 'trigger3', {}, 'action3'); |
||||
|
|
||||
|
const request = new CreateRuleDto({}, {}); |
||||
|
|
||||
|
rulesService.setup(x => x.postRule(app, request, modifier, creation)) |
||||
|
.returns(() => Observable.of(newRule)); |
||||
|
|
||||
|
rulesState.create(request, creation).subscribe(); |
||||
|
|
||||
|
expect(rulesState.snapshot.rules.values).toEqual([...oldRules, newRule]); |
||||
|
}); |
||||
|
|
||||
|
it('should update action and update and user info when updated action', () => { |
||||
|
const newAction = {}; |
||||
|
|
||||
|
rulesService.setup(x => x.putRule(app, oldRules[0].id, It.is<UpdateRuleDto>(i => true), version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
rulesState.updateAction(oldRules[0], newAction, modified).subscribe(); |
||||
|
|
||||
|
const rule_1 = rulesState.snapshot.rules.at(0); |
||||
|
|
||||
|
expect(rule_1.action).toBe(newAction); |
||||
|
expectToBeModified(rule_1); |
||||
|
}); |
||||
|
|
||||
|
it('should update trigger and update and user info when updated trigger', () => { |
||||
|
const newTrigger = {}; |
||||
|
|
||||
|
rulesService.setup(x => x.putRule(app, oldRules[0].id, It.is<UpdateRuleDto>(i => true), version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
rulesState.updateTrigger(oldRules[0], newTrigger, modified).subscribe(); |
||||
|
|
||||
|
const rule_1 = rulesState.snapshot.rules.at(0); |
||||
|
|
||||
|
expect(rule_1.trigger).toBe(newTrigger); |
||||
|
expectToBeModified(rule_1); |
||||
|
}); |
||||
|
|
||||
|
it('should mark as enabled and update and user info when enabled', () => { |
||||
|
rulesService.setup(x => x.enableRule(app, oldRules[0].id, version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
rulesState.enable(oldRules[0], modified).subscribe(); |
||||
|
|
||||
|
const rule_1 = rulesState.snapshot.rules.at(0); |
||||
|
|
||||
|
expect(rule_1.isEnabled).toBeTruthy(); |
||||
|
expectToBeModified(rule_1); |
||||
|
}); |
||||
|
|
||||
|
it('should mark as disabled and update and user info when disabled', () => { |
||||
|
rulesService.setup(x => x.disableRule(app, oldRules[1].id, version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
rulesState.disable(oldRules[1], modified).subscribe(); |
||||
|
|
||||
|
const rule_1 = rulesState.snapshot.rules.at(1); |
||||
|
|
||||
|
expect(rule_1.isEnabled).toBeFalsy(); |
||||
|
expectToBeModified(rule_1); |
||||
|
}); |
||||
|
|
||||
|
it('should remove rule from snapshot when deleted', () => { |
||||
|
rulesService.setup(x => x.deleteRule(app, oldRules[0].id, version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
rulesState.delete(oldRules[0]).subscribe(); |
||||
|
|
||||
|
expect(rulesState.snapshot.rules.values).toEqual([oldRules[1]]); |
||||
|
}); |
||||
|
|
||||
|
function expectToBeModified(rule_1: RuleDto) { |
||||
|
expect(rule_1.lastModified).toEqual(modified); |
||||
|
expect(rule_1.lastModifiedBy).toEqual(modifier); |
||||
|
expect(rule_1.version).toEqual(newVersion); |
||||
|
} |
||||
|
}); |
||||
@ -0,0 +1,184 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import '@app/framework/utils/rxjs-extensions'; |
||||
|
|
||||
|
import { |
||||
|
DialogService, |
||||
|
ImmutableArray, |
||||
|
State, |
||||
|
Version, |
||||
|
DateTime |
||||
|
} from '@app/framework'; |
||||
|
|
||||
|
import { AppsState } from './apps.state'; |
||||
|
import { AuthService} from './../services/auth.service'; |
||||
|
|
||||
|
import { |
||||
|
CreateRuleDto, |
||||
|
RuleDto, |
||||
|
RulesService, |
||||
|
UpdateRuleDto |
||||
|
} from './../services/rules.service'; |
||||
|
|
||||
|
interface Snapshot { |
||||
|
rules: ImmutableArray<RuleDto>; |
||||
|
} |
||||
|
|
||||
|
@Injectable() |
||||
|
export class RulesState extends State<Snapshot> { |
||||
|
public rules = |
||||
|
this.changes.map(x => x.rules); |
||||
|
|
||||
|
constructor( |
||||
|
private readonly appsState: AppsState, |
||||
|
private readonly authState: AuthService, |
||||
|
private readonly dialogs: DialogService, |
||||
|
private readonly rulesService: RulesService |
||||
|
) { |
||||
|
super({ rules: ImmutableArray.empty() }); |
||||
|
} |
||||
|
|
||||
|
public load(notifyLoad = false): Observable<any> { |
||||
|
return this.rulesService.getRules(this.appName) |
||||
|
.do(dtos => { |
||||
|
if (notifyLoad) { |
||||
|
this.dialogs.notifyInfo('Rules reloaded.'); |
||||
|
} |
||||
|
|
||||
|
this.next(s => { |
||||
|
const rules = ImmutableArray.of(dtos); |
||||
|
|
||||
|
return { ...s, rules }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public create(request: CreateRuleDto, now?: DateTime): Observable<any> { |
||||
|
return this.rulesService.postRule(this.appName, request, this.user, now || DateTime.now()) |
||||
|
.do(dto => { |
||||
|
this.next(s => { |
||||
|
const rules = s.rules.push(dto); |
||||
|
|
||||
|
return { ...s, rules }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public delete(rule: RuleDto): Observable<any> { |
||||
|
return this.rulesService.deleteRule(this.appName, rule.id, rule.version) |
||||
|
.do(dto => { |
||||
|
this.next(s => { |
||||
|
const rules = s.rules.removeAll(x => x.id === rule.id); |
||||
|
|
||||
|
return { ...s, rules }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public updateAction(rule: RuleDto, action: any, now?: DateTime): Observable<any> { |
||||
|
return this.rulesService.putRule(this.appName, rule.id, new UpdateRuleDto(null, action), rule.version) |
||||
|
.do(dto => { |
||||
|
this.replaceRule(updateAction(rule, action, this.user, dto.version, now)); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public updateTrigger(rule: RuleDto, trigger: any, now?: DateTime): Observable<any> { |
||||
|
return this.rulesService.putRule(this.appName, rule.id, new UpdateRuleDto(trigger, null), rule.version) |
||||
|
.do(dto => { |
||||
|
this.replaceRule(updateTrigger(rule, trigger, this.user, dto.version, now)); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public enable(rule: RuleDto, now?: DateTime): Observable<any> { |
||||
|
return this.rulesService.enableRule(this.appName, rule.id, rule.version) |
||||
|
.do(dto => { |
||||
|
this.replaceRule(enable(rule, this.user, dto.version, now)); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public disable(rule: RuleDto, now?: DateTime): Observable<any> { |
||||
|
return this.rulesService.disableRule(this.appName, rule.id, rule.version) |
||||
|
.do(dto => { |
||||
|
this.replaceRule(disable(rule, this.user, dto.version, now)); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
private replaceRule(rule: RuleDto) { |
||||
|
this.next(s => { |
||||
|
const rules = s.rules.replaceBy('id', rule); |
||||
|
|
||||
|
return { ...s, rules }; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private get appName() { |
||||
|
return this.appsState.appName; |
||||
|
} |
||||
|
|
||||
|
private get user() { |
||||
|
return this.authState.user!.token; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const updateTrigger = (rule: RuleDto, trigger: any, user: string, version: Version, now?: DateTime) => |
||||
|
new RuleDto( |
||||
|
rule.id, |
||||
|
rule.createdBy, user, |
||||
|
rule.created, now || DateTime.now(), |
||||
|
version, |
||||
|
rule.isEnabled, |
||||
|
trigger, |
||||
|
trigger.triggerType, |
||||
|
rule.action, |
||||
|
rule.action.actionType); |
||||
|
|
||||
|
const updateAction = (rule: RuleDto, action: any, user: string, version: Version, now?: DateTime) => |
||||
|
new RuleDto( |
||||
|
rule.id, |
||||
|
rule.createdBy, user, |
||||
|
rule.created, now || DateTime.now(), |
||||
|
version, |
||||
|
rule.isEnabled, |
||||
|
rule.trigger, |
||||
|
rule.trigger.triggerType, |
||||
|
action, |
||||
|
action.actionType); |
||||
|
|
||||
|
const enable = (rule: RuleDto, user: string, version: Version, now?: DateTime) => |
||||
|
new RuleDto( |
||||
|
rule.id, |
||||
|
rule.createdBy, user, |
||||
|
rule.created, now || DateTime.now(), |
||||
|
version, |
||||
|
true, |
||||
|
rule.trigger, |
||||
|
rule.triggerType, |
||||
|
rule.action, |
||||
|
rule.actionType); |
||||
|
|
||||
|
const disable = (rule: RuleDto, user: string, version: Version, now?: DateTime) => |
||||
|
new RuleDto( |
||||
|
rule.id, |
||||
|
rule.createdBy, user, |
||||
|
rule.created, now || DateTime.now(), |
||||
|
version, |
||||
|
false, |
||||
|
rule.trigger, |
||||
|
rule.triggerType, |
||||
|
rule.action, |
||||
|
rule.actionType); |
||||
Loading…
Reference in new issue