mirror of
https://github.com/CaramelFur/Picsur.git
synced 2026-05-07 16:38:01 +02:00
fix duplicate singleton
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { ComponentPortal, Portal } from '@angular/cdk/portal';
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Portal } from '@angular/cdk/portal';
|
||||
import { Component, Injector, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatSidenav } from '@angular/material/sidenav';
|
||||
import {
|
||||
ActivatedRoute,
|
||||
@@ -30,7 +30,8 @@ export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private breakPointObserver: BreakpointObserver
|
||||
private breakPointObserver: BreakpointObserver,
|
||||
private injector: Injector
|
||||
) {}
|
||||
|
||||
private get routeData(): PRouteData {
|
||||
@@ -88,10 +89,8 @@ export class AppComponent implements OnInit {
|
||||
|
||||
console.log(data);
|
||||
|
||||
if (data.sidebar !== undefined) {
|
||||
this.sidebarPortal?.detach();
|
||||
this.sidebarPortal = new ComponentPortal(data.sidebar);
|
||||
|
||||
if (data._sidebar_portal !== undefined) {
|
||||
this.sidebarPortal = data._sidebar_portal;
|
||||
this.hasSidebar = true;
|
||||
} else {
|
||||
this.hasSidebar = false;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ApiModule } from 'src/app/services/api/api.module';
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [CommonModule, ApiModule],
|
||||
imports: [CommonModule],
|
||||
exports: [FooterComponent],
|
||||
})
|
||||
export class FooterModule {}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ApiModule } from 'src/app/services/api/api.module';
|
||||
import { UtilModule } from 'src/app/util/util.module';
|
||||
import { HeaderComponent } from './header.component';
|
||||
|
||||
@@ -15,7 +14,6 @@ import { HeaderComponent } from './header.component';
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
RouterModule,
|
||||
ApiModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
UtilModule,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ApiModule } from '../services/api/api.module';
|
||||
import { PermissionGuard } from './permission.guard';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, ApiModule],
|
||||
imports: [CommonModule],
|
||||
providers: [PermissionGuard],
|
||||
exports: [],
|
||||
})
|
||||
|
||||
@@ -2,24 +2,39 @@ import { Injectable } from '@angular/core';
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
CanActivateChild,
|
||||
Router,
|
||||
RouterStateSnapshot
|
||||
} from '@angular/router';
|
||||
import { Permissions } from 'picsur-shared/dist/dto/permissions';
|
||||
import { isPermissionsArray } from 'picsur-shared/dist/util/permissions';
|
||||
import { PRouteData } from '../models/picsur-routes';
|
||||
import { PermissionService } from '../services/api/permission.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class PermissionGuard implements CanActivate {
|
||||
export class PermissionGuard implements CanActivate, CanActivateChild {
|
||||
constructor(
|
||||
private permissionService: PermissionService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
async canActivateChild(
|
||||
childRoute: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
) {
|
||||
console.log('canActivateChild');
|
||||
return await this.can(childRoute, state);
|
||||
}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const requiredPermissions: Permissions = route.data['permissions'];
|
||||
console.log('canActivate');
|
||||
return await this.can(route, state);
|
||||
}
|
||||
|
||||
private async can(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
|
||||
const requiredPermissions: Permissions = this.nestedPermissions(route);
|
||||
if (!isPermissionsArray(requiredPermissions)) {
|
||||
throw new Error(
|
||||
`PermissionGuard: route data 'permissions' must be an array of Permission values`
|
||||
@@ -37,4 +52,19 @@ export class PermissionGuard implements CanActivate {
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
|
||||
private nestedPermissions(route: ActivatedRouteSnapshot): Permissions {
|
||||
const data: PRouteData = route.data;
|
||||
|
||||
let permissions: Permissions = [];
|
||||
if (data?.permissions) {
|
||||
permissions = permissions.concat(data.permissions);
|
||||
}
|
||||
if (route.firstChild) {
|
||||
permissions = permissions.concat(
|
||||
this.nestedPermissions(route.firstChild)
|
||||
);
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ComponentType, Portal } from '@angular/cdk/portal';
|
||||
import { Route } from '@angular/router';
|
||||
import { Permissions } from 'picsur-shared/dist/dto/permissions';
|
||||
|
||||
|
||||
export type PRouteData = {
|
||||
page?: {
|
||||
title?: string;
|
||||
@@ -10,7 +10,8 @@ export type PRouteData = {
|
||||
};
|
||||
permissions?: Permissions;
|
||||
noContainer?: boolean;
|
||||
sidebar?: string;
|
||||
sidebar?: ComponentType<unknown>;
|
||||
_sidebar_portal?: Portal<unknown>;
|
||||
};
|
||||
|
||||
export type PRoute = Route & {
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-general.component.html',
|
||||
})
|
||||
export class SettingsGeneralComponent implements OnInit {
|
||||
constructor() {}
|
||||
constructor(private permissionsService: PermissionService) {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
ngOnInit(): void {
|
||||
this.subscribePermissions();
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
subscribePermissions() {
|
||||
return this.permissionsService.live.subscribe((permissions) => {
|
||||
console.log('Pogogog', permissions);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SettingsGeneralComponent } from './settings-general.component';
|
||||
import { SettingsGeneralRoutingModule } from './settings-home.routing.module';
|
||||
import { SettingsGeneralRoutingModule } from './settings-general.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SettingsGeneralComponent],
|
||||
@@ -1,5 +1,4 @@
|
||||
<mat-nav-list>
|
||||
<span mat-subheader>Big Peepee</span>
|
||||
<ng-container *ngIf="personalRoutes.length > 0">
|
||||
<span mat-subheader>Personal</span>
|
||||
<a
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { Component, Inject, OnDestroy, OnInit } from '@angular/core';
|
||||
import { PRoutes } from 'src/app/models/picsur-routes';
|
||||
import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
|
||||
@@ -8,32 +6,30 @@ import { PermissionService } from 'src/app/services/api/permission.service';
|
||||
templateUrl: './settings-sidebar.component.html',
|
||||
styleUrls: ['./settings-sidebar.component.scss'],
|
||||
})
|
||||
export class SettingsSidebarComponent implements OnInit {
|
||||
export class SettingsSidebarComponent implements OnInit, OnDestroy {
|
||||
//private settingsRoutes: PRoutes = [];
|
||||
private accessibleRoutes: PRoutes = [];
|
||||
private settingsRoutes: PRoutes = [];
|
||||
|
||||
personalRoutes: PRoutes = [];
|
||||
systemRoutes: PRoutes = [];
|
||||
|
||||
constructor(
|
||||
/* @Inject('SettingsRoutes')*/
|
||||
private permissionService: PermissionService,
|
||||
private router: Router
|
||||
) {
|
||||
console.error("contstruct");
|
||||
console.log('stat', this.router.getCurrentNavigation());
|
||||
@Inject('SettingsRoutes') private settingsRoutes: PRoutes,
|
||||
private permissionService: PermissionService
|
||||
) {}
|
||||
ngOnDestroy(): void {
|
||||
console.error('destoryed');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
console.log('SettingsSidebarComponent.ngOnInit()');
|
||||
console.log('SettingsSidebarComponent.ngOnInit() with ' + this.permissionService.counter);
|
||||
this.subscribePermissions();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@AutoUnsubscribe()
|
||||
// @AutoUnsubscribe()
|
||||
private subscribePermissions() {
|
||||
return this.permissionService.live.subscribe((permissions) => {
|
||||
const o = this.permissionService.live.subscribe((permissions) => {
|
||||
console.warn('pog', permissions);
|
||||
this.accessibleRoutes = this.settingsRoutes
|
||||
.filter((route) => route.path !== '')
|
||||
.filter((route) =>
|
||||
@@ -51,5 +47,9 @@ export class SettingsSidebarComponent implements OnInit {
|
||||
(route) => route.data?.page?.category === 'system'
|
||||
);
|
||||
});
|
||||
o.add(() => {
|
||||
console.error('stopped');
|
||||
});
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<h1>Settings Syspref</h1>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-syspref.component.html',
|
||||
})
|
||||
export class SettingsSysprefComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SettingsSysprefComponent } from './settings-syspref.component';
|
||||
import { SettingsSysprefRoutingModule } from './settings-syspref.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SettingsSysprefComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SettingsSysprefRoutingModule,
|
||||
],
|
||||
})
|
||||
export class SettingsSysprefRouteModule {}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { PRoutes } from 'src/app/models/picsur-routes';
|
||||
import { SettingsSysprefComponent } from './settings-syspref.component';
|
||||
|
||||
const routes: PRoutes = [
|
||||
{
|
||||
path: '',
|
||||
component: SettingsSysprefComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class SettingsSysprefRoutingModule {}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Injector, NgModule } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { ApiModule } from 'src/app/services/api/api.module';
|
||||
import { SettingsSidebarComponent } from './settings-sidebar/settings-sidebar.component';
|
||||
import { SettingsRoutingModule } from './settings.routing.module';
|
||||
|
||||
@@ -11,9 +10,11 @@ import { SettingsRoutingModule } from './settings.routing.module';
|
||||
imports: [
|
||||
CommonModule,
|
||||
SettingsRoutingModule.forRoot(),
|
||||
ApiModule,
|
||||
MatListModule,
|
||||
MatIconModule,
|
||||
],
|
||||
exports: [SettingsRoutingModule],
|
||||
})
|
||||
export class SettingsRouteModule {}
|
||||
export class SettingsRouteModule {
|
||||
constructor(private injector: Injector) {}
|
||||
}
|
||||
|
||||
@@ -3,30 +3,50 @@ import { RouterModule } from '@angular/router';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions';
|
||||
import { PermissionGuard } from 'src/app/guards/permission.guard';
|
||||
import { PRoutes } from 'src/app/models/picsur-routes';
|
||||
import { SettingsGeneralRouteModule } from './settings-general/settings-home.module';
|
||||
import { SidebarResolverService } from 'src/app/services/sidebar-resolver/sidebar-resolver.service';
|
||||
import { SettingsGeneralRouteModule } from './settings-general/settings-general.module';
|
||||
import { SettingsSidebarComponent } from './settings-sidebar/settings-sidebar.component';
|
||||
import { SettingsSysprefRouteModule } from './settings-syspref/settings-syspref.module';
|
||||
|
||||
const SettingsRoutes: PRoutes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'general',
|
||||
},
|
||||
{
|
||||
path: 'general',
|
||||
loadChildren: () => SettingsGeneralRouteModule,
|
||||
canActivate: [PermissionGuard],
|
||||
data: {
|
||||
permissions: [Permission.Settings],
|
||||
page: {
|
||||
title: 'General',
|
||||
icon: 'settings',
|
||||
category: 'personal',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'general',
|
||||
},
|
||||
{
|
||||
path: 'general',
|
||||
loadChildren: () => SettingsGeneralRouteModule,
|
||||
data: {
|
||||
permissions: [Permission.Settings],
|
||||
page: {
|
||||
title: 'General',
|
||||
icon: 'settings',
|
||||
category: 'personal',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'general',
|
||||
loadChildren: () => SettingsSysprefRouteModule,
|
||||
data: {
|
||||
permissions: [Permission.SysPrefManage],
|
||||
page: {
|
||||
title: 'Sys Preferences',
|
||||
icon: 'settings',
|
||||
category: 'system',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
canActivate: [PermissionGuard],
|
||||
canActivateChild: [PermissionGuard],
|
||||
data: {
|
||||
sidebar: SettingsSidebarComponent,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'sidebar',
|
||||
component: SettingsSidebarComponent,
|
||||
resolve: SidebarResolverService.build(),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -41,7 +61,7 @@ export class SettingsRoutingModule {
|
||||
providers: [
|
||||
{
|
||||
provide: 'SettingsRoutes',
|
||||
useFactory: () => SettingsRoutes,
|
||||
useFactory: () => SettingsRoutes[0].children,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ApiService } from './api.service';
|
||||
import { ImageService } from './image.service';
|
||||
import { InfoService } from './info.service';
|
||||
import { KeyService } from './key.service';
|
||||
import { PermissionService } from './permission.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
ApiService,
|
||||
ImageService,
|
||||
UserService,
|
||||
PermissionService,
|
||||
KeyService,
|
||||
InfoService,
|
||||
],
|
||||
imports: [CommonModule],
|
||||
})
|
||||
export class ApiModule {}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Optional, SkipSelf } from '@angular/core';
|
||||
import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator';
|
||||
import { UserMePermissionsResponse } from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import {
|
||||
@@ -10,11 +10,20 @@ import { BehaviorSubject, filter, map, Observable, take } from 'rxjs';
|
||||
import { ApiService } from './api.service';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
@Injectable()
|
||||
let i = 0;
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PermissionService {
|
||||
private readonly logger = console;
|
||||
public counter = 0;
|
||||
|
||||
constructor(private userService: UserService, private api: ApiService) {
|
||||
constructor(
|
||||
private userService: UserService,
|
||||
private api: ApiService,
|
||||
@Optional() @SkipSelf() parent?: PermissionService
|
||||
) {
|
||||
this.counter = ++i;
|
||||
console.log('PermissionService.constructor(' + this.counter + ')');
|
||||
this.onUser();
|
||||
}
|
||||
|
||||
@@ -45,12 +54,13 @@ export class PermissionService {
|
||||
@AutoUnsubscribe()
|
||||
private onUser() {
|
||||
return this.userService.live.subscribe(async (user) => {
|
||||
console.log('PermissionService.onUser(' + this.counter + ')', user);
|
||||
const permissions = await this.fetchPermissions();
|
||||
if (HasFailed(permissions)) {
|
||||
this.logger.warn(permissions.getReason());
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Permissions next', permissions);
|
||||
this.permissionsSubject.next(permissions);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ComponentPortal, Portal } from '@angular/cdk/portal';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
|
||||
import { PRouteData } from 'src/app/models/picsur-routes';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'any',
|
||||
})
|
||||
export class SidebarResolverService
|
||||
implements Resolve<Portal<unknown> | undefined>
|
||||
{
|
||||
constructor(private injector: Injector) {}
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot) {
|
||||
const data: PRouteData = route.data;
|
||||
if (!data.sidebar) return undefined;
|
||||
|
||||
return new ComponentPortal(data.sidebar, null, this.injector);
|
||||
}
|
||||
|
||||
static build() {
|
||||
return {
|
||||
_sidebar_portal: SidebarResolverService,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user