diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index 708b9b1bdbea5..e09cee8c3c7c2 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -29,7 +29,6 @@ import { ReportingConfig, ReportingSetup } from './'; import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factory'; import { ReportingConfigType } from './config'; import { checkLicense, getExportTypesRegistry, LevelLogger } from './lib'; -import { screenshotsObservableFactory, ScreenshotsObservableFn } from './lib/screenshots'; import { ReportingStore } from './lib/store'; import { ExecuteReportTask, MonitorReportsTask, ReportTaskParams } from './lib/tasks'; import { ReportingPluginRouter } from './types'; @@ -237,12 +236,6 @@ export class ReportingCore { .toPromise(); } - public async getScreenshotsObservable(): Promise { - const config = this.getConfig(); - const { browserDriverFactory } = await this.getPluginStartDeps(); - return screenshotsObservableFactory(config.get('capture'), browserDriverFactory); - } - public getEnableScreenshotMode() { const { screenshotMode } = this.getPluginSetupDeps(); return screenshotMode.setScreenshotModeEnabled; diff --git a/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts b/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts index 12815cf1b25a4..2af56ed9881ae 100644 --- a/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts +++ b/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts @@ -11,7 +11,7 @@ import { finalize, map, tap } from 'rxjs/operators'; import { ReportingCore } from '../../../'; import { LevelLogger } from '../../../lib'; import { LayoutParams, PreserveLayout } from '../../../lib/layouts'; -import { ScreenshotResults } from '../../../lib/screenshots'; +import { getScreenshots$, ScreenshotResults } from '../../../lib/screenshots'; import { ConditionalHeaders } from '../../common'; function getBase64DecodedSize(value: string) { @@ -24,7 +24,9 @@ function getBase64DecodedSize(value: string) { } export async function generatePngObservableFactory(reporting: ReportingCore) { - const getScreenshots = await reporting.getScreenshotsObservable(); + const config = reporting.getConfig(); + const captureConfig = config.get('capture'); + const { browserDriverFactory } = await reporting.getPluginStartDeps(); return function generatePngObservable( logger: LevelLogger, @@ -43,7 +45,7 @@ export async function generatePngObservableFactory(reporting: ReportingCore) { const apmScreenshots = apmTrans?.startSpan('screenshots_pipeline', 'setup'); let apmBuffer: typeof apm.currentSpan; - const screenshots$ = getScreenshots({ + const screenshots$ = getScreenshots$(captureConfig, browserDriverFactory, { logger, urls: [url], conditionalHeaders, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/lib/generate_pdf.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/lib/generate_pdf.ts index 9b1a1820b002a..88b9f8dc95b94 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/lib/generate_pdf.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/lib/generate_pdf.ts @@ -11,7 +11,7 @@ import { mergeMap } from 'rxjs/operators'; import { ReportingCore } from '../../../'; import { LevelLogger } from '../../../lib'; import { createLayout, LayoutParams } from '../../../lib/layouts'; -import { ScreenshotResults } from '../../../lib/screenshots'; +import { getScreenshots$, ScreenshotResults } from '../../../lib/screenshots'; import { ConditionalHeaders } from '../../common'; import { PdfMaker } from './pdf'; import { getTracker } from './tracker'; @@ -29,7 +29,7 @@ const getTimeRange = (urlScreenshots: ScreenshotResults[]) => { export async function generatePdfObservableFactory(reporting: ReportingCore) { const config = reporting.getConfig(); const captureConfig = config.get('capture'); - const getScreenshots = await reporting.getScreenshotsObservable(); + const { browserDriverFactory } = await reporting.getPluginStartDeps(); return function generatePdfObservable( logger: LevelLogger, @@ -48,7 +48,7 @@ export async function generatePdfObservableFactory(reporting: ReportingCore) { tracker.endLayout(); tracker.startScreenshots(); - const screenshots$ = getScreenshots({ + const screenshots$ = getScreenshots$(captureConfig, browserDriverFactory, { logger, urls, conditionalHeaders, diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts index abfa2b88258fc..8cfea1b010dfe 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.test.ts @@ -16,7 +16,7 @@ import { } from '../test_helpers'; import { ReportingRequestHandlerContext } from '../types'; import { ExportTypesRegistry, ReportingStore } from './'; -import { enqueueJobFactory } from './enqueue_job'; +import { enqueueJob } from './enqueue_job'; import { Report } from './store'; describe('Enqueue Job', () => { @@ -72,13 +72,14 @@ describe('Enqueue Job', () => { }); it('returns a Report object', async () => { - const enqueueJob = enqueueJobFactory(mockReporting, logger); const report = await enqueueJob( + mockReporting, + ({} as unknown) as KibanaRequest, + ({} as unknown) as ReportingRequestHandlerContext, + false, 'printablePdf', mockBaseParams, - false, - ({} as unknown) as ReportingRequestHandlerContext, - ({} as unknown) as KibanaRequest + logger ); const { _id, created_at: _created_at, ...snapObj } = report; @@ -117,14 +118,15 @@ describe('Enqueue Job', () => { }); it('provides a default kibana version field for older POST URLs', async () => { - const enqueueJob = enqueueJobFactory(mockReporting, logger); mockBaseParams.version = undefined; const report = await enqueueJob( + mockReporting, + ({} as unknown) as KibanaRequest, + ({} as unknown) as ReportingRequestHandlerContext, + false, 'printablePdf', mockBaseParams, - false, - ({} as unknown) as ReportingRequestHandlerContext, - ({} as unknown) as KibanaRequest + logger ); const { _id, created_at: _created_at, ...snapObj } = report; diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.ts index 1c73b0d925ad0..998e4edf26a38 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.ts @@ -12,64 +12,53 @@ import { BaseParams, ReportingUser } from '../types'; import { checkParamsVersion, LevelLogger } from './'; import { Report } from './store'; -export type EnqueueJobFn = ( +export async function enqueueJob( + reporting: ReportingCore, + request: KibanaRequest, + context: ReportingRequestHandlerContext, + user: ReportingUser, exportTypeId: string, jobParams: BaseParams, - user: ReportingUser, - context: ReportingRequestHandlerContext, - request: KibanaRequest -) => Promise; - -export function enqueueJobFactory( - reporting: ReportingCore, parentLogger: LevelLogger -): EnqueueJobFn { +): Promise { const logger = parentLogger.clone(['createJob']); - return async function enqueueJob( - exportTypeId: string, - jobParams: BaseParams, - user: ReportingUser, - context: ReportingRequestHandlerContext, - request: KibanaRequest - ) { - const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); + const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); - if (exportType == null) { - throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); - } + if (exportType == null) { + throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); + } - if (!exportType.createJobFnFactory) { - throw new Error(`Export type ${exportTypeId} is not an async job type!`); - } + if (!exportType.createJobFnFactory) { + throw new Error(`Export type ${exportTypeId} is not an async job type!`); + } - const [createJob, store] = await Promise.all([ - exportType.createJobFnFactory(reporting, logger.clone([exportType.id])), - reporting.getStore(), - ]); + const [createJob, store] = await Promise.all([ + exportType.createJobFnFactory(reporting, logger.clone([exportType.id])), + reporting.getStore(), + ]); - jobParams.version = checkParamsVersion(jobParams, logger); - const job = await createJob!(jobParams, context, request); + jobParams.version = checkParamsVersion(jobParams, logger); + const job = await createJob!(jobParams, context, request); - // 1. Add the report to ReportingStore to show as pending - const report = await store.addReport( - new Report({ - jobtype: exportType.jobType, - created_by: user ? user.username : false, - payload: job, - meta: { - objectType: jobParams.objectType, - layout: jobParams.layout?.id, - }, - }) - ); - logger.debug(`Successfully stored pending job: ${report._index}/${report._id}`); + // 1. Add the report to ReportingStore to show as pending + const report = await store.addReport( + new Report({ + jobtype: exportType.jobType, + created_by: user ? user.username : false, + payload: job, + meta: { + objectType: jobParams.objectType, + layout: jobParams.layout?.id, + }, + }) + ); + logger.debug(`Successfully stored pending job: ${report._index}/${report._id}`); - // 2. Schedule the report with Task Manager - const task = await reporting.scheduleTask(report.toReportTaskJSON()); - logger.info( - `Scheduled ${exportType.name} reporting task. Task ID: task:${task.id}. Report ID: ${report._id}` - ); + // 2. Schedule the report with Task Manager + const task = await reporting.scheduleTask(report.toReportTaskJSON()); + logger.info( + `Scheduled ${exportType.name} reporting task. Task ID: task:${task.id}. Report ID: ${report._id}` + ); - return report; - }; + return report; } diff --git a/x-pack/plugins/reporting/server/lib/screenshots/index.ts b/x-pack/plugins/reporting/server/lib/screenshots/index.ts index d924b45c1e016..d5ef52d627c6b 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/index.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/index.ts @@ -5,12 +5,11 @@ * 2.0. */ -import * as Rx from 'rxjs'; import { LevelLogger } from '../'; import { ConditionalHeaders } from '../../export_types/common'; import { LayoutInstance } from '../layouts'; -export { screenshotsObservableFactory } from './observable'; +export { getScreenshots$ } from './observable'; export interface ScreenshotObservableOpts { logger: LevelLogger; @@ -55,11 +54,3 @@ export interface ScreenshotResults { error?: Error; elementsPositionAndAttributes?: ElementsPositionAndAttribute[]; // NOTE: for testing } - -export type ScreenshotsObservableFn = ({ - logger, - urls, - conditionalHeaders, - layout, - browserTimezone, -}: ScreenshotObservableOpts) => Rx.Observable; diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts index dd8aadb49a5ba..7458340a4a52f 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable.test.ts @@ -32,7 +32,7 @@ import { } from '../../test_helpers'; import { ElementsPositionAndAttribute } from './'; import * as contexts from './constants'; -import { screenshotsObservableFactory } from './observable'; +import { getScreenshots$ } from './'; /* * Mocks @@ -67,8 +67,7 @@ describe('Screenshot Observable Pipeline', () => { }); it('pipelines a single url into screenshot and timeRange', async () => { - const getScreenshots$ = screenshotsObservableFactory(captureConfig, mockBrowserDriverFactory); - const result = await getScreenshots$({ + const result = await getScreenshots$(captureConfig, mockBrowserDriverFactory, { logger, urls: ['/welcome/home/start/index.htm'], conditionalHeaders: {} as ConditionalHeaders, @@ -128,8 +127,7 @@ describe('Screenshot Observable Pipeline', () => { }); // test - const getScreenshots$ = screenshotsObservableFactory(captureConfig, mockBrowserDriverFactory); - const result = await getScreenshots$({ + const result = await getScreenshots$(captureConfig, mockBrowserDriverFactory, { logger, urls: ['/welcome/home/start/index2.htm', '/welcome/home/start/index.php3?page=./home.php'], conditionalHeaders: {} as ConditionalHeaders, @@ -227,9 +225,8 @@ describe('Screenshot Observable Pipeline', () => { }); // test - const getScreenshots$ = screenshotsObservableFactory(captureConfig, mockBrowserDriverFactory); const getScreenshot = async () => { - return await getScreenshots$({ + return await getScreenshots$(captureConfig, mockBrowserDriverFactory, { logger, urls: [ '/welcome/home/start/index2.htm', @@ -322,9 +319,8 @@ describe('Screenshot Observable Pipeline', () => { }); // test - const getScreenshots$ = screenshotsObservableFactory(captureConfig, mockBrowserDriverFactory); const getScreenshot = async () => { - return await getScreenshots$({ + return await getScreenshots$(captureConfig, mockBrowserDriverFactory, { logger, urls: ['/welcome/home/start/index.php3?page=./home.php3'], conditionalHeaders: {} as ConditionalHeaders, @@ -354,50 +350,46 @@ describe('Screenshot Observable Pipeline', () => { }); mockLayout.getViewport = () => null; - // test - const getScreenshots$ = screenshotsObservableFactory(captureConfig, mockBrowserDriverFactory); - const getScreenshot = async () => { - return await getScreenshots$({ - logger, - urls: ['/welcome/home/start/index.php3?page=./home.php3'], - conditionalHeaders: {} as ConditionalHeaders, - layout: mockLayout, - browserTimezone: 'UTC', - }).toPromise(); - }; + const screenshots = await getScreenshots$(captureConfig, mockBrowserDriverFactory, { + logger, + urls: ['/welcome/home/start/index.php3?page=./home.php3'], + conditionalHeaders: {} as ConditionalHeaders, + layout: mockLayout, + browserTimezone: 'UTC', + }).toPromise(); - await expect(getScreenshot()).resolves.toMatchInlineSnapshot(` - Array [ - Object { - "elementsPositionAndAttributes": Array [ - Object { - "attributes": Object {}, - "position": Object { - "boundingClientRect": Object { - "height": 1200, - "left": 0, - "top": 0, - "width": 1800, - }, - "scroll": Object { - "x": 0, - "y": 0, - }, - }, - }, - ], - "error": undefined, - "screenshots": Array [ - Object { - "base64EncodedData": "allyourBase64", - "description": undefined, - "title": undefined, - }, - ], - "timeRange": undefined, + expect(screenshots).toMatchInlineSnapshot(` + Array [ + Object { + "elementsPositionAndAttributes": Array [ + Object { + "attributes": Object {}, + "position": Object { + "boundingClientRect": Object { + "height": 1200, + "left": 0, + "top": 0, + "width": 1800, + }, + "scroll": Object { + "x": 0, + "y": 0, + }, }, - ] - `); + }, + ], + "error": undefined, + "screenshots": Array [ + Object { + "base64EncodedData": "allyourBase64", + "description": undefined, + "title": undefined, + }, + ], + "timeRange": undefined, + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/reporting/server/lib/screenshots/observable.ts b/x-pack/plugins/reporting/server/lib/screenshots/observable.ts index 3692678064415..baaf8a4fb38ee 100644 --- a/x-pack/plugins/reporting/server/lib/screenshots/observable.ts +++ b/x-pack/plugins/reporting/server/lib/screenshots/observable.ts @@ -10,12 +10,7 @@ import * as Rx from 'rxjs'; import { catchError, concatMap, first, mergeMap, take, takeUntil, toArray } from 'rxjs/operators'; import { HeadlessChromiumDriverFactory } from '../../browsers'; import { CaptureConfig } from '../../types'; -import { - ElementsPositionAndAttribute, - ScreenshotObservableOpts, - ScreenshotResults, - ScreenshotsObservableFn, -} from './'; +import { ElementsPositionAndAttribute, ScreenshotObservableOpts, ScreenshotResults } from './'; import { checkPageIsOpen } from './check_browser_open'; import { DEFAULT_PAGELOAD_SELECTOR } from './constants'; import { getElementPositionAndAttributes } from './get_element_position_data'; @@ -36,117 +31,110 @@ interface ScreenSetupData { error?: Error; } -export function screenshotsObservableFactory( +export function getScreenshots$( captureConfig: CaptureConfig, - browserDriverFactory: HeadlessChromiumDriverFactory -): ScreenshotsObservableFn { - return function screenshotsObservable({ - logger, - urls, - conditionalHeaders, - layout, - browserTimezone, - }: ScreenshotObservableOpts): Rx.Observable { - const apmTrans = apm.startTransaction(`reporting screenshot pipeline`, 'reporting'); + browserDriverFactory: HeadlessChromiumDriverFactory, + { logger, urls, conditionalHeaders, layout, browserTimezone }: ScreenshotObservableOpts +): Rx.Observable { + const apmTrans = apm.startTransaction(`reporting screenshot pipeline`, 'reporting'); - const apmCreatePage = apmTrans?.startSpan('create_page', 'wait'); - const create$ = browserDriverFactory.createPage( - { viewport: layout.getBrowserViewport(), browserTimezone }, - logger - ); + const apmCreatePage = apmTrans?.startSpan('create_page', 'wait'); + const create$ = browserDriverFactory.createPage( + { viewport: layout.getBrowserViewport(), browserTimezone }, + logger + ); - return create$.pipe( - mergeMap(({ driver, exit$ }) => { - apmCreatePage?.end(); - exit$.subscribe({ error: () => apmTrans?.end() }); + return create$.pipe( + mergeMap(({ driver, exit$ }) => { + apmCreatePage?.end(); + exit$.subscribe({ error: () => apmTrans?.end() }); - return Rx.from(urls).pipe( - concatMap((url, index) => { - const setup$: Rx.Observable = Rx.of(1).pipe( - mergeMap(() => { - // If we're moving to another page in the app, we'll want to wait for the app to tell us - // it's loaded the next page. - const page = index + 1; - const pageLoadSelector = - page > 1 ? `[data-shared-page="${page}"]` : DEFAULT_PAGELOAD_SELECTOR; + return Rx.from(urls).pipe( + concatMap((url, index) => { + const setup$: Rx.Observable = Rx.of(1).pipe( + mergeMap(() => { + // If we're moving to another page in the app, we'll want to wait for the app to tell us + // it's loaded the next page. + const page = index + 1; + const pageLoadSelector = + page > 1 ? `[data-shared-page="${page}"]` : DEFAULT_PAGELOAD_SELECTOR; - return openUrl( - captureConfig, - driver, - url, - pageLoadSelector, - conditionalHeaders, - logger - ); - }), - mergeMap(() => getNumberOfItems(captureConfig, driver, layout, logger)), - mergeMap(async (itemsCount) => { - // set the viewport to the dimentions from the job, to allow elements to flow into the expected layout - const viewport = layout.getViewport(itemsCount) || getDefaultViewPort(); - await Promise.all([ - driver.setViewport(viewport, logger), - waitForVisualizations(captureConfig, driver, itemsCount, layout, logger), - ]); - }), - mergeMap(async () => { - // Waiting till _after_ elements have rendered before injecting our CSS - // allows for them to be displayed properly in many cases - await injectCustomCss(driver, layout, logger); + return openUrl( + captureConfig, + driver, + url, + pageLoadSelector, + conditionalHeaders, + logger + ); + }), + mergeMap(() => getNumberOfItems(captureConfig, driver, layout, logger)), + mergeMap(async (itemsCount) => { + // set the viewport to the dimentions from the job, to allow elements to flow into the expected layout + const viewport = layout.getViewport(itemsCount) || getDefaultViewPort(); + await Promise.all([ + driver.setViewport(viewport, logger), + waitForVisualizations(captureConfig, driver, itemsCount, layout, logger), + ]); + }), + mergeMap(async () => { + // Waiting till _after_ elements have rendered before injecting our CSS + // allows for them to be displayed properly in many cases + await injectCustomCss(driver, layout, logger); - const apmPositionElements = apmTrans?.startSpan('position_elements', 'correction'); - if (layout.positionElements) { - // position panel elements for print layout - await layout.positionElements(driver, logger); - } - if (apmPositionElements) apmPositionElements.end(); + const apmPositionElements = apmTrans?.startSpan('position_elements', 'correction'); + if (layout.positionElements) { + // position panel elements for print layout + await layout.positionElements(driver, logger); + } + if (apmPositionElements) apmPositionElements.end(); - await waitForRenderComplete(captureConfig, driver, layout, logger); - }), - mergeMap(async () => { - return await Promise.all([ - getTimeRange(driver, layout, logger), - getElementPositionAndAttributes(driver, layout, logger), - ]).then(([timeRange, elementsPositionAndAttributes]) => ({ - elementsPositionAndAttributes, - timeRange, - })); - }), - catchError((err) => { - checkPageIsOpen(driver); // if browser has closed, throw a relevant error about it + await waitForRenderComplete(captureConfig, driver, layout, logger); + }), + mergeMap(async () => { + return await Promise.all([ + getTimeRange(driver, layout, logger), + getElementPositionAndAttributes(driver, layout, logger), + ]).then(([timeRange, elementsPositionAndAttributes]) => ({ + elementsPositionAndAttributes, + timeRange, + })); + }), + catchError((err) => { + checkPageIsOpen(driver); // if browser has closed, throw a relevant error about it - logger.error(err); - return Rx.of({ elementsPositionAndAttributes: null, timeRange: null, error: err }); - }) - ); + logger.error(err); + return Rx.of({ elementsPositionAndAttributes: null, timeRange: null, error: err }); + }) + ); - return setup$.pipe( - takeUntil(exit$), - mergeMap( - async (data: ScreenSetupData): Promise => { - checkPageIsOpen(driver); // re-check that the browser has not closed + return setup$.pipe( + takeUntil(exit$), + mergeMap( + async (data: ScreenSetupData): Promise => { + checkPageIsOpen(driver); // re-check that the browser has not closed - const elements = data.elementsPositionAndAttributes - ? data.elementsPositionAndAttributes - : getDefaultElementPosition(layout.getViewport(1)); - const screenshots = await getScreenshots(driver, layout, elements, logger); - const { timeRange, error: setupError } = data; - return { - timeRange, - screenshots, - error: setupError, - elementsPositionAndAttributes: elements, - }; - } - ) - ); - }), - take(urls.length), - toArray() - ); - }), - first() - ); - }; + const elements = data.elementsPositionAndAttributes + ? data.elementsPositionAndAttributes + : getDefaultElementPosition(layout.getViewport(1)); + const screenshots = await getScreenshots(driver, layout, elements, logger); + const { timeRange, error: setupError } = data; + return { + timeRange, + screenshots, + error: setupError, + elementsPositionAndAttributes: elements, + }; + } + ) + ); + }), + take(urls.length), + toArray() + ); + }), + first() + ); } /* diff --git a/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts b/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts index 3d482d4f84d52..57324830af4a0 100644 --- a/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts +++ b/x-pack/plugins/reporting/server/routes/csv_searchsource_immediate.ts @@ -13,7 +13,7 @@ import { runTaskFnFactory } from '../export_types/csv_searchsource_immediate/exe import { JobParamsDownloadCSV } from '../export_types/csv_searchsource_immediate/types'; import { LevelLogger as Logger } from '../lib'; import { TaskRunResult } from '../lib/tasks'; -import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from './lib/authorized_user_pre_routing'; import { HandlerErrorFunction } from './types'; const API_BASE_URL_V1 = '/api/reporting/v1'; @@ -36,7 +36,6 @@ export function registerGenerateCsvFromSavedObjectImmediate( parentLogger: Logger ) { const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; // TODO: find a way to abstract this using ExportTypeRegistry: it needs a new @@ -63,47 +62,50 @@ export function registerGenerateCsvFromSavedObjectImmediate( tags: kibanaAccessControlTags, }, }, - userHandler(async (_user, context, req: CsvFromSavedObjectRequest, res) => { - const logger = parentLogger.clone(['csv_searchsource_immediate']); - const runTaskFn = runTaskFnFactory(reporting, logger); + authorizedUserPreRouting( + reporting, + async (_user, context, req: CsvFromSavedObjectRequest, res) => { + const logger = parentLogger.clone(['csv_searchsource_immediate']); + const runTaskFn = runTaskFnFactory(reporting, logger); - try { - let buffer = Buffer.from(''); - const stream = new Writable({ - write(chunk, encoding, callback) { - buffer = Buffer.concat([ - buffer, - Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding), - ]); - callback(); - }, - }); + try { + let buffer = Buffer.from(''); + const stream = new Writable({ + write(chunk, encoding, callback) { + buffer = Buffer.concat([ + buffer, + Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding), + ]); + callback(); + }, + }); - const { - content_type: jobOutputContentType, - size: jobOutputSize, - }: TaskRunResult = await runTaskFn(null, req.body, context, stream, req); - stream.end(); - const jobOutputContent = buffer.toString(); + const { + content_type: jobOutputContentType, + size: jobOutputSize, + }: TaskRunResult = await runTaskFn(null, req.body, context, stream, req); + stream.end(); + const jobOutputContent = buffer.toString(); - logger.info(`Job output size: ${jobOutputSize} bytes`); + logger.info(`Job output size: ${jobOutputSize} bytes`); - // convert null to undefined so the value can be sent to h.response() - if (jobOutputContent === null) { - logger.warn('CSV Job Execution created empty content result'); - } + // convert null to undefined so the value can be sent to h.response() + if (jobOutputContent === null) { + logger.warn('CSV Job Execution created empty content result'); + } - return res.ok({ - body: jobOutputContent || '', - headers: { - 'content-type': jobOutputContentType ? jobOutputContentType : [], - 'accept-ranges': 'none', - }, - }); - } catch (err) { - logger.error(err); - return handleError(res, err); + return res.ok({ + body: jobOutputContent || '', + headers: { + 'content-type': jobOutputContentType ? jobOutputContentType : [], + 'accept-ranges': 'none', + }, + }); + } catch (err) { + logger.error(err); + return handleError(res, err); + } } - }) + ) ); } diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts b/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts index 25e60c65676d7..268cabd9be55f 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts @@ -10,7 +10,7 @@ import { ReportingCore } from '../..'; import { API_DIAGNOSE_URL } from '../../../common/constants'; import { browserStartLogs } from '../../browsers/chromium/driver_factory/start_logs'; import { LevelLogger as Logger } from '../../lib'; -import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from '../lib/authorized_user_pre_routing'; import { DiagnosticResponse } from './'; const logsToHelpMap = { @@ -47,14 +47,13 @@ const logsToHelpMap = { export const registerDiagnoseBrowser = (reporting: ReportingCore, logger: Logger) => { const { router } = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); router.post( { path: `${API_DIAGNOSE_URL}/browser`, validate: {}, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (_user, _context, _req, res) => { try { const logs = await browserStartLogs(reporting, logger).toPromise(); const knownIssues = Object.keys(logsToHelpMap) as Array; diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/config.ts b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts index 109849aa302f2..93677409693f8 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/config.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts @@ -11,7 +11,7 @@ import { defaults, get } from 'lodash'; import { ReportingCore } from '../..'; import { API_DIAGNOSE_URL } from '../../../common/constants'; import { LevelLogger as Logger } from '../../lib'; -import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from '../lib/authorized_user_pre_routing'; import { DiagnosticResponse } from './'; const KIBANA_MAX_SIZE_BYTES_PATH = 'csv.maxSizeBytes'; @@ -27,7 +27,6 @@ const numberToByteSizeValue = (value: number | ByteSizeValue) => { export const registerDiagnoseConfig = (reporting: ReportingCore, logger: Logger) => { const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; router.post( @@ -35,7 +34,7 @@ export const registerDiagnoseConfig = (reporting: ReportingCore, logger: Logger) path: `${API_DIAGNOSE_URL}/config`, validate: {}, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (_user, _context, _req, res) => { const warnings = []; const { asInternalUser: elasticsearchClient } = await reporting.getEsClient(); const config = reporting.getConfig(); diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts index 7405e8cff8975..765e0a2a4e8a2 100644 --- a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts +++ b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts @@ -13,12 +13,11 @@ import { omitBlockedHeaders } from '../../export_types/common'; import { getAbsoluteUrlFactory } from '../../export_types/common/get_absolute_url'; import { generatePngObservableFactory } from '../../export_types/png/lib/generate_png'; import { LevelLogger as Logger } from '../../lib'; -import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from '../lib/authorized_user_pre_routing'; import { DiagnosticResponse } from './'; export const registerDiagnoseScreenshot = (reporting: ReportingCore, logger: Logger) => { const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; router.post( @@ -26,7 +25,7 @@ export const registerDiagnoseScreenshot = (reporting: ReportingCore, logger: Log path: `${API_DIAGNOSE_URL}/screenshot`, validate: {}, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (_user, _context, req, res) => { const generatePngObservable = await generatePngObservableFactory(reporting); const config = reporting.getConfig(); const decryptedHeaders = req.headers as Record; diff --git a/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts b/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts index 69b3f216886e6..c519616cda5fb 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts +++ b/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts @@ -10,7 +10,7 @@ import rison from 'rison-node'; import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; import { BaseParams } from '../types'; -import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from './lib/authorized_user_pre_routing'; import { HandlerErrorFunction, HandlerFunction } from './types'; const BASE_GENERATE = `${API_BASE_URL}/generate`; @@ -21,7 +21,6 @@ export function registerGenerateFromJobParams( handleError: HandlerErrorFunction ) { const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; // TODO: find a way to abstract this using ExportTypeRegistry: it needs a new @@ -41,7 +40,7 @@ export function registerGenerateFromJobParams( }, options: { tags: kibanaAccessControlTags }, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (user, context, req, res) => { let jobParamsRison: null | string = null; if (req.body) { diff --git a/x-pack/plugins/reporting/server/routes/generation.ts b/x-pack/plugins/reporting/server/routes/generation.ts index ce6d1a2f2641f..4082084c82fbc 100644 --- a/x-pack/plugins/reporting/server/routes/generation.ts +++ b/x-pack/plugins/reporting/server/routes/generation.ts @@ -10,7 +10,7 @@ import { kibanaResponseFactory } from 'src/core/server'; import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; import { LevelLogger as Logger } from '../lib'; -import { enqueueJobFactory } from '../lib/enqueue_job'; +import { enqueueJob } from '../lib/enqueue_job'; import { registerGenerateFromJobParams } from './generate_from_jobparams'; import { registerGenerateCsvFromSavedObjectImmediate } from './csv_searchsource_immediate'; import { HandlerFunction } from './types'; @@ -42,8 +42,15 @@ export function registerJobGenerationRoutes(reporting: ReportingCore, logger: Lo } try { - const enqueueJob = enqueueJobFactory(reporting, logger); - const report = await enqueueJob(exportTypeId, jobParams, user, context, req); + const report = await enqueueJob( + reporting, + req, + context, + user, + exportTypeId, + jobParams, + logger + ); // return task manager's task information and the download URL const downloadBaseUrl = getDownloadBaseUrl(reporting); diff --git a/x-pack/plugins/reporting/server/routes/jobs.ts b/x-pack/plugins/reporting/server/routes/jobs.ts index 37557c3afb0c7..ad0aac121106c 100644 --- a/x-pack/plugins/reporting/server/routes/jobs.ts +++ b/x-pack/plugins/reporting/server/routes/jobs.ts @@ -10,12 +10,9 @@ import Boom from '@hapi/boom'; import { ROUTE_TAG_CAN_REDIRECT } from '../../../security/server'; import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; -import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; +import { authorizedUserPreRouting } from './lib/authorized_user_pre_routing'; import { jobsQueryFactory } from './lib/jobs_query'; -import { - deleteJobResponseHandlerFactory, - downloadJobResponseHandlerFactory, -} from './lib/job_response_handler'; +import { deleteJobResponseHandler, downloadJobResponseHandler } from './lib/job_response_handler'; const MAIN_ENTRY = `${API_BASE_URL}/jobs`; @@ -25,8 +22,8 @@ const handleUnavailable = (res: any) => { export function registerJobInfoRoutes(reporting: ReportingCore) { const setupDeps = reporting.getPluginSetupDeps(); - const userHandler = authorizedUserPreRoutingFactory(reporting); const { router } = setupDeps; + const jobsQuery = jobsQueryFactory(reporting); // list jobs in the queue, paginated router.get( @@ -40,7 +37,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { }), }, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (user, context, req, res) => { // ensure the async dependencies are loaded if (!context.reporting) { return handleUnavailable(res); @@ -53,7 +50,6 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { const page = parseInt(queryPage, 10) || 0; const size = Math.min(100, parseInt(querySize, 10) || 10); const jobIds = queryIds ? queryIds.split(',') : null; - const jobsQuery = jobsQueryFactory(reporting); const results = await jobsQuery.list(jobTypes, user, page, size, jobIds); return res.ok({ @@ -71,7 +67,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { path: `${MAIN_ENTRY}/count`, validate: false, }, - userHandler(async (user, context, _req, res) => { + authorizedUserPreRouting(reporting, async (user, context, _req, res) => { // ensure the async dependencies are loaded if (!context.reporting) { return handleUnavailable(res); @@ -81,7 +77,6 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); - const jobsQuery = jobsQueryFactory(reporting); const count = await jobsQuery.count(jobTypes, user); return res.ok({ @@ -103,7 +98,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { }), }, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (user, context, req, res) => { // ensure the async dependencies are loaded if (!context.reporting) { return res.custom({ statusCode: 503 }); @@ -114,7 +109,6 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); - const jobsQuery = jobsQueryFactory(reporting); const result = await jobsQuery.get(user, docId); if (!result) { @@ -137,8 +131,6 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { ); // trigger a download of the output from a job - const downloadResponseHandler = downloadJobResponseHandlerFactory(reporting); - router.get( { path: `${MAIN_ENTRY}/download/{docId}`, @@ -149,7 +141,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { }, options: { tags: [ROUTE_TAG_CAN_REDIRECT] }, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (user, context, req, res) => { // ensure the async dependencies are loaded if (!context.reporting) { return handleUnavailable(res); @@ -160,12 +152,11 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); - return downloadResponseHandler(res, jobTypes, user, { docId }); + return downloadJobResponseHandler(reporting, res, jobTypes, user, { docId }); }) ); // allow a report to be deleted - const deleteResponseHandler = deleteJobResponseHandlerFactory(reporting); router.delete( { path: `${MAIN_ENTRY}/delete/{docId}`, @@ -175,7 +166,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { }), }, }, - userHandler(async (user, context, req, res) => { + authorizedUserPreRouting(reporting, async (user, context, req, res) => { // ensure the async dependencies are loaded if (!context.reporting) { return handleUnavailable(res); @@ -186,7 +177,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); - return deleteResponseHandler(res, jobTypes, user, { docId }); + return deleteJobResponseHandler(reporting, res, jobTypes, user, { docId }); }) ); } diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts index 16ef9e6d5bc10..0cff81539e52e 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts @@ -11,7 +11,7 @@ import { ReportingCore } from '../../'; import { ReportingInternalSetup } from '../../core'; import { createMockConfigSchema, createMockReportingCore } from '../../test_helpers'; import type { ReportingRequestHandlerContext } from '../../types'; -import { authorizedUserPreRoutingFactory } from './authorized_user_pre_routing'; +import { authorizedUserPreRouting } from './authorized_user_pre_routing'; let mockCore: ReportingCore; const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } }); @@ -46,11 +46,10 @@ describe('authorized_user_pre_routing', function () { ...mockCore.pluginSetupDeps, security: undefined, // disable security } as unknown) as ReportingInternalSetup); - const authorizedUserPreRouting = authorizedUserPreRoutingFactory(mockCore); const mockResponseFactory = httpServerMock.createResponseFactory() as KibanaResponseFactory; let handlerCalled = false; - authorizedUserPreRouting((user: unknown) => { + authorizedUserPreRouting(mockCore, (user: unknown) => { expect(user).toBe(false); // verify the user is a false value handlerCalled = true; return Promise.resolve({ status: 200, options: {} }); @@ -70,11 +69,10 @@ describe('authorized_user_pre_routing', function () { }, }, // disable security } as unknown) as ReportingInternalSetup); - const authorizedUserPreRouting = authorizedUserPreRoutingFactory(mockCore); const mockResponseFactory = httpServerMock.createResponseFactory() as KibanaResponseFactory; let handlerCalled = false; - authorizedUserPreRouting((user: unknown) => { + authorizedUserPreRouting(mockCore, (user: unknown) => { expect(user).toBe(false); // verify the user is a false value handlerCalled = true; return Promise.resolve({ status: 200, options: {} }); @@ -93,11 +91,10 @@ describe('authorized_user_pre_routing', function () { authc: { getCurrentUser: () => null }, }, } as unknown) as ReportingInternalSetup); - const authorizedUserPreRouting = authorizedUserPreRoutingFactory(mockCore); const mockHandler = () => { throw new Error('Handler callback should not be called'); }; - const requestHandler = authorizedUserPreRouting(mockHandler); + const requestHandler = authorizedUserPreRouting(mockCore, mockHandler); const mockResponseFactory = getMockResponseFactory(); expect(requestHandler(getMockContext(), getMockRequest(), mockResponseFactory)).toMatchObject({ @@ -126,14 +123,13 @@ describe('authorized_user_pre_routing', function () { authc: { getCurrentUser: () => ({ username: 'friendlyuser', roles: ['cowboy'] }) }, }, } as unknown) as ReportingInternalSetup); - const authorizedUserPreRouting = authorizedUserPreRoutingFactory(mockCore); const mockResponseFactory = getMockResponseFactory(); const mockHandler = () => { throw new Error('Handler callback should not be called'); }; expect( - authorizedUserPreRouting(mockHandler)( + authorizedUserPreRouting(mockCore, mockHandler)( getMockContext(), getMockRequest(), mockResponseFactory @@ -153,10 +149,9 @@ describe('authorized_user_pre_routing', function () { }, }, } as unknown) as ReportingInternalSetup); - const authorizedUserPreRouting = authorizedUserPreRoutingFactory(mockCore); const mockResponseFactory = getMockResponseFactory(); - authorizedUserPreRouting((user) => { + authorizedUserPreRouting(mockCore, (user) => { expect(user).toMatchObject({ roles: ['reporting_user'], username: 'friendlyuser' }); done(); return Promise.resolve({ status: 200, options: {} }); diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts index 846d8c28a5378..2c6a01e615487 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts @@ -8,12 +8,13 @@ import { RequestHandler, RouteMethod } from 'src/core/server'; import { AuthenticatedUser } from '../../../../security/server'; import { ReportingCore } from '../../core'; -import { getUserFactory } from './get_user'; +import { getUser } from './get_user'; import type { ReportingRequestHandlerContext } from '../../types'; const superuserRole = 'superuser'; type ReportingRequestUser = AuthenticatedUser | false; + export type RequestHandlerUser = RequestHandler< P, Q, @@ -23,43 +24,40 @@ export type RequestHandlerUser = RequestHandler< ? (user: ReportingRequestUser, ...a: U) => R : never; -export const authorizedUserPreRoutingFactory = function authorizedUserPreRoutingFn( - reporting: ReportingCore -) { +export const authorizedUserPreRouting = ( + reporting: ReportingCore, + handler: RequestHandlerUser +): RequestHandler => { const { logger, security } = reporting.getPluginSetupDeps(); - const getUser = getUserFactory(security); - return ( - handler: RequestHandlerUser - ): RequestHandler => { - return (context, req, res) => { - try { - let user: ReportingRequestUser = false; - if (security && security.license.isEnabled()) { - // find the authenticated user, or null if security is not enabled - user = getUser(req); - if (!user) { - // security is enabled but the user is null - return res.unauthorized({ body: `Sorry, you aren't authenticated` }); - } + + return (context, req, res) => { + try { + let user: ReportingRequestUser = false; + if (security && security.license.isEnabled()) { + // find the authenticated user, or null if security is not enabled + user = getUser(req, security); + if (!user) { + // security is enabled but the user is null + return res.unauthorized({ body: `Sorry, you aren't authenticated` }); } + } - const deprecatedAllowedRoles = reporting.getDeprecatedAllowedRoles(); - if (user && deprecatedAllowedRoles !== false) { - // check allowance with the configured set of roleas + "superuser" - const allowedRoles = deprecatedAllowedRoles || []; - const authorizedRoles = [superuserRole, ...allowedRoles]; + const deprecatedAllowedRoles = reporting.getDeprecatedAllowedRoles(); + if (user && deprecatedAllowedRoles !== false) { + // check allowance with the configured set of roleas + "superuser" + const allowedRoles = deprecatedAllowedRoles || []; + const authorizedRoles = [superuserRole, ...allowedRoles]; - if (!user.roles.find((role) => authorizedRoles.includes(role))) { - // user's roles do not allow - return res.forbidden({ body: `Sorry, you don't have access to Reporting` }); - } + if (!user.roles.find((role) => authorizedRoles.includes(role))) { + // user's roles do not allow + return res.forbidden({ body: `Sorry, you don't have access to Reporting` }); } - - return handler(user, context, req, res); - } catch (err) { - logger.error(err); - return res.custom({ statusCode: 500 }); } - }; + + return handler(user, context, req, res); + } catch (err) { + logger.error(err); + return res.custom({ statusCode: 500 }); + } }; }; diff --git a/x-pack/plugins/reporting/server/routes/lib/get_user.ts b/x-pack/plugins/reporting/server/routes/lib/get_user.ts index 31d2009346b5e..cc5c97c7a3552 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_user.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_user.ts @@ -8,8 +8,6 @@ import { KibanaRequest } from 'kibana/server'; import { SecurityPluginSetup } from '../../../../security/server'; -export function getUserFactory(security?: SecurityPluginSetup) { - return (request: KibanaRequest) => { - return security?.authc.getCurrentUser(request) ?? false; - }; +export function getUser(request: KibanaRequest, security?: SecurityPluginSetup) { + return security?.authc.getCurrentUser(request) ?? false; } diff --git a/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts b/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts index 9f90be09bccbc..419f2e118f039 100644 --- a/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts +++ b/x-pack/plugins/reporting/server/routes/lib/job_response_handler.ts @@ -16,93 +16,85 @@ interface JobResponseHandlerParams { docId: string; } -interface JobResponseHandlerOpts { - excludeContent?: boolean; -} - -export function downloadJobResponseHandlerFactory(reporting: ReportingCore) { +export async function downloadJobResponseHandler( + reporting: ReportingCore, + res: typeof kibanaResponseFactory, + validJobTypes: string[], + user: ReportingUser, + params: JobResponseHandlerParams +) { const jobsQuery = jobsQueryFactory(reporting); const getDocumentPayload = getDocumentPayloadFactory(reporting); - - return async function jobResponseHandler( - res: typeof kibanaResponseFactory, - validJobTypes: string[], - user: ReportingUser, - params: JobResponseHandlerParams, - opts: JobResponseHandlerOpts = {} - ) { - try { - const { docId } = params; - - const doc = await jobsQuery.get(user, docId); - if (!doc) { - return res.notFound(); - } - - if (!validJobTypes.includes(doc.jobtype)) { - return res.unauthorized({ - body: `Sorry, you are not authorized to download ${doc.jobtype} reports`, - }); - } - - const payload = await getDocumentPayload(doc); - - if (!payload.contentType || !ALLOWED_JOB_CONTENT_TYPES.includes(payload.contentType)) { - return res.badRequest({ - body: `Unsupported content-type of ${payload.contentType} specified by job output`, - }); - } - - return res.custom({ - body: typeof payload.content === 'string' ? Buffer.from(payload.content) : payload.content, - statusCode: payload.statusCode, - headers: { - ...payload.headers, - 'content-type': payload.contentType || '', - }, - }); - } catch (err) { - const { logger } = reporting.getPluginSetupDeps(); - logger.error(err); - } - }; -} - -export function deleteJobResponseHandlerFactory(reporting: ReportingCore) { - const jobsQuery = jobsQueryFactory(reporting); - - return async function deleteJobResponseHander( - res: typeof kibanaResponseFactory, - validJobTypes: string[], - user: ReportingUser, - params: JobResponseHandlerParams - ) { + try { const { docId } = params; - const doc = await jobsQuery.get(user, docId); + const doc = await jobsQuery.get(user, docId); if (!doc) { return res.notFound(); } - const { jobtype: jobType } = doc; - - if (!validJobTypes.includes(jobType)) { + if (!validJobTypes.includes(doc.jobtype)) { return res.unauthorized({ - body: `Sorry, you are not authorized to delete ${jobType} reports`, + body: `Sorry, you are not authorized to download ${doc.jobtype} reports`, }); } - try { - const docIndex = doc.index; - await jobsQuery.delete(docIndex, docId); - return res.ok({ - body: { deleted: true }, - }); - } catch (error) { - return res.customError({ - statusCode: error.statusCode, - body: error.message, + const payload = await getDocumentPayload(doc); + + if (!payload.contentType || !ALLOWED_JOB_CONTENT_TYPES.includes(payload.contentType)) { + return res.badRequest({ + body: `Unsupported content-type of ${payload.contentType} specified by job output`, }); } - }; + + return res.custom({ + body: typeof payload.content === 'string' ? Buffer.from(payload.content) : payload.content, + statusCode: payload.statusCode, + headers: { + ...payload.headers, + 'content-type': payload.contentType || '', + }, + }); + } catch (err) { + const { logger } = reporting.getPluginSetupDeps(); + logger.error(err); + } +} + +export async function deleteJobResponseHandler( + reporting: ReportingCore, + res: typeof kibanaResponseFactory, + validJobTypes: string[], + user: ReportingUser, + params: JobResponseHandlerParams +) { + const jobsQuery = jobsQueryFactory(reporting); + + const { docId } = params; + const doc = await jobsQuery.get(user, docId); + + if (!doc) { + return res.notFound(); + } + + const { jobtype: jobType } = doc; + + if (!validJobTypes.includes(jobType)) { + return res.unauthorized({ + body: `Sorry, you are not authorized to delete ${jobType} reports`, + }); + } + + try { + const docIndex = doc.index; + await jobsQuery.delete(docIndex, docId); + return res.ok({ + body: { deleted: true }, + }); + } catch (error) { + return res.customError({ + statusCode: error.statusCode, + body: error.message, + }); + } }