bugfix, Permission Link display correctly

This commit is contained in:
Sylvain MATHIEU 2022-02-08 14:16:04 +01:00
parent b6b9d735f5
commit fc0fdd2e51
14 changed files with 202 additions and 87 deletions

View File

@ -12,7 +12,7 @@
*/
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Server} from "@models/server";
import {ApiInformationService} from "@services/api-information.service";
import {ApiInformationService} from "@services/ApiInformation/api-information.service";
import {Methods, Permission, PermissionActions} from "@models/api/permission";
import {PermissionsService} from "@services/permissions.service";
import {ToasterService} from "@services/toaster.service";

View File

@ -11,14 +11,14 @@
* Author: Sylvain MATHIEU, Elise LEBEAU
*/
import { Pipe, PipeTransform } from '@angular/core';
import {IFormatedList} from "@services/api-information.service";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
@Pipe({
name: 'filterComplete'
})
export class FilterCompletePipe implements PipeTransform {
transform(value: IFormatedList[], searchText: string): IFormatedList[] {
transform(value: IGenericApiObject[], searchText: string): IGenericApiObject[] {
if (!searchText || searchText === '') { return value; }
return value.filter((v) => {

View File

@ -11,10 +11,11 @@
* Author: Sylvain MATHIEU, Elise LEBEAU
*/
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {ApiInformationService, IFormatedList} from "@services/api-information.service";
import {ApiInformationService} from "@services/ApiInformation/api-information.service";
import {Server} from "@models/server";
import {PermissionPath} from "@components/permissions-management/add-permission-line/path-auto-complete/PermissionPath";
import {SubPath} from "@components/permissions-management/add-permission-line/path-auto-complete/SubPath";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
@Component({
selector: 'app-path-auto-complete',
@ -28,7 +29,7 @@ export class PathAutoCompleteComponent implements OnInit {
@Input() server: Server;
path: PermissionPath = new PermissionPath();
values: string[] = [];
private completeData: { data: IFormatedList[]; key: string };
private completeData: { data: IGenericApiObject[]; key: string };
public mode: 'SELECT' | 'COMPLETE' | undefined;
completeField: string;

View File

@ -13,7 +13,7 @@
import {Pipe, PipeTransform} from '@angular/core';
import {map, switchMap} from "rxjs/operators";
import {forkJoin, Observable, of} from "rxjs";
import {ApiInformationService} from "@services/api-information.service";
import {ApiInformationService} from "@services/ApiInformation/api-information.service";
import {Server} from "@models/server";
@Pipe({

View File

@ -13,7 +13,7 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {Methods, Permission} from "@models/api/permission";
import {Server} from '@models/server';
import {ApiInformationService} from "@services/api-information.service";
import {ApiInformationService} from "@services/ApiInformation/api-information.service";
import {PermissionsService} from "@services/permissions.service";
import {ToasterService} from "@services/toaster.service";
import {MatDialog} from "@angular/material/dialog";

View File

@ -19,7 +19,8 @@ import {Permission} from "@models/api/permission";
import {AddPermissionLineComponent} from "@components/permissions-management/add-permission-line/add-permission-line.component";
import {ServerService} from "@services/server.service";
import {PageEvent} from "@angular/material/paginator";
import {ApiInformationService, IFormatedList} from "@services/api-information.service";
import {ApiInformationService} from "@services/ApiInformation/api-information.service";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
@Component({
selector: 'app-permissions-management',
@ -33,7 +34,7 @@ export class PermissionsManagementComponent implements OnInit {
newPermissionEdit = false;
searchPermissions: any;
pageEvent: PageEvent | undefined;
filteredOptions: IFormatedList[];
filteredOptions: IGenericApiObject[];
options: string[] = [];
@ViewChild('dynamic', {

View File

@ -10,15 +10,14 @@
*
* Author: Sylvain MATHIEU, Elise LEBEAU
*/
import {Component, Inject, Input, OnInit, Output} from '@angular/core';
import {Role} from "@models/api/role";
import {Component, Input, OnInit, Output, EventEmitter} from '@angular/core';
import {Server} from "@models/server";
import {Permission} from "@models/api/permission";
import {MatDialog} from "@angular/material/dialog";
import {PermissionEditorValidateDialogComponent} from "@components/role-management/role-detail/permission-editor/permission-editor-validate-dialog/permission-editor-validate-dialog.component";
import { EventEmitter } from '@angular/core';
import {ApiInformationService, IFormatedList} from "@services/api-information.service";
import {ApiInformationService } from "@services/ApiInformation/api-information.service";
import {PageEvent} from "@angular/material/paginator";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
@Component({
selector: 'app-permission-editor',
@ -30,7 +29,7 @@ export class PermissionEditorComponent implements OnInit {
owned: Set<Permission>;
available: Set<Permission>;
searchPermissions: any;
filteredOptions: IFormatedList[];
filteredOptions: IGenericApiObject[];
pageEventOwned: PageEvent | undefined;
pageEventAvailable: PageEvent | undefined;
@ -106,10 +105,10 @@ export class PermissionEditorComponent implements OnInit {
}
get ownedArray() {
return Array.from(this.owned.values())
return Array.from(this.owned.values());
}
get availableArray() {
return Array.from(this.available.values())
return Array.from(this.available.values());
}
}

View File

@ -0,0 +1,43 @@
import {IApiData} from "./IApiData";
import {Server} from "../../models/server";
import {IExtraParams} from "./IExtraParams";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
export class ApiInformationCache {
private cache = new Map<string, IApiData>();
public update(server: Server, key: string, value: string, extraParams: IExtraParams[], data: IGenericApiObject[]) {
const dataKey = this.generateKey(server, key, value, extraParams);
this.cache.set(dataKey, {expired: Date.now() + 10000, data});
}
public get(server: Server, key: string, value: string, extraParams: IExtraParams[]): IGenericApiObject[] | undefined {
const dataKey = this.generateKey(server, key, value, extraParams);
const data = this.cache.get(dataKey);
if (data) {
if (data.expired > Date.now()) {
return data.data;
}
}
}
private generateKey(server: Server, key: string, value: string, extraParams: IExtraParams[]) {
return `${server.id}-${key}-${value}-${extraParams.map(param => `${param.key}+${param.value}`).join('.')}`;
}
searchByName(name: string) {
const result: IGenericApiObject[] = [];
this.cache.forEach((apiData: IApiData) => {
apiData.data.forEach((value: IGenericApiObject) => {
if (value.name.includes(name)) {
result.push(value);
}
});
});
return result;
}
}

View File

@ -0,0 +1,106 @@
import {ApiInformationService, IApiObject} from "@services/ApiInformation/api-information.service";
import {Server} from "@models/server";
import {IExtraParams} from "@services/ApiInformation/IExtraParams";
import {forkJoin, Observable, of} from "rxjs";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
import {map} from "rxjs/operators";
export class GetObjectIdHelper {
public static getIdNameFromKey(key: string): string {
return /{([^)]+)}/.exec(key)[1];
}
public static findElementInObjectListFn(key): (data: IApiObject[]) => IApiObject {
return function findElement(data: IApiObject[]): IApiObject {
const elem = data.find(d => d.name === key);
if (!elem) {
throw new Error('entry not found');
}
return elem;
};
}
public static buildRequestURL(server: Server, value: string, extraParams: IExtraParams[]): (elem) => string {
return (elem): string => {
let url = `${server.protocol}//${server.host}:${server.port}${elem.path}`;
if (extraParams) {
extraParams.forEach((param) => {
url = url.replace(param.key, param.value);
});
}
if (value) {
url = `${url}/${value}`;
}
return url;
};
}
public static createResponseObject(key: string,
extraParams: IExtraParams[],
service: ApiInformationService,
server: Server
): (response) => Observable<IGenericApiObject[]> {
const idName = key ? GetObjectIdHelper.getIdNameFromKey(key) : undefined;
return (response): Observable<IGenericApiObject[]> => {
if (!(response instanceof Array)) {
response = [response];
}
if (response.length === 0) {
return of([]);
}
/*
specific treatment for link_id
*/
if (key === '{link_id}') {
return GetObjectIdHelper.setLinkObjectInformation(response, extraParams, service, server);
} else {
return GetObjectIdHelper.setGenericObjectInformation(response, idName);
}
};
}
private static setGenericObjectInformation(response: any[], idName: string): Observable<IGenericApiObject[]> {
const keys = Object.keys(response[0]);
const idKey = keys.find(k => k.match(/_id$|filename/));
const nameKey = keys.find(k => k.match(/name/));
response = response.map(o => {
return {
id: o[idName] || o[idKey],
name: o[nameKey]
};
});
return of(response);
}
private static setLinkObjectInformation(links: any[],
extraParams: IExtraParams[],
service: ApiInformationService,
server: Server
): Observable<IGenericApiObject[]> {
return forkJoin(links.map(link => GetObjectIdHelper.getLinkInformation(link, extraParams, service, server)));
}
private static getLinkInformation(link: any,
extraParams: IExtraParams[],
service: ApiInformationService,
server: Server
): Observable<IGenericApiObject> {
const nodesDataObs = link.nodes.map(node => service.getListByObjectId(server, '{node_id}', node.node_id, extraParams));
return forkJoin(nodesDataObs)
.pipe(map((nodes: [any]) => {
const name = nodes
.reduce((acc, val) => acc.concat(val), [])
.map(node => node.name)
.join(' <-> ');
return {id: link.link_id, name};
}));
}
}

View File

@ -0,0 +1,6 @@
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
export interface IApiData {
expired: number;
data: IGenericApiObject[];
}

View File

@ -0,0 +1,4 @@
export interface IExtraParams {
key: string;
value: string;
}

View File

@ -0,0 +1,4 @@
export interface IGenericApiObject {
id: string;
name?: string;
}

View File

@ -13,10 +13,14 @@
import {Injectable} from '@angular/core';
import {HttpClient} from "@angular/common/http";
import {Observable, of, ReplaySubject} from "rxjs";
import {map, switchMap, take} from "rxjs/operators";
import {Methods} from "@models/api/permission";
import {HttpServer} from "@services/http-server.service";
import {Server} from "@models/server";
import {map, switchMap, take, tap} from "rxjs/operators";
import {Methods} from "app/models/api/permission";
import {HttpServer} from "app/services/http-server.service";
import {Server} from "app/models/server";
import {GetObjectIdHelper} from "@services/ApiInformation/GetObjectIdHelper";
import {IExtraParams} from "@services/ApiInformation/IExtraParams";
import {ApiInformationCache} from "@services/ApiInformation/ApiInformationCache";
import {IGenericApiObject} from "@services/ApiInformation/IGenericApiObject";
export interface IPathDict {
methods: ('POST' | 'GET' | 'PUT' | 'DELETE' | 'HEAD' | 'PATH')[];
@ -35,18 +39,12 @@ export interface IQueryObject {
text: string[];
}
export interface IFormatedList {
id: string;
name?: string;
}
@Injectable({
providedIn: 'root'
})
export class ApiInformationService {
private cache_permissions: { [key: string]: IFormatedList; } = {};
private cache = new ApiInformationCache();
private allowed = ['projects', 'images', 'templates', 'computes', 'symbols', 'notifications'];
private data: ReplaySubject<IPathDict[]> = new ReplaySubject<IPathDict[]>(1);
private objs: ReplaySubject<IApiObject[]> = new ReplaySubject<IApiObject[]>(1);
@ -206,71 +204,24 @@ export class ApiInformationService {
}));
}
getListByObjectId(server: Server, key: string, value?: string, extraParams?: { key: string; value: string }[]) {
const idName = /{([^)]+)}/.exec(key)[1];
function findElement(data: IApiObject[]): IApiObject {
const elem = data.find(d => d.name === key);
if (!elem) {
throw new Error('entry not found');
}
return elem;
getListByObjectId(server: Server, key: string, value?: string, extraParams?: IExtraParams[]) {
const cachedData = this.cache.get(server, key, value, extraParams);
if (cachedData) {
return of(cachedData);
}
return this.objs.pipe(
map(findElement),
switchMap(elem => {
let url = `${server.protocol}//${server.host}:${server.port}${elem.path}`;
if (extraParams) {
extraParams.forEach((param) => {
url = url.replace(param.key, param.value);
});
}
if (value) {
url = `${url}/${value}`;
}
return this.httpClient.get<any[]>(url, {headers: {Authorization: `Bearer ${server.authToken}`}});
}
),
switchMap(response => {
if (response instanceof Array) {
if (response.length === 0) {
return of([]);
}
const keys = Object.keys(response[0]);
const idKey = keys.find(k => k.match(/_id$|filename/));
const nameKey = keys.find(k => k.match(/name/));
response = response.map(o => {
return {
id: o[idName] || o[idKey],
name: o[nameKey]
};
});
response.forEach(elt => {
this.cache_permissions[elt.id] = elt;
});
return of(response);
} else {
const keys = Object.keys(response);
const idKey = keys.find(k => k.match(/_id$|filename/));
const nameKey = keys.find(k => k.match(/name/));
const ret = {id: response[idName] || response[idKey], name: response[nameKey]};
this.cache_permissions[ret.id] = ret;
return of([ret]);
}
}), take(1));
map(GetObjectIdHelper.findElementInObjectListFn(key)),
map(GetObjectIdHelper.buildRequestURL(server, value, extraParams)),
switchMap(url => this.httpClient.get<any[]>(url, {headers: {Authorization: `Bearer ${server.authToken}`}})),
switchMap(GetObjectIdHelper.createResponseObject(key, extraParams, this, server)),
tap(data => this.cache.update(server, key, value, extraParams, data)),
take(1));
}
getIdByObjNameFromCache(name: string): IFormatedList[] {
const ret: IFormatedList[] = [];
for (let [key, value] of Object.entries(this.cache_permissions)) {
if (value.name.includes(name)) {
ret.push(value);
}
}
return ret;
getIdByObjNameFromCache(name: string): IGenericApiObject[] {
return this.cache.searchByName(name);
}
}