diff --git a/src/app/app.guard.ts b/src/app/app.guard.ts index 61076a26a7..955386d7f0 100644 --- a/src/app/app.guard.ts +++ b/src/app/app.guard.ts @@ -2,21 +2,24 @@ import {Injectable} from '@angular/core'; import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from '@angular/router'; import {WorkContextService} from './features/work-context/work-context.service'; import {Observable, of} from 'rxjs'; -import {switchMap, take} from 'rxjs/operators'; +import {concatMap, map, switchMap, take, tap} from 'rxjs/operators'; import {WorkContextType} from './features/work-context/work-context.model'; +import {TagService} from './features/tag/tag.service'; +import {ProjectService} from './features/project/project.service'; +import {DataInitService} from './core/data-init/data-init.service'; @Injectable({ providedIn: 'root' }) export class ActiveWorkContextGuard implements CanActivate { constructor( - private workContextService: WorkContextService, - private router: Router, + private _workContextService: WorkContextService, + private _router: Router, ) { } canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { - return this.workContextService.activeWorkContextTypeAndId$.pipe( + return this._workContextService.activeWorkContextTypeAndId$.pipe( take(1), switchMap(({activeType, activeId}) => { const {subPageType, param} = next.params; @@ -24,8 +27,50 @@ export class ActiveWorkContextGuard implements CanActivate { ? 'tag' : 'project'; const url = `/${base}/${activeId}/${subPageType}${param ? '/' + param : ''}`; - return of(this.router.parseUrl(url)); + return of(this._router.parseUrl(url)); }) ); } } + + +@Injectable({ + providedIn: 'root' +}) +export class ValidTagIdGuard implements CanActivate { + constructor( + private _router: Router, + private _tagService: TagService, + private _dataInitService: DataInitService, + ) { + } + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const {id} = next.params; + return this._dataInitService.isAllDataLoadedInitially$.pipe( + concatMap(() => this._tagService.getTagById$(id)), + take(1), + map(tag => !!tag), + ); + } +} + +@Injectable({ + providedIn: 'root' +}) +export class ValidProjectIdGuard implements CanActivate { + constructor( + private _router: Router, + private _projectService: ProjectService, + private _dataInitService: DataInitService, + ) { + } + + canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + const {id} = next.params; + return this._dataInitService.isAllDataLoadedInitially$.pipe( + concatMap(() => this._projectService.getByIdOnce$(id)), + map(project => !!project), + ); + } +} diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index e2c3ae4201..9e887642e4 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -9,7 +9,7 @@ import {ProcrastinationComponent} from './features/procrastination/procrastinati import {SchedulePageComponent} from './pages/schedule-page/schedule-page.component'; import {ProjectSettingsPageComponent} from './pages/project-settings-page/project-settings-page.component'; import {TagTaskPageComponent} from './pages/tag-task-page/tag-task-page.component'; -import {ActiveWorkContextGuard} from './app.guard'; +import {ActiveWorkContextGuard, ValidProjectIdGuard, ValidTagIdGuard} from './app.guard'; import {TagSettingsPageComponent} from './pages/tag-settings-page/tag-settings-page.component'; export const APP_ROUTES: Routes = [ @@ -17,19 +17,74 @@ export const APP_ROUTES: Routes = [ {path: 'schedule', component: SchedulePageComponent, data: {page: 'schedule'}}, {path: 'procrastination', component: ProcrastinationComponent, data: {page: 'procrastination'}}, - {path: 'tag/:id/tasks', component: TagTaskPageComponent, data: {page: 'tag-tasks'}}, - {path: 'tag/:id/settings', component: TagSettingsPageComponent, data: {page: 'tag-settings'}}, - {path: 'tag/:id/worklog', component: WorklogComponent, data: {page: 'worklog'}}, - // {path: 'tag/:id/metrics', component: MetricPageComponent, data: {page: 'metrics'}}, - {path: 'tag/:id/daily-summary', component: DailySummaryComponent, data: {page: 'daily-summary'}}, - {path: 'tag/:id/daily-summary/:dayStr', component: DailySummaryComponent, data: {page: 'daily-summary'}}, + { + path: 'tag/:id/tasks', + component: TagTaskPageComponent, + data: {page: 'tag-tasks'}, + canActivate: [ValidTagIdGuard] + }, + { + path: 'tag/:id/settings', + component: TagSettingsPageComponent, + data: {page: 'tag-settings'}, + canActivate: [ValidTagIdGuard] + }, + { + path: 'tag/:id/worklog', + component: WorklogComponent, + data: {page: 'worklog'}, + canActivate: [ValidTagIdGuard] + }, + // {path: 'tag/:id/metrics', component: MetricPageComponent, data: {page: 'metrics'}, canActivate: [ValidContextIdGuard]}, + { + path: 'tag/:id/daily-summary', + component: DailySummaryComponent, + data: {page: 'daily-summary'}, + canActivate: [ValidTagIdGuard] + }, + { + path: 'tag/:id/daily-summary/:dayStr', + component: DailySummaryComponent, + data: {page: 'daily-summary'}, + canActivate: [ValidTagIdGuard] + }, - {path: 'project/:id/tasks', component: ProjectTaskPageComponent, data: {page: 'project-tasks'}}, - {path: 'project/:id/settings', component: ProjectSettingsPageComponent, data: {page: 'project-settings'}}, - {path: 'project/:id/worklog', component: WorklogComponent, data: {page: 'worklog'}}, - {path: 'project/:id/metrics', component: MetricPageComponent, data: {page: 'metrics'}}, - {path: 'project/:id/daily-summary', component: DailySummaryComponent, data: {page: 'daily-summary'}}, - {path: 'project/:id/daily-summary/:dayStr', component: DailySummaryComponent, data: {page: 'daily-summary'}}, + { + path: 'project/:id/tasks', + component: ProjectTaskPageComponent, + data: {page: 'project-tasks'}, + canActivate: [ValidProjectIdGuard] + }, + { + path: 'project/:id/settings', + component: ProjectSettingsPageComponent, + data: {page: 'project-settings'}, + canActivate: [ValidProjectIdGuard] + }, + { + path: 'project/:id/worklog', + component: WorklogComponent, + data: {page: 'worklog'}, + canActivate: [ValidProjectIdGuard] + }, + { + path: 'project/:id/metrics', + component: MetricPageComponent, + data: {page: 'metrics'}, + canActivate: [ValidProjectIdGuard] + }, + { + path: 'project/:id/daily-summary', + component: DailySummaryComponent, + data: {page: 'daily-summary'}, + canActivate: [ValidProjectIdGuard] + }, + { + path: 'project/:id/daily-summary/:dayStr', + component: DailySummaryComponent, + data: {page: 'daily-summary'}, + canActivate: [ValidProjectIdGuard] + }, {path: 'project-overview', component: ProjectOverviewPageComponent, data: {page: 'project-overview'}}, diff --git a/src/app/features/work-context/work-context.service.ts b/src/app/features/work-context/work-context.service.ts index b916cbb6af..f3102b53b9 100644 --- a/src/app/features/work-context/work-context.service.ts +++ b/src/app/features/work-context/work-context.service.ts @@ -457,8 +457,11 @@ export class WorkContextService { } // NOTE: NEVER call this from some place other than the route change stuff - private _setActiveContext(activeId: string, activeType: WorkContextType) { + private async _setActiveContext(activeId: string, activeType: WorkContextType) { this._store$.dispatch(setActiveWorkContext({activeId, activeType})); } + private async _isValidContextId(id: string): Promise { + + } }