Browse Source

Guards fixed

pull/271/head
Sebastian Stehle 8 years ago
parent
commit
64d60a2be9
  1. 22
      src/Squidex/app/features/administration/guards/user-must-exist.guard.spec.ts
  2. 52
      src/Squidex/app/shared/guards/app-must-exist.guard.spec.ts
  3. 10
      src/Squidex/app/shared/guards/app-must-exist.guard.ts
  4. 38
      src/Squidex/app/shared/guards/load-apps.guard.spec.ts
  5. 4
      src/Squidex/app/shared/guards/load-apps.guard.ts
  6. 44
      src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts
  7. 4
      src/Squidex/app/shared/guards/must-be-authenticated.guard.ts
  8. 46
      src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts
  9. 4
      src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts
  10. 90
      src/Squidex/app/shared/guards/resolve-app-languages.guard.spec.ts
  11. 12
      src/Squidex/app/shared/guards/resolve-app-languages.guard.ts
  12. 105
      src/Squidex/app/shared/guards/resolve-content.guard.spec.ts
  13. 16
      src/Squidex/app/shared/guards/resolve-content.guard.ts
  14. 100
      src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts
  15. 26
      src/Squidex/app/shared/guards/resolve-published-schema.guard.ts
  16. 83
      src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts
  17. 17
      src/Squidex/app/shared/guards/resolve-schema.guard.ts
  18. 14
      src/Squidex/app/shared/guards/router-mockup.ts
  19. 13
      src/Squidex/app/shared/guards/unset-app.guard.spec.ts
  20. 4
      src/Squidex/app/shared/guards/unset-app.guard.ts
  21. 28
      src/Squidex/app/shared/interceptors/auth.interceptor.spec.ts
  22. 4
      src/Squidex/app/shared/services/users-provider.service.spec.ts
  23. 2
      src/Squidex/app/shared/state/apps.state.spec.ts

22
src/Squidex/app/features/administration/guards/user-must-exist.guard.spec.ts

@ -14,6 +14,12 @@ import { UsersState } from './../state/users.state';
import { UserMustExistGuard } from './user-must-exist.guard'; import { UserMustExistGuard } from './user-must-exist.guard';
describe('UserMustExistGuard', () => { describe('UserMustExistGuard', () => {
const route: any = {
params: {
userId: '123'
}
};
let usersState: IMock<UsersState>; let usersState: IMock<UsersState>;
let router: IMock<Router>; let router: IMock<Router>;
let userGuard: UserMustExistGuard; let userGuard: UserMustExistGuard;
@ -30,14 +36,6 @@ describe('UserMustExistGuard', () => {
let result: boolean; let result: boolean;
const route: any = {
snapshot: {
params: {
userId: '123'
}
}
};
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
result = x; result = x;
}).unsubscribe(); }).unsubscribe();
@ -53,14 +51,6 @@ describe('UserMustExistGuard', () => {
let result: boolean; let result: boolean;
const route: any = {
snapshot: {
params: {
userId: '123'
}
}
};
userGuard.canActivate(route).subscribe(x => { userGuard.canActivate(route).subscribe(x => {
result = x; result = x;
}).unsubscribe(); }).unsubscribe();

52
src/Squidex/app/shared/guards/app-must-exist.guard.spec.ts

@ -5,54 +5,60 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { IMock, Mock } from 'typemoq'; import { Router } from '@angular/router';
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AppsState } from '@app/shared'; import { AppsState } from '@app/shared';
import { AppMustExistGuard } from './app-must-exist.guard'; import { AppMustExistGuard } from './app-must-exist.guard';
import { RouterMockup } from './router-mockup';
describe('AppMustExistGuard', () => { describe('AppMustExistGuard', () => {
const route: any = {
params: {
appName: 'my-app'
}
};
let router: IMock<Router>;
let appsState: IMock<AppsState>; let appsState: IMock<AppsState>;
let appGuard: AppMustExistGuard;
beforeEach(() => { beforeEach(() => {
appsState = Mock.ofType(AppsState); router = Mock.ofType<Router>();
appsState = Mock.ofType<AppsState>();
appGuard = new AppMustExistGuard(appsState.object, router.object);
}); });
it('should navigate to 404 page if app is not found', (done) => { it('should navigate to 404 page if app is not found', () => {
appsState.setup(x => x.selectApp('my-app')) appsState.setup(x => x.selectApp('my-app'))
.returns(() => Observable.of(null)); .returns(() => Observable.of(null));
const router = new RouterMockup(); let result: boolean;
const route = <any> { params: { appName: 'my-app' } };
const guard = new AppMustExistGuard(appsState.object, <any>router); appGuard.canActivate(route).subscribe(x => {
result = x;
});
guard.canActivate(route, <any>{}) expect(result!).toBeFalsy();
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']);
done(); appsState.verify(x => x.selectApp('my-app'), Times.once());
});
}); });
it('should return true if app is found', (done) => { it('should return true if app is found', () => {
appsState.setup(x => x.selectApp('my-app')) appsState.setup(x => x.selectApp('my-app'))
.returns(() => Observable.of(<any>{})); .returns(() => Observable.of(<any>{}));
const router = new RouterMockup(); let result: boolean;
const route = <any> { params: { appName: 'my-app' } };
const guard = new AppMustExistGuard(appsState.object, <any>router); appGuard.canActivate(route).subscribe(x => {
result = x;
});
guard.canActivate(route, <any>{}) expect(result!).toBeTruthy();
.subscribe(result => {
expect(result).toBeTruthy();
expect(router.lastNavigation).toBeUndefined();
done(); // router.verify(x => x.navigate(['/404']), Times.once());
});
}); });
}); });

10
src/Squidex/app/shared/guards/app-must-exist.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AppsState } from './../state/apps.state'; import { AppsState } from './../state/apps.state';
@ -14,21 +14,21 @@ import { AppsState } from './../state/apps.state';
@Injectable() @Injectable()
export class AppMustExistGuard implements CanActivate { export class AppMustExistGuard implements CanActivate {
constructor( constructor(
private readonly appsStore: AppsState, private readonly appsState: AppsState,
private readonly router: Router private readonly router: Router
) { ) {
} }
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { public canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
const appName = route.params['appName']; const appName = route.params['appName'];
const result = const result =
this.appsStore.selectApp(appName) this.appsState.selectApp(appName)
.do(dto => { .do(dto => {
if (!dto) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
} }
}).map(a => a !== null); }).map(a => !!a);
return result; return result;
} }

38
src/Squidex/app/shared/guards/load-apps.guard.spec.ts

@ -0,0 +1,38 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs';
import { AppsState } from '@app/shared';
import { LoadAppsGuard } from './load-apps.guard';
describe('LoadAppsGuard', () => {
let appsState: IMock<AppsState>;
let appGuard: LoadAppsGuard;
beforeEach(() => {
appsState = Mock.ofType<AppsState>();
appGuard = new LoadAppsGuard(appsState.object);
});
it('should load apps', () => {
appsState.setup(x => x.loadApps())
.returns(() => Observable.of(null));
let result = false;
appGuard.canActivate().subscribe(value => {
result = value;
});
expect(result).toBeTruthy();
appsState.verify(x => x.loadApps(), Times.once());
});
});

4
src/Squidex/app/shared/guards/load-apps.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AppsState } from './../state/apps.state'; import { AppsState } from './../state/apps.state';
@ -18,7 +18,7 @@ export class LoadAppsGuard implements CanActivate {
) { ) {
} }
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { public canActivate(): Observable<boolean> {
return this.appsState.loadApps().map(a => true); return this.appsState.loadApps().map(a => true);
} }
} }

44
src/Squidex/app/shared/guards/must-be-authenticated.guard.spec.ts

@ -5,50 +5,52 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { IMock, Mock } from 'typemoq'; import { Router } from '@angular/router';
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AuthService } from '@app/shared'; import { AuthService } from '@app/shared';
import { MustBeAuthenticatedGuard } from './must-be-authenticated.guard'; import { MustBeAuthenticatedGuard } from './must-be-authenticated.guard';
import { RouterMockup } from './router-mockup';
describe('MustBeAuthenticatedGuard', () => { describe('MustBeAuthenticatedGuard', () => {
let router: IMock<Router>;
let authService: IMock<AuthService>; let authService: IMock<AuthService>;
let authGuard: MustBeAuthenticatedGuard;
beforeEach(() => { beforeEach(() => {
authService = Mock.ofType(AuthService); router = Mock.ofType<Router>();
authService = Mock.ofType<AuthService>();
authGuard = new MustBeAuthenticatedGuard(authService.object, router.object);
}); });
it('should navigate to default page if not authenticated', (done) => { it('should navigate to default page if not authenticated', () => {
authService.setup(x => x.userChanges) authService.setup(x => x.userChanges)
.returns(() => Observable.of(null)); .returns(() => Observable.of(null));
const router = new RouterMockup();
const guard = new MustBeAuthenticatedGuard(authService.object, <any>router); let result: boolean;
authGuard.canActivate().subscribe(x => {
result = x;
});
guard.canActivate(<any>{}, <any>{}) expect(result!).toBeFalsy();
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['']);
done(); router.verify(x => x.navigate(['']), Times.once());
});
}); });
it('should return true if authenticated', (done) => { it('should return true if authenticated', () => {
authService.setup(x => x.userChanges) authService.setup(x => x.userChanges)
.returns(() => Observable.of(<any>{})); .returns(() => Observable.of(<any>{}));
const router = new RouterMockup();
const guard = new MustBeAuthenticatedGuard(authService.object, <any>router); let result: boolean;
guard.canActivate(<any>{}, <any>{}) authGuard.canActivate().subscribe(x => {
.subscribe(result => { result = x;
expect(result).toBeTruthy(); });
expect(router.lastNavigation).toBeUndefined();
done(); expect(result!).toBeTruthy();
});
}); });
}); });

4
src/Squidex/app/shared/guards/must-be-authenticated.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AuthService } from './../services/auth.service'; import { AuthService } from './../services/auth.service';
@ -19,7 +19,7 @@ export class MustBeAuthenticatedGuard implements CanActivate {
) { ) {
} }
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { public canActivate(): Observable<boolean> {
return this.authService.userChanges.take(1) return this.authService.userChanges.take(1)
.do(user => { .do(user => {
if (!user) { if (!user) {

46
src/Squidex/app/shared/guards/must-be-not-authenticated.guard.spec.ts

@ -5,50 +5,52 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { IMock, Mock } from 'typemoq'; import { Router } from '@angular/router';
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AuthService } from '@app/shared'; import { AuthService } from '@app/shared';
import { MustBeNotAuthenticatedGuard } from './must-be-not-authenticated.guard'; import { MustBeNotAuthenticatedGuard } from './must-be-not-authenticated.guard';
import { RouterMockup } from './router-mockup';
describe('MustBeNotAuthenticatedGuard', () => { describe('MustNotBeAuthenticatedGuard', () => {
let router: IMock<Router>;
let authService: IMock<AuthService>; let authService: IMock<AuthService>;
let authGuard: MustBeNotAuthenticatedGuard;
beforeEach(() => { beforeEach(() => {
authService = Mock.ofType(AuthService); router = Mock.ofType<Router>();
authService = Mock.ofType<AuthService>();
authGuard = new MustBeNotAuthenticatedGuard(authService.object, router.object);
}); });
it('should navigate to app page if authenticated', (done) => { it('should navigate to app page if authenticated', () => {
authService.setup(x => x.userChanges) authService.setup(x => x.userChanges)
.returns(() => Observable.of(<any>{})); .returns(() => Observable.of(<any>{}));
const router = new RouterMockup();
const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router); let result: boolean;
authGuard.canActivate().subscribe(x => {
result = x;
});
guard.canActivate(<any>{}, <any>{}) expect(result!).toBeFalsy();
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['app']);
done(); router.verify(x => x.navigate(['app']), Times.once());
});
}); });
it('should return true if not authenticated', (done) => { it('should return true if not authenticated', () => {
authService.setup(x => x.userChanges) authService.setup(x => x.userChanges)
.returns(() => Observable.of(null)); .returns(() => Observable.of(null));
const router = new RouterMockup();
const guard = new MustBeNotAuthenticatedGuard(authService.object, <any>router); let result: boolean;
guard.canActivate(<any>{}, <any>{}) authGuard.canActivate().subscribe(x => {
.subscribe(result => { result = x;
expect(result).toBeTruthy(); });
expect(router.lastNavigation).toBeUndefined();
done(); expect(result!).toBeTruthy();
});
}); });
}); });

4
src/Squidex/app/shared/guards/must-be-not-authenticated.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AuthService } from './../services/auth.service'; import { AuthService } from './../services/auth.service';
@ -19,7 +19,7 @@ export class MustBeNotAuthenticatedGuard implements CanActivate {
) { ) {
} }
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { public canActivate(): Observable<boolean> {
return this.authService.userChanges.take(1) return this.authService.userChanges.take(1)
.do(user => { .do(user => {
if (user) { if (user) {

90
src/Squidex/app/shared/guards/resolve-app-languages.guard.spec.ts

@ -1,90 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { IMock, Mock } from 'typemoq';
import { Observable } from 'rxjs';
import {
AppLanguagesDto,
AppLanguagesService,
Version
} from '@app/shared';
import { ResolveAppLanguagesGuard } from './resolve-app-languages.guard';
import { RouterMockup } from './router-mockup';
describe('ResolveAppLanguagesGuard', () => {
const route = {
params: { },
parent: {
params: {
appName: 'my-app'
}
}
};
let appLanguagesService: IMock<AppLanguagesService>;
beforeEach(() => {
appLanguagesService = Mock.ofType(AppLanguagesService);
});
it('should throw if route does not contain parameter', () => {
const guard = new ResolveAppLanguagesGuard(appLanguagesService.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app name.');
});
it('should navigate to 404 page if languages are not found', (done) => {
appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.of(null!));
const router = new RouterMockup();
const guard = new ResolveAppLanguagesGuard(appLanguagesService.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 languages loading fails', (done) => {
appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.throw(null!));
const router = new RouterMockup();
const guard = new ResolveAppLanguagesGuard(appLanguagesService.object, <any>router);
guard.resolve(<any>route, <any>{})
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']);
done();
});
});
it('should return languages if loading succeeded', (done) => {
const languages = new AppLanguagesDto([], new Version('2'));
appLanguagesService.setup(x => x.getLanguages('my-app'))
.returns(() => Observable.of(languages));
const router = new RouterMockup();
const guard = new ResolveAppLanguagesGuard(appLanguagesService.object, <any>router);
guard.resolve(<any>route, <any>{})
.subscribe(result => {
expect(result).toBe(languages.languages);
done();
});
});
});

12
src/Squidex/app/shared/guards/resolve-app-languages.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { allParams } from '@app/framework'; import { allParams } from '@app/framework';
@ -21,14 +21,8 @@ export class ResolveAppLanguagesGuard implements Resolve<AppLanguageDto[] | null
) { ) {
} }
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<AppLanguageDto[] | null> { public resolve(route: ActivatedRouteSnapshot): Observable<AppLanguageDto[] | null> {
const params = allParams(route); const appName = allParams(route)['appName'];
const appName = params['appName'];
if (!appName) {
throw 'Route must contain app name.';
}
const result = const result =
this.appLanguagesService.getLanguages(appName).map(d => d.languages) this.appLanguagesService.getLanguages(appName).map(d => d.languages)

105
src/Squidex/app/shared/guards/resolve-content.guard.spec.ts

@ -1,105 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { IMock, Mock } from 'typemoq';
import { Observable } from 'rxjs';
import { ContentsService } from '@app/shared';
import { ResolveContentGuard } from './resolve-content.guard';
import { RouterMockup } from './router-mockup';
describe('ResolveContentGuard', () => {
const route = {
params: {
appName: 'my-app'
},
parent: {
params: {
schemaName: 'my-schema'
},
parent: {
params: {
contentId: '123'
}
}
}
};
let appsStore: IMock<ContentsService>;
beforeEach(() => {
appsStore = Mock.ofType(ContentsService);
});
it('should throw if route does not contain app name', () => {
const guard = new ResolveContentGuard(appsStore.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app name.');
});
it('should throw if route does not contain schema name', () => {
const guard = new ResolveContentGuard(appsStore.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: { appName: 'my-app' } }, <any>{})).toThrow('Route must contain schema name.');
});
it('should throw if route does not contain content id', () => {
const guard = new ResolveContentGuard(appsStore.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: { appName: 'my-app', schemaName: 'my-schema' } }, <any>{})).toThrow('Route must contain content id.');
});
it('should navigate to 404 page if schema is not found', (done) => {
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.of(null!));
const router = new RouterMockup();
const guard = new ResolveContentGuard(appsStore.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 schema loading fails', (done) => {
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.throw(null!));
const router = new RouterMockup();
const guard = new ResolveContentGuard(appsStore.object, <any>router);
guard.resolve(<any>route, <any>{})
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']);
done();
});
});
it('should return content if loading succeeded', (done) => {
const content: any = {};
appsStore.setup(x => x.getContent('my-app', 'my-schema', '123'))
.returns(() => Observable.of(content));
const router = new RouterMockup();
const guard = new ResolveContentGuard(appsStore.object, <any>router);
guard.resolve(<any>route, <any>{})
.subscribe(result => {
expect(result).toBe(content);
done();
});
});
});

16
src/Squidex/app/shared/guards/resolve-content.guard.ts

@ -25,22 +25,8 @@ export class ResolveContentGuard implements Resolve<ContentDto | null> {
const params = allParams(route); const params = allParams(route);
const appName = params['appName']; const appName = params['appName'];
if (!appName) {
throw 'Route must contain app name.';
}
const schemaName = params['schemaName'];
if (!schemaName) {
throw 'Route must contain schema name.';
}
const contentId = params['contentId']; const contentId = params['contentId'];
const schemaName = params['schemaName'];
if (!contentId) {
throw 'Route must contain content id.';
}
const result = const result =
this.contentsService.getContent(appName, schemaName, contentId) this.contentsService.getContent(appName, schemaName, contentId)

100
src/Squidex/app/shared/guards/resolve-published-schema.guard.spec.ts

@ -5,16 +5,16 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { IMock, Mock } from 'typemoq'; import { Router } from '@angular/router';
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { SchemasService } from '@app/shared'; import { SchemasService, SchemaDetailsDto } from '@app/shared';
import { ResolvePublishedSchemaGuard } from './resolve-published-schema.guard'; import { ResolvePublishedSchemaGuard } from './resolve-published-schema.guard';
import { RouterMockup } from './router-mockup';
describe('ResolvePublishedSchemaGuard', () => { describe('ResolvePublishedSchemaGuard', () => {
const route = { const route: any = {
params: { params: {
appName: 'my-app' appName: 'my-app'
}, },
@ -25,88 +25,78 @@ describe('ResolvePublishedSchemaGuard', () => {
} }
}; };
let router: IMock<Router>;
let schemasService: IMock<SchemasService>; let schemasService: IMock<SchemasService>;
let schemaGuard: ResolvePublishedSchemaGuard;
beforeEach(() => { beforeEach(() => {
schemasService = Mock.ofType(SchemasService); router = Mock.ofType<Router>();
});
it('should throw if route does not contain app name', () => {
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app name.'); schemasService = Mock.ofType<SchemasService>();
schemaGuard = new ResolvePublishedSchemaGuard(schemasService.object, router.object);
}); });
it('should throw if route does not contain schema name', () => { it('should return schema if loading succeeded', () => {
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>new RouterMockup()); const schema: any = { isPublished: true };
expect(() => guard.resolve(<any>{ params: { appName: 'my-app' } }, <any>{})).toThrow('Route must contain schema name.');
});
it('should navigate to 404 page if schema is not found', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(schema));
const router = new RouterMockup();
let result: SchemaDetailsDto;
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>router); schemaGuard.resolve(route).subscribe(x => {
result = x!;
});
guard.resolve(<any>route, <any>{}) expect(result!).toBe(schema);
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']);
done(); schemasService.verify(x => x.getSchema('my-app', 'my-schema'), Times.once());
});
}); });
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema is not found', () => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.throw(null)); .returns(() => Observable.of(null!));
const router = new RouterMockup();
let result: SchemaDetailsDto;
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>router); schemaGuard.resolve(route).subscribe(x => {
result = x!!;
});
guard.resolve(<any>route, <any>{}) expect(result!).toBeNull();
.subscribe(result => {
expect(result).toBeFalsy();
expect(router.lastNavigation).toEqual(['/404']);
done(); router.verify(x => x.navigate(['/404']), Times.once());
});
}); });
it('should navigate to 404 page if schema not published', (done) => { it('should navigate to 404 page if schema is not published', () => {
const schema: any = { isPublished: false }; const schema: any = { isPublished: false };
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.of(schema));
const router = new RouterMockup();
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>router); let result: SchemaDetailsDto;
guard.resolve(<any>route, <any>{}) schemaGuard.resolve(route).subscribe(x => {
.subscribe(result => { result = x!;
expect(result).toBe(schema); });
expect(router.lastNavigation).toEqual(['/404']);
done(); expect(result!).toBeNull();
});
});
it('should return schema if loading succeeded', (done) => { router.verify(x => x.navigate(['/404']), Times.once());
const schema: any = { isPublished: true }; });
it('should navigate to 404 page if schema loading fails', () => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.throw({}));
const router = new RouterMockup();
let result: SchemaDetailsDto;
const guard = new ResolvePublishedSchemaGuard(schemasService.object, <any>router); schemaGuard.resolve(route).subscribe(x => {
result = x!;
});
guard.resolve(<any>route, <any>{}) expect(result!).toBeNull();
.subscribe(result => {
expect(result).toBe(schema);
done(); router.verify(x => x.navigate(['/404']), Times.once());
});
}); });
}); });

26
src/Squidex/app/shared/guards/resolve-published-schema.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { allParams } from '@app/framework'; import { allParams } from '@app/framework';
@ -14,39 +14,37 @@ import { allParams } from '@app/framework';
import { SchemaDetailsDto, SchemasService } from './../services/schemas.service'; import { SchemaDetailsDto, SchemasService } from './../services/schemas.service';
@Injectable() @Injectable()
export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto> { export class ResolvePublishedSchemaGuard implements Resolve<SchemaDetailsDto | null> {
constructor( constructor(
private readonly schemasService: SchemasService, private readonly schemasService: SchemasService,
private readonly router: Router private readonly router: Router
) { ) {
} }
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<SchemaDetailsDto> { public resolve(route: ActivatedRouteSnapshot): Observable<SchemaDetailsDto | null> {
const params = allParams(route); const params = allParams(route);
const appName = params['appName']; const appName = params['appName'];
if (!appName) {
throw 'Route must contain app name.';
}
const schemaName = params['schemaName']; const schemaName = params['schemaName'];
if (!schemaName) {
throw 'Route must contain schema name.';
}
const result = const result =
this.schemasService.getSchema(appName, schemaName) this.schemasService.getSchema(appName, schemaName)
.map(dto => {
if (dto && !dto.isPublished) {
return null;
}
return dto;
})
.do(dto => { .do(dto => {
if (!dto || !dto.isPublished) { if (!dto) {
this.router.navigate(['/404']); this.router.navigate(['/404']);
} }
}) })
.catch(error => { .catch(error => {
this.router.navigate(['/404']); this.router.navigate(['/404']);
return Observable.of(error); return Observable.of(null);
}); });
return result; return result;

83
src/Squidex/app/shared/guards/resolve-schema.guard.spec.ts

@ -5,16 +5,16 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { IMock, Mock } from 'typemoq'; import { Router } from '@angular/router';
import { IMock, Mock, Times } from 'typemoq';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { SchemasService } from '@app/shared'; import { SchemasService, SchemaDetailsDto } from '@app/shared';
import { ResolveSchemaGuard } from './resolve-schema.guard'; import { ResolveSchemaGuard } from './resolve-schema.guard';
import { RouterMockup } from './router-mockup';
describe('ResolveSchemaGuard', () => { describe('ResolveSchemaGuard', () => {
const route = { const route: any = {
params: { params: {
appName: 'my-app' appName: 'my-app'
}, },
@ -25,70 +25,61 @@ describe('ResolveSchemaGuard', () => {
} }
}; };
let router: IMock<Router>;
let schemasService: IMock<SchemasService>; let schemasService: IMock<SchemasService>;
let schemaGuard: ResolveSchemaGuard;
beforeEach(() => { beforeEach(() => {
schemasService = Mock.ofType(SchemasService); router = Mock.ofType<Router>();
});
it('should throw if route does not contain app name', () => {
const guard = new ResolveSchemaGuard(schemasService.object, <any>new RouterMockup());
expect(() => guard.resolve(<any>{ params: {} }, <any>{})).toThrow('Route must contain app name.'); schemasService = Mock.ofType<SchemasService>();
schemaGuard = new ResolveSchemaGuard(schemasService.object, router.object);
}); });
it('should throw if route does not contain schema name', () => { it('should return schema if loading succeeded', () => {
const guard = new ResolveSchemaGuard(schemasService.object, <any>new RouterMockup()); const schema: any = {};
expect(() => guard.resolve(<any>{ params: { appName: 'my-app' } }, <any>{})).toThrow('Route must contain schema name.');
});
it('should navigate to 404 page if schema is not found', (done) => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(null!)); .returns(() => Observable.of(schema));
const router = new RouterMockup();
const guard = new ResolveSchemaGuard(schemasService.object, <any>router); let result: SchemaDetailsDto;
guard.resolve(<any>route, <any>{}) schemaGuard.resolve(route).subscribe(x => {
.subscribe(result => { result = x!;
expect(result).toBeFalsy(); });
expect(router.lastNavigation).toEqual(['/404']);
done(); expect(result!).toBe(schema);
});
schemasService.verify(x => x.getSchema('my-app', 'my-schema'), Times.once());
}); });
it('should navigate to 404 page if schema loading fails', (done) => { it('should navigate to 404 page if schema is not found', () => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.throw(null!)); .returns(() => Observable.of(null!));
const router = new RouterMockup();
const guard = new ResolveSchemaGuard(schemasService.object, <any>router); let result: SchemaDetailsDto;
guard.resolve(<any>route, <any>{}) schemaGuard.resolve(route).subscribe(x => {
.subscribe(result => { result = x!;
expect(result).toBeFalsy(); });
expect(router.lastNavigation).toEqual(['/404']);
done(); expect(result!).toBeNull();
});
});
it('should return schema if loading succeeded', (done) => { router.verify(x => x.navigate(['/404']), Times.once());
const schema: any = {}; });
it('should navigate to 404 page if schema loading fails', () => {
schemasService.setup(x => x.getSchema('my-app', 'my-schema')) schemasService.setup(x => x.getSchema('my-app', 'my-schema'))
.returns(() => Observable.of(schema)); .returns(() => Observable.throw({}));
const router = new RouterMockup();
let result: SchemaDetailsDto;
const guard = new ResolveSchemaGuard(schemasService.object, <any>router); schemaGuard.resolve(route).subscribe(x => {
result = x!;
});
guard.resolve(<any>route, <any>{}) expect(result!).toBeNull();
.subscribe(result => {
expect(result).toBe(schema);
done(); router.verify(x => x.navigate(['/404']), Times.once());
});
}); });
}); });

17
src/Squidex/app/shared/guards/resolve-schema.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router'; import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { allParams } from '@app/framework'; import { allParams } from '@app/framework';
@ -14,28 +14,19 @@ import { allParams } from '@app/framework';
import { SchemaDetailsDto, SchemasService } from './../services/schemas.service'; import { SchemaDetailsDto, SchemasService } from './../services/schemas.service';
@Injectable() @Injectable()
export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto> { export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto | null> {
constructor( constructor(
private readonly schemasService: SchemasService, private readonly schemasService: SchemasService,
private readonly router: Router private readonly router: Router
) { ) {
} }
public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<SchemaDetailsDto> { public resolve(route: ActivatedRouteSnapshot): Observable<SchemaDetailsDto | null> {
const params = allParams(route); const params = allParams(route);
const appName = params['appName']; const appName = params['appName'];
if (!appName) {
throw 'Route must contain app name.';
}
const schemaName = params['schemaName']; const schemaName = params['schemaName'];
if (!schemaName) {
throw 'Route must contain schema name.';
}
const result = const result =
this.schemasService.getSchema(appName, schemaName) this.schemasService.getSchema(appName, schemaName)
.do(dto => { .do(dto => {
@ -46,7 +37,7 @@ export class ResolveSchemaGuard implements Resolve<SchemaDetailsDto> {
.catch(error => { .catch(error => {
this.router.navigate(['/404']); this.router.navigate(['/404']);
return Observable.of(error); return Observable.of(null);
}); });
return result; return result;

14
src/Squidex/app/shared/guards/router-mockup.ts

@ -1,14 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
export class RouterMockup {
public lastNavigation: any[];
public navigate(target: any[]) {
this.lastNavigation = target;
}
}

13
src/Squidex/app/shared/guards/unset-app.guard.spec.ts

@ -14,23 +14,22 @@ import { UnsetAppGuard } from './unset-app.guard';
describe('UnsetAppGuard', () => { describe('UnsetAppGuard', () => {
let appsState: IMock<AppsState>; let appsState: IMock<AppsState>;
let appGuard: UnsetAppGuard;
beforeEach(() => { beforeEach(() => {
appsState = Mock.ofType(AppsState); appsState = Mock.ofType<AppsState>();
appGuard = new UnsetAppGuard(appsState.object);
}); });
it('should unselect app', () => { it('should unselect app', () => {
appsState.setup(x => x.selectApp(null)) appsState.setup(x => x.selectApp(null))
.returns(() => Observable.of(null)); .returns(() => Observable.of(null));
const guard = new UnsetAppGuard(appsState.object);
let result = false; let result = false;
guard.canActivate(<any>{}, <any>{}) appGuard.canActivate().subscribe(value => {
.subscribe(value => { result = value;
result = value; });
});
expect(result).toBeTruthy(); expect(result).toBeTruthy();

4
src/Squidex/app/shared/guards/unset-app.guard.ts

@ -6,7 +6,7 @@
*/ */
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router'; import { CanActivate } from '@angular/router';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AppsState } from './../state/apps.state'; import { AppsState } from './../state/apps.state';
@ -18,7 +18,7 @@ export class UnsetAppGuard implements CanActivate {
) { ) {
} }
public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { public canActivate(): Observable<boolean> {
return this.appsState.selectApp(null).map(a => a === null); return this.appsState.selectApp(null).map(a => a === null);
} }
} }

28
src/Squidex/app/shared/interceptors/auth.interceptor.spec.ts

@ -46,7 +46,7 @@ describe('AuthInterceptor', () => {
it('should append headers to request', it('should append headers to request',
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
http.get('http://service/p/apps').subscribe(); http.get('http://service/p/apps').subscribe();
@ -61,7 +61,7 @@ describe('AuthInterceptor', () => {
it('should not append headers for no auth headers', it('should not append headers for no auth headers',
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
http.get('http://service/p/apps', { headers: new HttpHeaders().set('NoAuth', '') }).subscribe(); http.get('http://service/p/apps', { headers: new HttpHeaders().set('NoAuth', '') }).subscribe();
@ -76,7 +76,7 @@ describe('AuthInterceptor', () => {
it('should not append headers for other requests', it('should not append headers for other requests',
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
http.get('http://cloud/p/apps').subscribe(); http.get('http://cloud/p/apps').subscribe();
@ -91,14 +91,10 @@ describe('AuthInterceptor', () => {
it(`should logout for 401 status code`, it(`should logout for 401 status code`,
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
authService.setup(x => x.loginSilent()).returns(() => { return Observable.of(<any>{ authToken: 'letmereallyin' }); }); authService.setup(x => x.loginSilent()).returns(() => Observable.of(<any>{ authToken: 'letmereallyin' }));
http.get('http://service/p/apps').subscribe( http.get('http://service/p/apps').onErrorResumeNext().subscribe();
_ => { /* NOOP */ },
_ => { /* NOOP */ });
// const req = httpMock.expectOne('http://service/p/apps');
httpMock.expectOne('http://service/p/apps').error(<any>{}, { status: 401 }); httpMock.expectOne('http://service/p/apps').error(<any>{}, { status: 401 });
httpMock.expectOne('http://service/p/apps').error(<any>{}, { status: 401 }); httpMock.expectOne('http://service/p/apps').error(<any>{}, { status: 401 });
@ -110,11 +106,9 @@ describe('AuthInterceptor', () => {
it(`should logout for ${statusCode} status code`, it(`should logout for ${statusCode} status code`,
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
http.get('http://service/p/apps').subscribe( http.get('http://service/p/apps').onErrorResumeNext().subscribe();
_ => { /* NOOP */ },
_ => { /* NOOP */ });
const req = httpMock.expectOne('http://service/p/apps'); const req = httpMock.expectOne('http://service/p/apps');
@ -128,11 +122,9 @@ describe('AuthInterceptor', () => {
it(`should not logout for ${statusCode} status code`, it(`should not logout for ${statusCode} status code`,
inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => { inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
authService.setup(x => x.userChanges).returns(() => { return Observable.of(<any>{ authToken: 'letmein' }); }); authService.setup(x => x.userChanges).returns(() => Observable.of(<any>{ authToken: 'letmein' }));
http.get('http://service/p/apps').subscribe( http.get('http://service/p/apps').onErrorResumeNext().subscribe();
_ => { /* NOOP */ },
_ => { /* NOOP */ });
const req = httpMock.expectOne('http://service/p/apps'); const req = httpMock.expectOne('http://service/p/apps');

4
src/Squidex/app/shared/services/users-provider.service.spec.ts

@ -22,8 +22,8 @@ describe('UsersProviderService', () => {
let usersProviderService: UsersProviderService; let usersProviderService: UsersProviderService;
beforeEach(() => { beforeEach(() => {
authService = Mock.ofType(AuthService); authService = Mock.ofType<AuthService>();
usersService = Mock.ofType(UsersService); usersService = Mock.ofType<UsersService>();
usersProviderService = new UsersProviderService(usersService.object, authService.object); usersProviderService = new UsersProviderService(usersService.object, authService.object);
}); });

2
src/Squidex/app/shared/state/apps.state.spec.ts

@ -29,7 +29,7 @@ describe('AppsState', () => {
let appsState: AppsState; let appsState: AppsState;
beforeEach(() => { beforeEach(() => {
appsService = Mock.ofType(AppsService); appsService = Mock.ofType<AppsService>();
appsService.setup(x => x.getApps()) appsService.setup(x => x.getApps())
.returns(() => Observable.of(oldApps)) .returns(() => Observable.of(oldApps))

Loading…
Cancel
Save