1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-03-11 14:59:21 +02:00

Add RestApi extendability #753

This commit is contained in:
Patrik J. Braun 2023-11-04 16:54:32 +01:00
parent f7dba927b8
commit 7a0f0c743c
3 changed files with 134 additions and 10 deletions

View File

@ -0,0 +1,72 @@
import * as express from 'express';
import {NextFunction, Request, Response} from 'express';
import {UserDTO, UserRoles} from '../../../common/entities/UserDTO';
import {AuthenticationMWs} from '../../middlewares/user/AuthenticationMWs';
import {RenderingMWs} from '../../middlewares/RenderingMWs';
import {ParamsDictionary} from 'express-serve-static-core';
import {IExtensionRESTApi, IExtensionRESTRoute} from './IExtension';
import {Logger} from '../../Logger';
import {ExtensionManager} from './ExtensionManager';
import {Utils} from '../../../common/Utils';
export class ExpressRouterWrapper implements IExtensionRESTApi {
constructor(private readonly router: express.Router, private readonly name: string) {
}
get use() {
return new ExpressRouteWrapper(this.router, this.name, 'use');
}
get get() {
return new ExpressRouteWrapper(this.router, this.name, 'get');
}
get put() {
return new ExpressRouteWrapper(this.router, this.name, 'put');
}
get post() {
return new ExpressRouteWrapper(this.router, this.name, 'post');
}
get delete() {
return new ExpressRouteWrapper(this.router, this.name, 'delete');
}
}
export class ExpressRouteWrapper implements IExtensionRESTRoute {
constructor(private readonly router: express.Router,
private readonly name: string,
private readonly func: 'get' | 'use' | 'put' | 'post' | 'delete') {
}
private getAuthMWs(minRole: UserRoles) {
return minRole ? [AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(minRole)] : [];
}
public jsonResponse(paths: string[], minRole: UserRoles, cb: (params?: ParamsDictionary, body?: any, user?: UserDTO) => Promise<unknown> | unknown) {
const fullPaths = paths.map(p => (Utils.concatUrls('/' + this.name + '/' + p)));
this.router[this.func](fullPaths,
...(this.getAuthMWs(minRole).concat([
async (req: Request, res: Response, next: NextFunction) => {
req.resultPipe = await cb(req.params, req.body, req.session['user']);
next();
},
RenderingMWs.renderResult
])));
Logger.silly(`[ExtensionRest:${this.name}]`, `Listening on ${this.func} ${ExtensionManager.EXTENSION_API_PATH}${fullPaths}`);
}
public rawMiddleware(paths: string[], minRole: UserRoles, mw: (req: Request, res: Response, next: NextFunction) => void | Promise<void>) {
const fullPaths = paths.map(p => (Utils.concatUrls('/' + this.name + '/' + p)));
this.router[this.func](fullPaths,
...this.getAuthMWs(minRole),
mw);
Logger.silly(`[ExtensionRest:${this.name}]`, `Listening on ${this.func} ${ExtensionManager.EXTENSION_API_PATH}${fullPaths}`);
}
}

View File

@ -8,11 +8,15 @@ import {IExtensionEvents, IExtensionObject, IServerExtension} from './IExtension
import {ObjectManagers} from '../ObjectManagers';
import {Server} from '../../server';
import {ExtensionEvent} from './ExtensionEvent';
import {ExpressRouterWrapper} from './ExpressRouterWrapper';
import * as express from 'express';
const LOG_TAG = '[ExtensionManager]';
export class ExtensionManager implements IObjectManager {
public static EXTENSION_API_PATH = Config.Server.apiPath + '/extension';
events: IExtensionEvents = {
gallery: {
MetadataLoader: {
@ -32,8 +36,13 @@ export class ExtensionManager implements IObjectManager {
}
}
};
extObjects: { [key: string]: IExtensionObject } = {};
router: express.Router;
public async init() {
this.extObjects = {};
this.router = express.Router();
Server.getInstance().app.use(ExtensionManager.EXTENSION_API_PATH, this.router);
this.loadExtensionsList();
await this.initExtensions();
}
@ -69,16 +78,23 @@ export class ExtensionManager implements IObjectManager {
}
private createExtensionObject(name: string): IExtensionObject {
return {
_app: {
objectManagers: ObjectManagers.getInstance(),
expressApp: Server.getInstance().app,
config: Config
},
paths: ProjectPath,
Logger: createLoggerWrapper(`[Extension: ${name}]`),
events: this.events
};
if (!this.extObjects[name]) {
const rw = new ExpressRouterWrapper(this.router, name);
this.extObjects[name] = {
_app: {
get objectManagers() {
return ObjectManagers.getInstance();
},
expressApp: Server.getInstance().app,
config: Config
},
paths: ProjectPath,
Logger: createLoggerWrapper(`[Extension: ${name}]`),
events: this.events,
RESTApi: rw
};
}
return this.extObjects[name];
}
private async initExtensions() {
@ -102,5 +118,7 @@ export class ExtensionManager implements IObjectManager {
public async cleanUp() {
await this.cleanUpExtensions();
Server.getInstance().app.use(ExtensionManager.EXTENSION_API_PATH, express.Router());
this.extObjects = {};
}
}

View File

@ -1,8 +1,11 @@
import * as express from 'express';
import {NextFunction, Request, Response} from 'express';
import {PrivateConfigClass} from '../../../common/config/private/Config';
import {ObjectManagers} from '../ObjectManagers';
import {ProjectPathClass} from '../../ProjectPath';
import {ILogger} from '../../Logger';
import {UserDTO, UserRoles} from '../../../common/entities/UserDTO';
import {ParamsDictionary} from 'express-serve-static-core';
export type IExtensionBeforeEventHandler<I, O> = (input: { inputs: I }, event: { stopPropagation: boolean }) => Promise<{ inputs: I } | O>;
@ -59,11 +62,41 @@ export interface IExtensionApp {
config: PrivateConfigClass;
}
export interface IExtensionRESTRoute {
jsonResponse(paths: string[], minRole: UserRoles, cb: (params?: ParamsDictionary, body?: any, user?: UserDTO) => Promise<unknown> | unknown): void;
rawMiddleware(paths: string[], minRole: UserRoles, mw: (req: Request, res: Response, next: NextFunction) => void | Promise<void>): void;
}
export interface IExtensionRESTApi {
use: IExtensionRESTRoute;
get: IExtensionRESTRoute;
post: IExtensionRESTRoute;
put: IExtensionRESTRoute;
delete: IExtensionRESTRoute;
}
export interface IExtensionObject {
/**
* Inner functionality of the app. Use this wit caution
*/
_app: IExtensionApp;
/**
* Paths to the main components of the app.
*/
paths: ProjectPathClass;
/**
* Logger of the app
*/
Logger: ILogger;
/**
* Main app events. Use this change indexing, cover or serving gallery
*/
events: IExtensionEvents;
/**
* Use this to define REST calls related to the extension
*/
RESTApi: IExtensionRESTApi;
}
@ -72,5 +105,6 @@ export interface IExtensionObject {
*/
export interface IServerExtension {
init(extension: IExtensionObject): Promise<void>;
cleanUp?: (extension: IExtensionObject) => Promise<void>;
}