mirror of https://github.com/Squidex/squidex.git
16 changed files with 993 additions and 146 deletions
@ -0,0 +1,87 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
/* |
|||
import { IMock, Mock } from 'typemoq'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { UserManagementService } from 'shared'; |
|||
|
|||
import { ResolveUserGuard } from './resolve-user.guard'; |
|||
import { RouterMockup } from './router-mockup'; |
|||
|
|||
describe('ResolveUserGuard', () => { |
|||
const route = { |
|||
params: {}, |
|||
parent: { |
|||
params: { |
|||
userId: 'my-user' |
|||
} |
|||
} |
|||
}; |
|||
|
|||
let usersService: IMock<UserManagementService>; |
|||
|
|||
beforeEach(() => { |
|||
usersService = Mock.ofType(UserManagementService); |
|||
}); |
|||
|
|||
it('should throw if route does not contain parameter', () => { |
|||
const guard = new ResolveUserGuard(usersService.object, <any>new RouterMockup()); |
|||
|
|||
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain user id.'); |
|||
}); |
|||
|
|||
it('should navigate to 404 page if user is not found', (done) => { |
|||
usersService.setup(x => x.getUser('my-user')) |
|||
.returns(() => Observable.of(null!)); |
|||
const router = new RouterMockup(); |
|||
|
|||
const guard = new ResolveUserGuard(usersService.object, <any>router); |
|||
|
|||
guard.resolve(<any>route, <any>{}) |
|||
.subscribe(result => { |
|||
expect(result).toBeFalsy(); |
|||
expect(router.lastNavigation).toEqual(['/404']); |
|||
|
|||
done(); |
|||
}); |
|||
}); |
|||
|
|||
it('should navigate to 404 page if user loading fails', (done) => { |
|||
usersService.setup(x => x.getUser('my-user')) |
|||
.returns(() => Observable.throw(null!)); |
|||
const router = new RouterMockup(); |
|||
|
|||
const guard = new ResolveUserGuard(usersService.object, <any>router); |
|||
|
|||
guard.resolve(<any>route, <any>{}) |
|||
.subscribe(result => { |
|||
expect(result).toBeFalsy(); |
|||
expect(router.lastNavigation).toEqual(['/404']); |
|||
|
|||
done(); |
|||
}); |
|||
}); |
|||
|
|||
it('should return user if loading succeeded', (done) => { |
|||
const user: any = {}; |
|||
|
|||
usersService.setup(x => x.getUser('my-user')) |
|||
.returns(() => Observable.of(user)); |
|||
const router = new RouterMockup(); |
|||
|
|||
const guard = new ResolveUserGuard(usersService.object, <any>router); |
|||
|
|||
guard.resolve(<any>route, <any>{}) |
|||
.subscribe(result => { |
|||
expect(result).toBe(user); |
|||
|
|||
done(); |
|||
}); |
|||
}); |
|||
}); |
|||
*/ |
|||
@ -0,0 +1,24 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { UsersState } from './../state/users.state'; |
|||
|
|||
@Injectable() |
|||
export class UnsetUserGuard implements CanActivate { |
|||
constructor( |
|||
private readonly usersState: UsersState |
|||
) { |
|||
} |
|||
|
|||
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { |
|||
return this.usersState.selectUser(null).map(r => !r); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { allParams } from 'framework'; |
|||
|
|||
import { UsersState } from './../state/users.state'; |
|||
|
|||
@Injectable() |
|||
export class UserMustExistGuard implements CanActivate { |
|||
constructor( |
|||
private readonly usersState: UsersState, |
|||
private readonly router: Router |
|||
) { |
|||
} |
|||
|
|||
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { |
|||
const params = allParams(route); |
|||
|
|||
const userId = params['userId']; |
|||
|
|||
if (!userId) { |
|||
throw 'Route must contain user id.'; |
|||
} |
|||
|
|||
const result = |
|||
this.usersState.selectUser(userId).map(u => !!u) |
|||
.do(dto => { |
|||
if (!dto) { |
|||
this.router.navigate(['/404']); |
|||
} |
|||
}) |
|||
.catch(error => { |
|||
this.router.navigate(['/404']); |
|||
|
|||
return Observable.of(false); |
|||
}); |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
@ -0,0 +1,130 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; |
|||
import { inject, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { ApiUrlConfig } from 'framework'; |
|||
|
|||
import { EventConsumerDto, EventConsumersService } from './event-consumers.service'; |
|||
|
|||
describe('EventConsumerDto', () => { |
|||
it('should update isStopped property when starting', () => { |
|||
const consumer_1 = new EventConsumerDto('consumer', true, false, 'error', 'position'); |
|||
const consumer_2 = consumer_1.start(); |
|||
|
|||
expect(consumer_2.isStopped).toBeFalsy(); |
|||
}); |
|||
|
|||
it('should update isStopped property when starting', () => { |
|||
const consumer_1 = new EventConsumerDto('consumer', false, false, 'error', 'position'); |
|||
const consumer_2 = consumer_1.stop(); |
|||
|
|||
expect(consumer_2.isStopped).toBeTruthy(); |
|||
}); |
|||
|
|||
it('should update isResetting property when resetting', () => { |
|||
const consumer_1 = new EventConsumerDto('consumer', false, false, 'error', 'position'); |
|||
const consumer_2 = consumer_1.reset(); |
|||
|
|||
expect(consumer_2.isResetting).toBeTruthy(); |
|||
}); |
|||
}); |
|||
|
|||
describe('EventConsumersService', () => { |
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
imports: [ |
|||
HttpClientTestingModule |
|||
], |
|||
providers: [ |
|||
EventConsumersService, |
|||
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } |
|||
] |
|||
}); |
|||
}); |
|||
|
|||
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { |
|||
httpMock.verify(); |
|||
})); |
|||
|
|||
it('should make get request to get event consumers', |
|||
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { |
|||
|
|||
let eventConsumers: EventConsumerDto[] | null = null; |
|||
|
|||
eventConsumersService.getEventConsumers().subscribe(result => { |
|||
eventConsumers = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/event-consumers'); |
|||
|
|||
expect(req.request.method).toEqual('GET'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush([ |
|||
{ |
|||
name: 'event-consumer1', |
|||
position: '13', |
|||
isStopped: true, |
|||
isResetting: true, |
|||
error: 'an error 1' |
|||
}, |
|||
{ |
|||
name: 'event-consumer2', |
|||
position: '29', |
|||
isStopped: true, |
|||
isResetting: true, |
|||
error: 'an error 2' |
|||
} |
|||
]); |
|||
|
|||
expect(eventConsumers).toEqual([ |
|||
new EventConsumerDto('event-consumer1', true, true, 'an error 1', '13'), |
|||
new EventConsumerDto('event-consumer2', true, true, 'an error 2', '29') |
|||
]); |
|||
})); |
|||
|
|||
it('should make put request to start event consumer', |
|||
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { |
|||
|
|||
eventConsumersService.startEventConsumer('event-consumer1').subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer1/start'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
|
|||
it('should make put request to stop event consumer', |
|||
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { |
|||
|
|||
eventConsumersService.stopEventConsumer('event-consumer1').subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer1/stop'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
|
|||
it('should make put request to reset event consumer', |
|||
inject([EventConsumersService, HttpTestingController], (eventConsumersService: EventConsumersService, httpMock: HttpTestingController) => { |
|||
|
|||
eventConsumersService.resetEventConsumer('event-consumer1').subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/event-consumers/event-consumer1/reset'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
}); |
|||
@ -0,0 +1,88 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import 'framework/angular/http-extensions'; |
|||
|
|||
import { ApiUrlConfig, HTTP } from 'framework'; |
|||
|
|||
export class EventConsumerDto { |
|||
constructor( |
|||
public readonly name: string, |
|||
public readonly isStopped: boolean, |
|||
public readonly isResetting: boolean, |
|||
public readonly error: string, |
|||
public readonly position: string |
|||
) { |
|||
} |
|||
|
|||
public start(): EventConsumerDto { |
|||
return new EventConsumerDto(this.name, false, false, this.error, this.position); |
|||
} |
|||
|
|||
public stop(): EventConsumerDto { |
|||
return new EventConsumerDto(this.name, true, false, this.error, this.position); |
|||
} |
|||
|
|||
public reset(): EventConsumerDto { |
|||
return new EventConsumerDto(this.name, this.isStopped, true, this.error, this.position); |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class EventConsumersService { |
|||
constructor( |
|||
private readonly http: HttpClient, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getEventConsumers(): Observable<EventConsumerDto[]> { |
|||
const url = this.apiUrl.buildUrl('/api/event-consumers'); |
|||
|
|||
return HTTP.getVersioned<any>(this.http, url) |
|||
.map(response => { |
|||
const body = response.payload.body; |
|||
|
|||
const items: any[] = body; |
|||
|
|||
return items.map(item => { |
|||
return new EventConsumerDto( |
|||
item.name, |
|||
item.isStopped, |
|||
item.isResetting, |
|||
item.error, |
|||
item.position); |
|||
}); |
|||
}) |
|||
.pretifyError('Failed to load event consumers. Please reload.'); |
|||
} |
|||
|
|||
public startEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/start`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, {}) |
|||
.pretifyError('Failed to start event consumer. Please reload.'); |
|||
} |
|||
|
|||
public stopEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/stop`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, {}) |
|||
.pretifyError('Failed to stop event consumer. Please reload.'); |
|||
} |
|||
|
|||
public resetEventConsumer(name: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/event-consumers/${name}/reset`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, {}) |
|||
.pretifyError('Failed to reset event consumer. Please reload.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,230 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; |
|||
import { inject, TestBed } from '@angular/core/testing'; |
|||
|
|||
import { ApiUrlConfig } from 'framework'; |
|||
|
|||
import { |
|||
CreateUserDto, |
|||
UpdateUserDto, |
|||
UserDto, |
|||
UsersService, |
|||
UsersDto |
|||
} from './users.service'; |
|||
|
|||
describe('UserDto', () => { |
|||
it('should update email and display name property when unlocking', () => { |
|||
const user_1 = new UserDto('1', 'sebastian@squidex.io', 'Sebastian', 'picture', true); |
|||
const user_2 = user_1.update('qaisar@squidex.io', 'Qaisar'); |
|||
|
|||
expect(user_2.email).toEqual('qaisar@squidex.io'); |
|||
expect(user_2.displayName).toEqual('Qaisar'); |
|||
}); |
|||
|
|||
it('should update isLocked property when locking', () => { |
|||
const user_1 = new UserDto('1', 'sebastian@squidex.io', 'Sebastian', 'picture', false); |
|||
const user_2 = user_1.lock(); |
|||
|
|||
expect(user_2.isLocked).toBeTruthy(); |
|||
}); |
|||
|
|||
it('should update isLocked property when unlocking', () => { |
|||
const user_1 = new UserDto('1', 'sebastian@squidex.io', 'Sebastian', 'picture', true); |
|||
const user_2 = user_1.unlock(); |
|||
|
|||
expect(user_2.isLocked).toBeFalsy(); |
|||
}); |
|||
}); |
|||
|
|||
describe('UsersService', () => { |
|||
beforeEach(() => { |
|||
TestBed.configureTestingModule({ |
|||
imports: [ |
|||
HttpClientTestingModule |
|||
], |
|||
providers: [ |
|||
UsersService, |
|||
{ provide: ApiUrlConfig, useValue: new ApiUrlConfig('http://service/p/') } |
|||
] |
|||
}); |
|||
}); |
|||
|
|||
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => { |
|||
httpMock.verify(); |
|||
})); |
|||
|
|||
it('should make get request to get many users', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
let users: UsersDto | null = null; |
|||
|
|||
userManagementService.getUsers(20, 30).subscribe(result => { |
|||
users = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query='); |
|||
|
|||
expect(req.request.method).toEqual('GET'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({ |
|||
total: 100, |
|||
items: [ |
|||
{ |
|||
id: '123', |
|||
email: 'mail1@domain.com', |
|||
displayName: 'User1', |
|||
pictureUrl: 'path/to/image1', |
|||
isLocked: true |
|||
}, |
|||
{ |
|||
id: '456', |
|||
email: 'mail2@domain.com', |
|||
displayName: 'User2', |
|||
pictureUrl: 'path/to/image2', |
|||
isLocked: true |
|||
} |
|||
] |
|||
}); |
|||
|
|||
expect(users).toEqual( |
|||
new UsersDto(100, [ |
|||
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true), |
|||
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true) |
|||
])); |
|||
})); |
|||
|
|||
it('should make get request with query to get many users', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
let users: UsersDto | null = null; |
|||
|
|||
userManagementService.getUsers(20, 30, 'my-query').subscribe(result => { |
|||
users = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management?take=20&skip=30&query=my-query'); |
|||
|
|||
expect(req.request.method).toEqual('GET'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({ |
|||
total: 100, |
|||
items: [ |
|||
{ |
|||
id: '123', |
|||
email: 'mail1@domain.com', |
|||
displayName: 'User1', |
|||
pictureUrl: 'path/to/image1', |
|||
isLocked: true |
|||
}, |
|||
{ |
|||
id: '456', |
|||
email: 'mail2@domain.com', |
|||
displayName: 'User2', |
|||
pictureUrl: 'path/to/image2', |
|||
isLocked: true |
|||
} |
|||
] |
|||
}); |
|||
|
|||
expect(users).toEqual( |
|||
new UsersDto(100, [ |
|||
new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true), |
|||
new UserDto('456', 'mail2@domain.com', 'User2', 'path/to/image2', true) |
|||
])); |
|||
})); |
|||
|
|||
it('should make get request to get single user', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
let user: UserDto | null = null; |
|||
|
|||
userManagementService.getUser('123').subscribe(result => { |
|||
user = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management/123'); |
|||
|
|||
expect(req.request.method).toEqual('GET'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({ |
|||
id: '123', |
|||
email: 'mail1@domain.com', |
|||
displayName: 'User1', |
|||
pictureUrl: 'path/to/image1', |
|||
isLocked: true |
|||
}); |
|||
|
|||
expect(user).toEqual(new UserDto('123', 'mail1@domain.com', 'User1', 'path/to/image1', true)); |
|||
})); |
|||
|
|||
it('should make post request to create user', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
const dto = new CreateUserDto('mail@squidex.io', 'Squidex User', 'password'); |
|||
|
|||
let user: UserDto | null = null; |
|||
|
|||
userManagementService.postUser(dto).subscribe(result => { |
|||
user = result; |
|||
}); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management'); |
|||
|
|||
expect(req.request.method).toEqual('POST'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({ id: '123', pictureUrl: 'path/to/image1' }); |
|||
|
|||
expect(user).toEqual(new UserDto('123', dto.email, dto.displayName, 'path/to/image1', false)); |
|||
})); |
|||
|
|||
it('should make put request to update user', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
const dto = new UpdateUserDto('mail@squidex.io', 'Squidex User', 'password'); |
|||
|
|||
userManagementService.putUser('123', dto).subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management/123'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
|
|||
it('should make put request to lock user', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
userManagementService.lockUser('123').subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management/123/lock'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
|
|||
it('should make put request to unlock user', |
|||
inject([UsersService, HttpTestingController], (userManagementService: UsersService, httpMock: HttpTestingController) => { |
|||
|
|||
userManagementService.unlockUser('123').subscribe(); |
|||
|
|||
const req = httpMock.expectOne('http://service/p/api/user-management/123/unlock'); |
|||
|
|||
expect(req.request.method).toEqual('PUT'); |
|||
expect(req.request.headers.get('If-Match')).toBeNull(); |
|||
|
|||
req.flush({}); |
|||
})); |
|||
}); |
|||
@ -0,0 +1,145 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { HttpClient } from '@angular/common/http'; |
|||
import { Injectable } from '@angular/core'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import 'framework/angular/http-extensions'; |
|||
|
|||
import { ApiUrlConfig, HTTP } from 'framework'; |
|||
|
|||
export class UsersDto { |
|||
constructor( |
|||
public readonly total: number, |
|||
public readonly items: UserDto[] |
|||
) { |
|||
} |
|||
} |
|||
|
|||
export class UserDto { |
|||
constructor( |
|||
public readonly id: string, |
|||
public readonly email: string, |
|||
public readonly displayName: string, |
|||
public readonly pictureUrl: string | null, |
|||
public readonly isLocked: boolean |
|||
) { |
|||
} |
|||
|
|||
public update(email: string, displayName: string): UserDto { |
|||
return new UserDto(this.id, email, displayName, this.pictureUrl, this.isLocked); |
|||
} |
|||
|
|||
public lock(): UserDto { |
|||
return new UserDto(this.id, this.email, this.displayName, this.pictureUrl, true); |
|||
} |
|||
|
|||
public unlock(): UserDto { |
|||
return new UserDto(this.id, this.email, this.displayName, this.pictureUrl, false); |
|||
} |
|||
} |
|||
|
|||
export class CreateUserDto { |
|||
constructor( |
|||
public readonly email: string, |
|||
public readonly displayName: string, |
|||
public readonly password: string |
|||
) { |
|||
} |
|||
} |
|||
|
|||
export class UpdateUserDto { |
|||
constructor( |
|||
public readonly email: string, |
|||
public readonly displayName: string, |
|||
public readonly password: string |
|||
) { |
|||
} |
|||
} |
|||
|
|||
@Injectable() |
|||
export class UsersService { |
|||
constructor( |
|||
private readonly http: HttpClient, |
|||
private readonly apiUrl: ApiUrlConfig |
|||
) { |
|||
} |
|||
|
|||
public getUsers(take: number, skip: number, query?: string): Observable<UsersDto> { |
|||
const url = this.apiUrl.buildUrl(`api/user-management?take=${take}&skip=${skip}&query=${query || ''}`); |
|||
|
|||
return HTTP.getVersioned<any>(this.http, url) |
|||
.map(response => { |
|||
const body = response.payload.body; |
|||
|
|||
const items: any[] = body.items; |
|||
|
|||
const users = items.map(item => { |
|||
return new UserDto( |
|||
item.id, |
|||
item.email, |
|||
item.displayName, |
|||
item.pictureUrl, |
|||
item.isLocked); |
|||
}); |
|||
|
|||
return new UsersDto(body.total, users); |
|||
}) |
|||
.pretifyError('Failed to load users. Please reload.'); |
|||
} |
|||
|
|||
public getUser(id: string): Observable<UserDto> { |
|||
const url = this.apiUrl.buildUrl(`api/user-management/${id}`); |
|||
|
|||
return HTTP.getVersioned<any>(this.http, url) |
|||
.map(response => { |
|||
const body = response.payload.body; |
|||
|
|||
return new UserDto( |
|||
body.id, |
|||
body.email, |
|||
body.displayName, |
|||
body.pictureUrl, |
|||
body.isLocked); |
|||
}) |
|||
.pretifyError('Failed to load user. Please reload.'); |
|||
} |
|||
|
|||
public postUser(dto: CreateUserDto): Observable<UserDto> { |
|||
const url = this.apiUrl.buildUrl('api/user-management'); |
|||
|
|||
return HTTP.postVersioned<any>(this.http, url, dto) |
|||
.map(response => { |
|||
const body = response.payload.body; |
|||
|
|||
return new UserDto(body.id, dto.email, dto.displayName, body.pictureUrl, false); |
|||
}) |
|||
.pretifyError('Failed to create user. Please reload.'); |
|||
} |
|||
|
|||
public putUser(id: string, dto: UpdateUserDto): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/user-management/${id}`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, dto) |
|||
.pretifyError('Failed to update user. Please reload.'); |
|||
} |
|||
|
|||
public lockUser(id: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/user-management/${id}/lock`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, {}) |
|||
.pretifyError('Failed to load users. Please retry.'); |
|||
} |
|||
|
|||
public unlockUser(id: string): Observable<any> { |
|||
const url = this.apiUrl.buildUrl(`api/user-management/${id}/unlock`); |
|||
|
|||
return HTTP.putVersioned(this.http, url, {}) |
|||
.pretifyError('Failed to load users. Please retry.'); |
|||
} |
|||
} |
|||
@ -0,0 +1,138 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { Injectable } from '@angular/core'; |
|||
import { BehaviorSubject, Observable } from 'rxjs'; |
|||
|
|||
import 'framework/utils/rxjs-extensions'; |
|||
|
|||
import { |
|||
DialogService, |
|||
ErrorDto, |
|||
ImmutableArray, |
|||
Notification, |
|||
Pager |
|||
} from 'shared'; |
|||
|
|||
import { |
|||
CreateUserDto, |
|||
UserDto, |
|||
UsersService |
|||
} from './../services/users.service'; |
|||
|
|||
@Injectable() |
|||
export class UsersState { |
|||
public usersItems = new BehaviorSubject<ImmutableArray<UserDto>>(ImmutableArray.empty()); |
|||
public usersPager = new BehaviorSubject(new Pager(0)); |
|||
public usersQuery = new BehaviorSubject(''); |
|||
|
|||
public selectedUser = new BehaviorSubject<UserDto | null>(null); |
|||
|
|||
constructor( |
|||
private readonly usersService: UsersService, |
|||
private readonly dialogs: DialogService |
|||
) { |
|||
} |
|||
|
|||
public selectUser(id: string | null): Observable<boolean> { |
|||
const observable = |
|||
!id ? |
|||
Observable.of(null) : |
|||
Observable.of(this.usersItems.value.find(x => x.id === id)) |
|||
.switchMap(user => { |
|||
if (!user) { |
|||
return this.usersService.getUser(id).catch(() => Observable.of(null)); |
|||
} else { |
|||
return Observable.of(user); |
|||
} |
|||
}); |
|||
|
|||
return observable |
|||
.do(user => { |
|||
this.selectedUser.next(user); |
|||
}) |
|||
.map(u => u !== null); |
|||
} |
|||
|
|||
public loadUsers(): Observable<any> { |
|||
return this.usersService.getUsers(this.usersPager.value.pageSize, this.usersPager.value.skip, this.usersQuery.value) |
|||
.catch(error => this.notifyError(error)) |
|||
.do(dtos => { |
|||
this.usersItems.nextBy(v => ImmutableArray.of(dtos.items)); |
|||
this.usersPager.nextBy(v => v.setCount(dtos.total)); |
|||
}); |
|||
} |
|||
|
|||
public updateUser(request: CreateUserDto): Observable<any> { |
|||
const id = this.selectedUser.value!.id; |
|||
|
|||
return this.usersService.putUser(id, request) |
|||
.do(() => { |
|||
this.dialogs.notify(Notification.info('User saved successsfull')); |
|||
|
|||
this.usersItems.nextBy(v => v.replaceAll(x => x.id === id, u => u.update(request.email, request.displayName))); |
|||
}); |
|||
} |
|||
|
|||
public createUser(request: CreateUserDto): Observable<UserDto> { |
|||
return this.usersService.postUser(request) |
|||
.catch(error => this.notifyError(error)) |
|||
.do(user => { |
|||
this.usersItems.nextBy(v => v.pushFront(user)); |
|||
this.usersPager.nextBy(v => v.incrementCount()); |
|||
}); |
|||
} |
|||
|
|||
public lockUser(id: string): Observable<any> { |
|||
return this.usersService.lockUser(id) |
|||
.catch(error => this.notifyError(error)) |
|||
.do(() => { |
|||
this.usersItems.nextBy(v => v.replaceAll(x => x.id === id, u => u.lock())); |
|||
}); |
|||
} |
|||
|
|||
public unlockUser(id: string): Observable<any> { |
|||
return this.usersService.lockUser(id) |
|||
.catch(error => this.notifyError(error)) |
|||
.do(() => { |
|||
this.usersItems.nextBy(v => v.replaceAll(x => x.id === id, u => u.unlock())); |
|||
}); |
|||
} |
|||
|
|||
public search(filter: string) { |
|||
this.usersPager.nextBy(v => new Pager(0)); |
|||
this.usersQuery.nextBy(v => filter); |
|||
|
|||
this.loadUsers(); |
|||
} |
|||
|
|||
public goNext() { |
|||
this.usersPager.nextBy(v => v.goNext()); |
|||
|
|||
this.loadUsers(); |
|||
} |
|||
|
|||
public goPrev() { |
|||
this.usersPager.nextBy(v => v.goPrev()); |
|||
|
|||
this.loadUsers(); |
|||
} |
|||
|
|||
public trackBy(index: number, user: UserDto): any { |
|||
return user.id; |
|||
} |
|||
|
|||
private notifyError(error: string | ErrorDto) { |
|||
if (error instanceof ErrorDto) { |
|||
this.dialogs.notify(Notification.error(error.displayMessage)); |
|||
} else { |
|||
this.dialogs.notify(Notification.error(error)); |
|||
} |
|||
|
|||
return Observable.throw(error); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
export function nextBy<T>(updater: (value: T) => T): void { |
|||
return this.next(updater(this.value)); |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; |
|||
|
|||
import { nextBy } from './rxjs-extensions-impl'; |
|||
|
|||
/* tslint:disable:no-shadowed-variable */ |
|||
|
|||
declare module 'rxjs/BehaviorSubject' { |
|||
interface BehaviorSubject<T> { |
|||
nextBy(updater: (value: T) => T): void; |
|||
} |
|||
} |
|||
|
|||
BehaviorSubject.prototype['nextBy'] = nextBy; |
|||
Loading…
Reference in new issue