mirror of
https://github.com/bpatrik/pigallery2.git
synced 2024-12-23 01:27:14 +02:00
Add messenger extensibility to extensions #753
This commit is contained in:
parent
50b8f7a81d
commit
ebb9886d4b
@ -62,7 +62,9 @@ export class ExpressRouteWrapper implements IExtensionRESTRoute {
|
||||
},
|
||||
RenderingMWs.renderResult
|
||||
])));
|
||||
this.extLogger.silly(`Listening on ${this.func} ${ExtensionManager.EXTENSION_API_PATH}${fullPaths}`);
|
||||
const p = ExtensionManager.EXTENSION_API_PATH + fullPaths;
|
||||
this.extLogger.silly(`Listening on ${this.func} ${p}`);
|
||||
return p;
|
||||
}
|
||||
|
||||
public rawMiddleware(paths: string[], minRole: UserRoles, mw: (req: Request, res: Response, next: NextFunction) => void | Promise<void>) {
|
||||
@ -70,6 +72,8 @@ export class ExpressRouteWrapper implements IExtensionRESTRoute {
|
||||
this.router[this.func](fullPaths,
|
||||
...this.getAuthMWs(minRole),
|
||||
mw);
|
||||
this.extLogger.silly(`Listening on ${this.func} ${ExtensionManager.EXTENSION_API_PATH}${fullPaths}`);
|
||||
const p = ExtensionManager.EXTENSION_API_PATH + fullPaths;
|
||||
this.extLogger.silly(`Listening on ${this.func} ${p}`);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {IObjectManager} from '../database/IObjectManager';
|
||||
import {Logger} from '../../Logger';
|
||||
import {IExtensionEvents, IExtensionObject, IServerExtension} from './IExtension';
|
||||
import {IExtensionEvents, IExtensionObject} from './IExtension';
|
||||
import {Server} from '../../server';
|
||||
import {ExtensionEvent} from './ExtensionEvent';
|
||||
import * as express from 'express';
|
||||
@ -108,8 +108,8 @@ export class ExtensionManager implements IObjectManager {
|
||||
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
Logger.silly(LOG_TAG, `Running: "npm install --omit=dev" in ${extPath}`);
|
||||
await exec('npm install --omit=dev' ,{
|
||||
cwd:extPath
|
||||
await exec('npm install --omit=dev', {
|
||||
cwd: extPath
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const pkg = require(packageJsonPath);
|
||||
@ -138,8 +138,9 @@ export class ExtensionManager implements IObjectManager {
|
||||
const ext = require(serverExt);
|
||||
if (typeof ext?.cleanUp === 'function') {
|
||||
Logger.debug(LOG_TAG, 'Running Init on extension:' + extObj.extensionName);
|
||||
await ext?.cleanUp(ext);
|
||||
await ext?.cleanUp(extObj);
|
||||
}
|
||||
extObj.messengers.cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
|
31
src/backend/model/extension/ExtensionMessengerHandler.ts
Normal file
31
src/backend/model/extension/ExtensionMessengerHandler.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import {IExtensionMessengers} from './IExtension';
|
||||
import {DynamicConfig} from '../../../common/entities/DynamicConfig';
|
||||
import {MediaDTOWithThPath, Messenger} from '../messenger/Messenger';
|
||||
import {ExtensionMessenger} from '../messenger/ExtensionMessenger';
|
||||
import {MessengerRepository} from '../messenger/MessengerRepository';
|
||||
import {ILogger} from '../../Logger';
|
||||
|
||||
export class ExtensionMessengerHandler implements IExtensionMessengers {
|
||||
|
||||
messengers: Messenger[] = [];
|
||||
|
||||
|
||||
constructor(private readonly extLogger: ILogger) {
|
||||
}
|
||||
|
||||
|
||||
addMessenger<C extends Record<string, unknown>>(name: string, config: DynamicConfig[], callbacks: {
|
||||
sendMedia: (config: C, media: MediaDTOWithThPath[]) => Promise<void>
|
||||
}): void {
|
||||
this.extLogger.silly('Adding new Messenger:', name);
|
||||
const em = new ExtensionMessenger(name, config, callbacks);
|
||||
this.messengers.push(em);
|
||||
MessengerRepository.Instance.register(em);
|
||||
}
|
||||
|
||||
cleanUp() {
|
||||
this.extLogger.silly('Removing Messenger');
|
||||
this.messengers.forEach(m => MessengerRepository.Instance.remove(m));
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,7 @@ import {ProjectPath} from '../../ProjectPath';
|
||||
import {ExpressRouterWrapper} from './ExpressRouterWrapper';
|
||||
import {createLoggerWrapper} from '../../Logger';
|
||||
import * as express from 'express';
|
||||
import {ExtensionMessengerHandler} from './ExtensionMessengerHandler';
|
||||
|
||||
export class ExtensionObject<C> implements IExtensionObject<C> {
|
||||
|
||||
@ -16,6 +17,7 @@ export class ExtensionObject<C> implements IExtensionObject<C> {
|
||||
public readonly Logger;
|
||||
public readonly events;
|
||||
public readonly RESTApi;
|
||||
public readonly messengers;
|
||||
|
||||
constructor(public readonly extensionId: string,
|
||||
public readonly extensionName: string,
|
||||
@ -30,6 +32,7 @@ export class ExtensionObject<C> implements IExtensionObject<C> {
|
||||
this.Logger = logger;
|
||||
this.events = events;
|
||||
this.RESTApi = new ExpressRouterWrapper(extensionRouter, extensionId, logger);
|
||||
this.messengers = new ExtensionMessengerHandler(logger);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import {ILogger} from '../../Logger';
|
||||
import {UserDTO, UserRoles} from '../../../common/entities/UserDTO';
|
||||
import {ParamsDictionary} from 'express-serve-static-core';
|
||||
import {Connection} from 'typeorm';
|
||||
import {DynamicConfig} from '../../../common/entities/DynamicConfig';
|
||||
import {MediaDTOWithThPath} from '../messenger/Messenger';
|
||||
|
||||
|
||||
export type IExtensionBeforeEventHandler<I, O> = (input: { inputs: I }, event: { stopPropagation: boolean }) => Promise<{ inputs: I } | O>;
|
||||
@ -69,16 +71,18 @@ export interface IExtensionRESTRoute {
|
||||
* @param paths RESTapi path, relative to the extension base endpoint
|
||||
* @param minRole set to null to omit auer check (ie make the endpoint public)
|
||||
* @param cb function callback
|
||||
* @return newly added REST api path
|
||||
*/
|
||||
jsonResponse(paths: string[], minRole: UserRoles, cb: (params?: ParamsDictionary, body?: any, user?: UserDTO) => Promise<unknown> | unknown): void;
|
||||
jsonResponse(paths: string[], minRole: UserRoles, cb: (params?: ParamsDictionary, body?: any, user?: UserDTO) => Promise<unknown> | unknown): string;
|
||||
|
||||
/**
|
||||
* Exposes a standard expressjs middleware
|
||||
* @param paths RESTapi path, relative to the extension base endpoint
|
||||
* @param minRole set to null to omit auer check (ie make the endpoint public)
|
||||
* @param mw expressjs middleware
|
||||
* @return newly added REST api path
|
||||
*/
|
||||
rawMiddleware(paths: string[], minRole: UserRoles, mw: (req: Request, res: Response, next: NextFunction) => void | Promise<void>): void;
|
||||
rawMiddleware(paths: string[], minRole: UserRoles, mw: (req: Request, res: Response, next: NextFunction) => void | Promise<void>): string;
|
||||
}
|
||||
|
||||
export interface IExtensionRESTApi {
|
||||
@ -116,9 +120,21 @@ export interface IExtensionConfig<C> {
|
||||
getConfig(): C;
|
||||
}
|
||||
|
||||
export interface IExtensionMessengers {
|
||||
/**
|
||||
* Adds a new messenger that the user can select e.g.: for sending top pick photos
|
||||
* @param name Name of the messenger (also used as id)
|
||||
* @param config config metadata for this messenger
|
||||
* @param callbacks messenger logic
|
||||
*/
|
||||
addMessenger<C extends Record<string, unknown> = Record<string, unknown>>(name: string, config: DynamicConfig[], callbacks: {
|
||||
sendMedia: (config: C, media: MediaDTOWithThPath[]) => Promise<void>
|
||||
}): void;
|
||||
}
|
||||
|
||||
export interface IExtensionObject<C> {
|
||||
/**
|
||||
* ID of the extension that is internally used. By default the name and ID matches if there is no collision.
|
||||
* ID of the extension that is internally used. By default, the name and ID matches if there is no collision.
|
||||
*/
|
||||
extensionId: string,
|
||||
|
||||
@ -159,6 +175,13 @@ export interface IExtensionObject<C> {
|
||||
* Use this to define REST calls related to the extension
|
||||
*/
|
||||
RESTApi: IExtensionRESTApi;
|
||||
|
||||
/**
|
||||
* Object to manipulate messengers.
|
||||
* Messengers are used to send messages (like emails) from the app.
|
||||
* One type of message is a list of selected photos.
|
||||
*/
|
||||
messengers: IExtensionMessengers;
|
||||
}
|
||||
|
||||
|
||||
|
15
src/backend/model/messenger/ExtensionMessenger.ts
Normal file
15
src/backend/model/messenger/ExtensionMessenger.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {MediaDTOWithThPath, Messenger} from './Messenger';
|
||||
import {DynamicConfig} from '../../../common/entities/DynamicConfig';
|
||||
|
||||
export class ExtensionMessenger<C extends Record<string, unknown> = Record<string, unknown>> extends Messenger<C> {
|
||||
|
||||
constructor(public readonly Name: string,
|
||||
public readonly ConfigTemplate: DynamicConfig[],
|
||||
private readonly callbacks: { sendMedia: (config: C, media: MediaDTOWithThPath[]) => Promise<void> }) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected sendMedia(config: C, media: MediaDTOWithThPath[]): Promise<void> {
|
||||
return this.callbacks.sendMedia(config, media);
|
||||
}
|
||||
}
|
@ -18,6 +18,13 @@ export class MessengerRepository {
|
||||
return Object.values(this.messengers);
|
||||
}
|
||||
|
||||
remove(m: Messenger<Record<string, unknown>>): void {
|
||||
if (!this.messengers[m.Name]) {
|
||||
throw new Error('Messenger does not exist:' + m.Name);
|
||||
}
|
||||
delete this.messengers[m.Name];
|
||||
}
|
||||
|
||||
register(msgr: Messenger): void {
|
||||
if (typeof this.messengers[msgr.Name] !== 'undefined') {
|
||||
throw new Error('Messenger already exist:' + msgr.Name);
|
||||
|
Loading…
Reference in New Issue
Block a user