mirror of https://github.com/Squidex/squidex.git
43 changed files with 376 additions and 283 deletions
@ -0,0 +1,99 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { IMock, Mock } from 'typemoq'; |
||||
|
|
||||
|
import { |
||||
|
AppsState, |
||||
|
AppClientDto, |
||||
|
AppClientsDto, |
||||
|
AppClientsService, |
||||
|
ClientsState, |
||||
|
DialogService, |
||||
|
UpdateAppClientDto, |
||||
|
Version, |
||||
|
Versioned, |
||||
|
CreateAppClientDto |
||||
|
} from '@app/shared'; |
||||
|
|
||||
|
describe('ClientsState', () => { |
||||
|
const app = 'my-app'; |
||||
|
const version = new Version('1'); |
||||
|
const newVersion = new Version('2'); |
||||
|
|
||||
|
const oldClients = [ |
||||
|
new AppClientDto('id1', 'name1', 'secret1', 'Developer'), |
||||
|
new AppClientDto('id2', 'name2', 'secret2', 'Developer') |
||||
|
]; |
||||
|
|
||||
|
let dialogs: IMock<DialogService>; |
||||
|
let appsState: IMock<AppsState>; |
||||
|
let clientsService: IMock<AppClientsService>; |
||||
|
let clientsState: ClientsState; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
dialogs = Mock.ofType<DialogService>(); |
||||
|
|
||||
|
appsState = Mock.ofType<AppsState>(); |
||||
|
|
||||
|
appsState.setup(x => x.appName) |
||||
|
.returns(() => app); |
||||
|
|
||||
|
clientsService = Mock.ofType<AppClientsService>(); |
||||
|
|
||||
|
clientsService.setup(x => x.getClients(app)) |
||||
|
.returns(() => Observable.of(new AppClientsDto(oldClients, version))); |
||||
|
|
||||
|
clientsState = new ClientsState(clientsService.object, appsState.object, dialogs.object); |
||||
|
clientsState.load().subscribe(); |
||||
|
}); |
||||
|
|
||||
|
it('should load clients', () => { |
||||
|
expect(clientsState.snapshot.clients.values).toEqual(oldClients); |
||||
|
expect(clientsState.snapshot.version).toEqual(version); |
||||
|
}); |
||||
|
|
||||
|
it('should add client to snapshot', () => { |
||||
|
const newClient = new AppClientDto('id3', 'name3', 'secret3', 'Developer'); |
||||
|
|
||||
|
const request = new CreateAppClientDto('id3'); |
||||
|
|
||||
|
clientsService.setup(x => x.postClient(app, request, version)) |
||||
|
.returns(() => Observable.of(new Versioned<AppClientDto>(newVersion, newClient))); |
||||
|
|
||||
|
clientsState.attach(request).subscribe(); |
||||
|
|
||||
|
expect(clientsState.snapshot.clients.values).toEqual([...oldClients, newClient]); |
||||
|
expect(clientsState.snapshot.version).toEqual(newVersion); |
||||
|
}); |
||||
|
|
||||
|
it('should update client in snapshot', () => { |
||||
|
const request = new UpdateAppClientDto('NewName', 'NewPermission'); |
||||
|
|
||||
|
clientsService.setup(x => x.putClient(app, oldClients[0].id, request, version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
clientsState.update(oldClients[0], request).subscribe(); |
||||
|
|
||||
|
const client_1 = clientsState.snapshot.clients.at(0); |
||||
|
|
||||
|
expect(client_1.name).toBe('NewName'); |
||||
|
expect(client_1.permission).toBe('NewPermission'); |
||||
|
expect(clientsState.snapshot.version).toEqual(newVersion); |
||||
|
}); |
||||
|
|
||||
|
it('should remove client from snapshot', () => { |
||||
|
clientsService.setup(x => x.deleteClient(app, oldClients[0].id, version)) |
||||
|
.returns(() => Observable.of(new Versioned<any>(newVersion, {}))); |
||||
|
|
||||
|
clientsState.revoke(oldClients[0]).subscribe(); |
||||
|
|
||||
|
expect(clientsState.snapshot.clients.values).toEqual([oldClients[1]]); |
||||
|
expect(clientsState.snapshot.version).toEqual(newVersion); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,124 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { FormBuilder, Validators, FormGroup } from '@angular/forms'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
|
||||
|
import '@app/framework/utils/rxjs-extensions'; |
||||
|
|
||||
|
import { |
||||
|
DialogService, |
||||
|
ImmutableArray, |
||||
|
Form, |
||||
|
State, |
||||
|
ValidatorsEx, |
||||
|
Version |
||||
|
} from '@app/framework'; |
||||
|
|
||||
|
import { AppsState } from './apps.state'; |
||||
|
|
||||
|
import { |
||||
|
AppClientDto, |
||||
|
AppClientsService, |
||||
|
CreateAppClientDto, |
||||
|
UpdateAppClientDto |
||||
|
} from './../services/app-clients.service'; |
||||
|
|
||||
|
export class AttachClientForm extends Form<FormGroup> { |
||||
|
public hasNoName = |
||||
|
this.form.controls['name'].valueChanges.startWith('').map(x => !x || x.length === 0); |
||||
|
|
||||
|
constructor(formBuilder: FormBuilder) { |
||||
|
super(formBuilder.group({ |
||||
|
name: ['', |
||||
|
[ |
||||
|
Validators.maxLength(40), |
||||
|
ValidatorsEx.pattern('[a-z0-9]+(\-[a-z0-9]+)*', 'Name can contain lower case letters (a-z), numbers and dashes (not at the end).') |
||||
|
] |
||||
|
] |
||||
|
})); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
interface Snapshot { |
||||
|
clients: ImmutableArray<AppClientDto>; |
||||
|
|
||||
|
isLoaded: boolean; |
||||
|
|
||||
|
version: Version; |
||||
|
} |
||||
|
|
||||
|
@Injectable() |
||||
|
export class ClientsState extends State<Snapshot> { |
||||
|
public clients = |
||||
|
this.changes.map(x => x.clients); |
||||
|
|
||||
|
public isLoaded = |
||||
|
this.changes.map(x => x.isLoaded); |
||||
|
|
||||
|
constructor( |
||||
|
private readonly appClientsService: AppClientsService, |
||||
|
private readonly appsState: AppsState, |
||||
|
private readonly dialogs: DialogService |
||||
|
) { |
||||
|
super({ clients: ImmutableArray.empty(), version: new Version(''), isLoaded: false }); |
||||
|
} |
||||
|
|
||||
|
public load(): Observable<any> { |
||||
|
return this.appClientsService.getClients(this.appName) |
||||
|
.do(dtos => { |
||||
|
this.next(s => { |
||||
|
return { clients: ImmutableArray.of(dtos.clients), isLoaded: true, version: dtos.version }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public attach(request: CreateAppClientDto): Observable<any> { |
||||
|
return this.appClientsService.postClient(this.appName, request, this.snapshot.version) |
||||
|
.do(dto => { |
||||
|
this.next(s => { |
||||
|
const clients = s.clients.push(dto.payload); |
||||
|
|
||||
|
return { ...s, clients, version: dto.version }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public revoke(client: AppClientDto): Observable<any> { |
||||
|
return this.appClientsService.deleteClient(this.appName, client.id, this.snapshot.version) |
||||
|
.do(dto => { |
||||
|
this.next(s => { |
||||
|
const clients = s.clients.filter(c => c.id !== client.id); |
||||
|
|
||||
|
return { ...s, clients, version: dto.version }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
public update(client: AppClientDto, request: UpdateAppClientDto): Observable<any> { |
||||
|
return this.appClientsService.putClient(this.appName, client.id, request, this.snapshot.version) |
||||
|
.do(dto => { |
||||
|
this.next(s => { |
||||
|
const clients = s.clients.replaceBy('id', update(client, request)); |
||||
|
|
||||
|
return { ...s, clients, version: dto.version }; |
||||
|
}); |
||||
|
}) |
||||
|
.notify(this.dialogs); |
||||
|
} |
||||
|
|
||||
|
private get appName() { |
||||
|
return this.appsState.appName; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const update = (client: AppClientDto, request: UpdateAppClientDto) => |
||||
|
new AppClientDto(client.id, request.name || client.name, client.secret, request.permission || client.permission); |
||||
Loading…
Reference in new issue