diff --git a/plugins/arcgis/service/src/index.ts b/plugins/arcgis/service/src/index.ts index f888cabf3..fdf6b90f3 100644 --- a/plugins/arcgis/service/src/index.ts +++ b/plugins/arcgis/service/src/index.ts @@ -7,7 +7,7 @@ import { SettingPermission } from '@ngageoint/mage.service/lib/entities/authoriz import express from 'express' import { ArcGISPluginConfig } from './ArcGISPluginConfig' import { ObservationProcessor } from './ObservationProcessor' -import {HttpClient} from './HttpClient' +import { HttpClient } from './HttpClient' import { FeatureServiceResult } from './FeatureServiceResult' const logPrefix = '[mage.arcgis]' @@ -50,52 +50,67 @@ const arcgisPluginHooks: InitPluginHook = { const processor = new ObservationProcessor(stateRepo, eventRepo, obsRepoForEvent, userRepo, console); processor.start(); return { - webRoutes(requestContext: GetAppRequestContext) { - const routes = express.Router() - .use(express.json()) - .use(async (req, res, next) => { - const context = requestContext(req) - const user = context.requestingPrincipal() - if (!user.role.permissions.find(x => x === SettingPermission.UPDATE_SETTINGS)) { - return res.status(403).json({ message: 'unauthorized' }) - } - next() + webRoutes: { + public: (requestContext: GetAppRequestContext) => { + const routes = express.Router().use(express.json()) + routes.post('/oauth/signin', async (req, res, next) => { + // TODO implement }) - routes.route('/config') - .get(async (req, res, next) => { - console.info('Getting ArcGIS plugin config...') - const config = await processor.safeGetConfig(); - res.json(config) - }) - .put(async (req, res, next) => { - console.info('Applying ArcGIS plugin config...') - const arcConfig = req.body as ArcGISPluginConfig - const configString = JSON.stringify(arcConfig) - console.info(configString) - processor.putConfig(arcConfig) - res.status(200).json({}) + + routes.post('/oauth/authenticate', async (req, res, next) => { + // TODO implement }) - routes.route('/arcgisLayers') - .get(async (req, res, next) => { - const featureUrl = req.query.featureUrl as string; - console.info('Getting ArcGIS layer info for ' + featureUrl) - const httpClient = new HttpClient(console); - httpClient.sendGetHandleResponse(featureUrl, (chunk) => { - console.info('ArcGIS layer info response ' + chunk); - try { - const featureServiceResult = JSON.parse(chunk) as FeatureServiceResult; - res.json(featureServiceResult); - } catch(e) { - if(e instanceof SyntaxError) { - console.error('Problem with url response for url ' + featureUrl + ' error ' + e) - res.status(200).json({}) - } else { - throw e; - } + + return routes + }, + protected: (requestContext: GetAppRequestContext) => { + const routes = express.Router() + .use(express.json()) + .use(async (req, res, next) => { + const context = requestContext(req) + const user = context.requestingPrincipal() + if (!user.role.permissions.find(x => x === SettingPermission.UPDATE_SETTINGS)) { + return res.status(403).json({ message: 'unauthorized' }) } - }); - }) - return routes + next() + }) + routes.route('/config') + .get(async (req, res, next) => { + console.info('Getting ArcGIS plugin config...') + const config = await processor.safeGetConfig(); + res.json(config) + }) + .put(async (req, res, next) => { + console.info('Applying ArcGIS plugin config...') + const arcConfig = req.body as ArcGISPluginConfig + const configString = JSON.stringify(arcConfig) + console.info(configString) + processor.putConfig(arcConfig) + res.status(200).json({}) + }) + routes.route('/arcgisLayers') + .get(async (req, res, next) => { + const featureUrl = req.query.featureUrl as string; + console.info('Getting ArcGIS layer info for ' + featureUrl) + const httpClient = new HttpClient(console); + httpClient.sendGetHandleResponse(featureUrl, (chunk) => { + console.info('ArcGIS layer info response ' + chunk); + try { + const featureServiceResult = JSON.parse(chunk) as FeatureServiceResult; + res.json(featureServiceResult); + } catch (e) { + if (e instanceof SyntaxError) { + console.error('Problem with url response for url ' + featureUrl + ' error ' + e) + res.status(200).json({}) + } else { + throw e; + } + } + }); + }) + + return routes + } } } } diff --git a/plugins/image/service/package-lock.json b/plugins/image/service/package-lock.json index d7abb88f2..9bd762367 100644 --- a/plugins/image/service/package-lock.json +++ b/plugins/image/service/package-lock.json @@ -7967,8 +7967,6 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "extraneous": true, - "dev": true, - "optional": true, "hasInstallScript": true, "os": [ "darwin" diff --git a/plugins/image/service/src/index.ts b/plugins/image/service/src/index.ts index 60c31ec29..f2b99ae66 100644 --- a/plugins/image/service/src/index.ts +++ b/plugins/image/service/src/index.ts @@ -54,39 +54,41 @@ const imagePluginHooks: InitPluginHook = { const control = await createImagePluginControl(stateRepo, eventRepo, obsRepoForEvent, attachmentStore, queryAttachments, imageService, console) control.start() return { - webRoutes(requestContext: GetAppRequestContext): express.Router { - // TODO: add api routes to save image processing settings - const routes = express.Router() - .use(express.json()) - .use(async (req, res, next) => { - const context = requestContext(req) - const user = context.requestingPrincipal() - if (!user.role.permissions.find(x => x === SettingPermission.UPDATE_SETTINGS)) { - return res.status(403).json({ message: 'unauthorized' }) - } - next() - }) - routes.route('/config') - .get(async (req, res, next) => { - const config = await control.getConfig() - res.json(config) - }) - .put(async (req, res, next) => { - const bodyConfig = req.body as any - const configPatch: Partial = { - enabled: typeof bodyConfig.enabled === 'boolean' ? bodyConfig.enabled : undefined, - intervalBatchSize: typeof bodyConfig.intervalBatchSize === 'number' ? bodyConfig.intervalBatchSize : undefined, - intervalSeconds: typeof bodyConfig.intervalSeconds === 'number' ? bodyConfig.intervalSeconds : undefined, - thumbnailSizes: Array.isArray(bodyConfig.thumbnailSizes) ? - bodyConfig.thumbnailSizes.reduce((sizes: number[], size: any) => { - return typeof size === 'number' ? [ ...sizes, size ] : sizes - }, [] as number[]) - : [] - } - const config = await control.applyConfig(configPatch) - res.json(config) - }) - return routes + webRoutes: { + protected(requestContext: GetAppRequestContext): express.Router { + // TODO: add api routes to save image processing settings + const routes = express.Router() + .use(express.json()) + .use(async (req, res, next) => { + const context = requestContext(req) + const user = context.requestingPrincipal() + if (!user.role.permissions.find(x => x === SettingPermission.UPDATE_SETTINGS)) { + return res.status(403).json({ message: 'unauthorized' }) + } + next() + }) + routes.route('/config') + .get(async (req, res, next) => { + const config = await control.getConfig() + res.json(config) + }) + .put(async (req, res, next) => { + const bodyConfig = req.body as any + const configPatch: Partial = { + enabled: typeof bodyConfig.enabled === 'boolean' ? bodyConfig.enabled : undefined, + intervalBatchSize: typeof bodyConfig.intervalBatchSize === 'number' ? bodyConfig.intervalBatchSize : undefined, + intervalSeconds: typeof bodyConfig.intervalSeconds === 'number' ? bodyConfig.intervalSeconds : undefined, + thumbnailSizes: Array.isArray(bodyConfig.thumbnailSizes) ? + bodyConfig.thumbnailSizes.reduce((sizes: number[], size: any) => { + return typeof size === 'number' ? [...sizes, size] : sizes + }, [] as number[]) + : [] + } + const config = await control.applyConfig(configPatch) + res.json(config) + }) + return routes + } } } } diff --git a/service/src/app.ts b/service/src/app.ts index ed8255a87..85c4dbd1c 100644 --- a/service/src/app.ts +++ b/service/src/app.ts @@ -139,9 +139,9 @@ export const boot = async function(config: BootConfig): Promise { const dbLayer = await initDatabase() const repos = await initRepositories(dbLayer, config) const appLayer = await initAppLayer(repos) - const { webController, addAuthenticatedPluginRoutes } = await initWebLayer(repos, appLayer, config.plugins?.webUIPlugins || []) - const routesForPluginId: { [pluginId: string]: WebRoutesHooks['webRoutes'] } = {} - const collectPluginRoutesToSort = (pluginId: string, initPluginRoutes: WebRoutesHooks['webRoutes']) => { + const { webController, addPluginRoutes } = await initWebLayer(repos, appLayer, config.plugins?.webUIPlugins || []) + const routesForPluginId: {[pluginId: string]: WebRoutesHooks } = {} + const collectPluginRoutesToSort = (pluginId: string, initPluginRoutes: WebRoutesHooks): void => { routesForPluginId[pluginId] = initPluginRoutes } const globalScopeServices = new Map, any>([ @@ -191,7 +191,7 @@ export const boot = async function(config: BootConfig): Promise { } const pluginRoutePathsDescending = Object.keys(routesForPluginId).sort().reverse() for (const pluginId of pluginRoutePathsDescending) { - addAuthenticatedPluginRoutes(pluginId, routesForPluginId[pluginId]) + addPluginRoutes(pluginId, routesForPluginId[pluginId]) } try { @@ -532,8 +532,11 @@ interface MageEventRequestContext extends AppRequestContext { const observationEventScopeKey = 'observationEventScope' as const -async function initWebLayer(repos: Repositories, app: AppLayer, webUIPlugins: string[]): - Promise<{ webController: express.Application, addAuthenticatedPluginRoutes: (pluginId: string, pluginRoutes: WebRoutesHooks['webRoutes']) => void }> { +async function initWebLayer( + repos: Repositories, + app: AppLayer, + webUIPlugins: string[] +): Promise<{ webController: express.Application, addPluginRoutes: (pluginId: string, initPluginRoutes: WebRoutesHooks) => void }> { // load routes the old way const webLayer = await import('./express') const webController = webLayer.app @@ -648,13 +651,20 @@ async function initWebLayer(repos: Repositories, app: AppLayer, webUIPlugins: st } return { webController, - addAuthenticatedPluginRoutes: (pluginId: string, initPluginRoutes: WebRoutesHooks['webRoutes']) => { - const routes = initPluginRoutes(pluginAppRequestContext) - webController.use(`/plugins/${pluginId}`, [ bearerAuth, routes ]) + addPluginRoutes: (pluginId: string, initPluginRoutes: WebRoutesHooks): void => { + if (initPluginRoutes.webRoutes.public) { + const routes = initPluginRoutes.webRoutes.public(pluginAppRequestContext) + webController.use(`/plugins/${pluginId}`, [routes]) + } + + if (initPluginRoutes.webRoutes.protected) { + const routes = initPluginRoutes.webRoutes.protected(pluginAppRequestContext) + webController.use(`/plugins/${pluginId}`, [bearerAuth, routes]) + } } } } - + function baseAppRequestContext(req: express.Request): AppRequestContext { return { requestToken: Symbol(), diff --git a/service/src/main.impl/main.impl.plugins.ts b/service/src/main.impl/main.impl.plugins.ts index f6beb0b5c..e0f2411c4 100644 --- a/service/src/main.impl/main.impl.plugins.ts +++ b/service/src/main.impl/main.impl.plugins.ts @@ -13,9 +13,14 @@ export interface InjectableServices { (token: InjectionToken): Service } -export type AddPluginWebRoutes = (pluginId: string, initRoutes: WebRoutesHooks['webRoutes']) => void +export type AddPluginWebRoutes = (pluginId: string, webRoutes: WebRoutesHooks) => void -export async function integratePluginHooks(pluginId: string, plugin: InitPluginHook, injectService: InjectableServices, addWebRoutesFromPlugin: AddPluginWebRoutes): Promise { +export async function integratePluginHooks( + pluginId: string, + plugin: InitPluginHook, + injectService: InjectableServices, + addWebRoutesFromPlugin: AddPluginWebRoutes, +): Promise { let injection: Injection | null = null let hooks: PluginHooks if (plugin.inject) { @@ -32,6 +37,6 @@ export async function integratePluginHooks(pluginId: string, plugin: InitPluginH await loadIconsHooks(pluginId, hooks, injectService(StaticIconRepositoryToken)) await loadFeedsHooks(pluginId, hooks, injectService(FeedServiceTypeRepositoryToken)) if (hooks.webRoutes) { - await addWebRoutesFromPlugin(pluginId, hooks.webRoutes) + await addWebRoutesFromPlugin(pluginId, hooks) } } diff --git a/service/src/plugins.api/plugins.api.web.ts b/service/src/plugins.api/plugins.api.web.ts index 63b0cd139..a1382d4de 100644 --- a/service/src/plugins.api/plugins.api.web.ts +++ b/service/src/plugins.api/plugins.api.web.ts @@ -6,6 +6,9 @@ export interface GetAppRequestContext { (req: express.Request): AppRequestContext } -export interface WebRoutesHooks { - webRoutes(requestContext: GetAppRequestContext): express.Router -} +export type WebRoutesHooks = { + webRoutes: { + public?: (requestContext: GetAppRequestContext) => express.Router, + protected?: (requestContext: GetAppRequestContext) => express.Router + } +} \ No newline at end of file diff --git a/service/test/app/systemInfo/app.systemInfo.test.ts b/service/test/app/systemInfo/app.systemInfo.test.ts index 49a08d01d..4daa97625 100644 --- a/service/test/app/systemInfo/app.systemInfo.test.ts +++ b/service/test/app/systemInfo/app.systemInfo.test.ts @@ -124,7 +124,7 @@ describe('CreateReadSystemInfo', () => { .getSetting('disclaimer') .returns(Promise.resolve(mockDisclaimer as any)); mockedSettingsModule - .getSetting('contactInfo') + .getSetting('contactinfo') .returns(Promise.resolve(mockContactInfo as any)); mockedAuthConfigModule.getAllConfigurations().returns(Promise.resolve([])); mockedAuthConfigTransformerModule.transform(Arg.any()).returns([]); diff --git a/service/test/main/main.plugins.test.ts b/service/test/main/main.plugins.test.ts index da63c6a1b..906368109 100644 --- a/service/test/main/main.plugins.test.ts +++ b/service/test/main/main.plugins.test.ts @@ -18,7 +18,7 @@ class Service1Impl implements Service1 {} class Service2Impl implements Service2 {} const serviceMap = new Map([[ Service1Token, new Service1Impl() ], [ Service2Token, new Service2Impl() ]]) const injectService: plugins.InjectableServices = (token: any) => serviceMap.get(token) as any -const initPluginRoutes: AddPluginWebRoutes = (pluginId: string, initPluginRoutes: WebRoutesHooks['webRoutes']) => void(0) +const initPluginRoutes: AddPluginWebRoutes = (pluginId: string, initPluginRoutes: WebRoutesHooks) => void(0) interface InjectServiceHandle { injectService: typeof injectService @@ -71,7 +71,13 @@ describe('loading plugins', function() { service2: Service2Token } const routes = express.Router() - const hook: WebRoutesHooks['webRoutes'] = (appRequestContext: (req: express.Request) => AppRequestContext) => routes + const hook = { + webRoutes: { + public: (appRequestContext: (req: express.Request) => AppRequestContext) => routes, + protected: (appRequestContext: (req: express.Request) => AppRequestContext) => routes + } + } + let injected: any = null const initPlugin: InitPluginHook = { inject: { @@ -79,9 +85,7 @@ describe('loading plugins', function() { }, init: async (services): Promise => { injected = services - return { - webRoutes: hook - } + return hook } } initPlugin.inject = injectRequest