From 9fda3f9c17a18a4b17164df419da1ed2659ea144 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 12 Sep 2019 17:59:56 -0700 Subject: [PATCH] [Reporting] Rewrite addForceNowQuerystring to getFullUrls (#44851) (#45205) * this is the one * this could break a job nbd * get_full_url to observe PNG and PDF job payload types * fix typescripts * fix ts in tests * fix more types * cosmetic * remove PDF execute compatibility shim test -- that stuff is handled in now PDF executeJob * fix unit test * remove old strings * Remove pdf execute compatibility shim entirely * combine the 2 maps * More reject matchers in the test --- .../add_force_now_query_string.test.ts | 93 ------------- .../execute_job/add_force_now_query_string.ts | 60 --------- .../execute_job/decrypt_job_headers.test.ts | 3 - .../get_conditional_headers.test.ts | 123 ++---------------- .../execute_job/get_custom_logo.test.ts | 21 +-- .../common/execute_job/get_custom_logo.ts | 5 +- .../common/execute_job/get_full_urls.test.ts | 104 +++++++++++++++ .../common/execute_job/get_full_urls.ts | 87 +++++++++++++ .../export_types/common/execute_job/index.ts | 2 +- .../server/create_job/create_job.ts | 1 - .../server/execute_job.ts | 13 +- .../server/lib/generate_csv.ts | 7 +- .../csv_from_savedobject/types.d.ts | 7 +- .../png/server/execute_job/index.js | 4 +- .../reporting/export_types/png/types.d.ts | 17 ++- .../server/execute_job/compatibility_shim.js | 44 ------- .../execute_job/compatibility_shim.test.js | 114 ---------------- .../printable_pdf/server/execute_job/index.js | 10 +- .../export_types/printable_pdf/types.d.ts | 16 ++- x-pack/legacy/plugins/reporting/types.d.ts | 5 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 22 files changed, 252 insertions(+), 486 deletions(-) delete mode 100644 x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts create mode 100644 x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts create mode 100644 x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.ts delete mode 100644 x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.js delete mode 100644 x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.test.js diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts deleted file mode 100644 index 117b72e59bf23..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.test.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { createMockServer } from '../../../test_helpers/create_mock_server'; -import { addForceNowQuerystring } from './index'; - -let mockServer: any; -beforeEach(() => { - mockServer = createMockServer(''); -}); - -test(`fails if no URL is passed`, async () => { - await expect( - addForceNowQuerystring({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, - server: mockServer, - }) - ).rejects.toBeDefined(); -}); - -test(`adds forceNow to hash's query, if it exists`, async () => { - const forceNow = '2000-01-01T00:00:00.000Z'; - const { urls } = await addForceNowQuerystring({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - relativeUrl: '/app/kibana#/something', - forceNow, - }, - server: mockServer, - }); - - expect(urls[0]).toEqual( - 'http://localhost:5601/sbp/app/kibana#/something?forceNow=2000-01-01T00%3A00%3A00.000Z' - ); -}); - -test(`appends forceNow to hash's query, if it exists`, async () => { - const forceNow = '2000-01-01T00:00:00.000Z'; - - const { urls } = await addForceNowQuerystring({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - relativeUrl: '/app/kibana#/something?_g=something', - forceNow, - }, - server: mockServer, - }); - - expect(urls[0]).toEqual( - 'http://localhost:5601/sbp/app/kibana#/something?_g=something&forceNow=2000-01-01T00%3A00%3A00.000Z' - ); -}); - -test(`doesn't append forceNow query to url, if it doesn't exists`, async () => { - const { urls } = await addForceNowQuerystring({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - relativeUrl: '/app/kibana#/something', - }, - server: mockServer, - }); - - expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something'); -}); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts deleted file mode 100644 index fda91c51ef0c2..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/add_force_now_query_string.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import url from 'url'; -import { getAbsoluteUrlFactory } from '../../../common/get_absolute_url'; -import { ConditionalHeaders, JobDocPayload, KbnServer } from '../../../types'; - -function getSavedObjectAbsoluteUrl(job: JobDocPayload, relativeUrl: string, server: KbnServer) { - const getAbsoluteUrl: any = getAbsoluteUrlFactory(server); - - const { pathname: path, hash, search } = url.parse(relativeUrl); - return getAbsoluteUrl({ basePath: job.basePath, path, hash, search }); -} - -export const addForceNowQuerystring = async ({ - job, - conditionalHeaders, - logo, - server, -}: { - job: JobDocPayload; - conditionalHeaders?: ConditionalHeaders; - logo?: any; - server: KbnServer; -}) => { - // if no URLS then its from PNG which should only have one so put it in the array and process as PDF does - if (!job.urls) { - if (!job.relativeUrl) { - throw new Error(`Unable to generate report. Url is not defined.`); - } - job.urls = [getSavedObjectAbsoluteUrl(job, job.relativeUrl, server)]; - } - - const urls = job.urls.map((jobUrl: string) => { - if (!job.forceNow) { - return jobUrl; - } - - const parsed: any = url.parse(jobUrl, true); - const hash: any = url.parse(parsed.hash.replace(/^#/, ''), true); - - const transformedHash = url.format({ - pathname: hash.pathname, - query: { - ...hash.query, - forceNow: job.forceNow, - }, - }); - - return url.format({ - ...parsed, - hash: transformedHash, - }); - }); - - return { job, conditionalHeaders, logo, urls, server }; -}; diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts index 7318beadd6a69..8c78143677214 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/decrypt_job_headers.test.ts @@ -31,8 +31,6 @@ describe('headers', () => { isImmediate: false, savedObjectType: 'search', }, - relativeUrl: '/app/kibana#/something', - timeRange: {}, }, server: mockServer, }) @@ -55,7 +53,6 @@ describe('headers', () => { isImmediate: false, savedObjectType: 'search', }, - relativeUrl: '/app/kibana#/something', headers: encryptedHeaders, }, server: mockServer, diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts index 768c25e548717..5a3c8d9f55f75 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_conditional_headers.test.ts @@ -6,6 +6,8 @@ import { createMockServer } from '../../../test_helpers/create_mock_server'; import { getConditionalHeaders, getCustomLogo } from './index'; +import { JobDocPayload } from '../../../types'; +import { JobDocPayloadPDF } from '../../printable_pdf/types'; let mockServer: any; beforeEach(() => { @@ -26,15 +28,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -51,15 +45,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -80,15 +66,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -105,15 +83,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -128,15 +98,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -159,15 +121,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -184,15 +138,7 @@ describe('conditions', () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -208,15 +154,7 @@ test('uses basePath from job when creating saved object service', async () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -226,16 +164,7 @@ test('uses basePath from job when creating saved object service', async () => { const jobBasePath = '/sbp/s/marketing'; await getCustomLogo({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - basePath: jobBasePath, - }, + job: { basePath: jobBasePath } as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); @@ -252,15 +181,7 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: permittedHeaders, server: mockServer, }); @@ -269,15 +190,7 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav mockServer.uiSettingsServiceFactory().get.mockReturnValue(logo); await getCustomLogo({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); @@ -291,15 +204,7 @@ describe('config formatting', () => { test(`lowercases server.host`, async () => { mockServer = createMockServer({ settings: { 'server.host': 'COOL-HOSTNAME' } }); const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayload, filteredHeaders: {}, server: mockServer, }); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts index 029b641bd73e5..4fca05337ea0c 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.test.ts @@ -6,6 +6,7 @@ import { createMockServer } from '../../../test_helpers/create_mock_server'; import { getConditionalHeaders, getCustomLogo } from './index'; +import { JobDocPayloadPDF } from '../../printable_pdf/types'; let mockServer: any; beforeEach(() => { @@ -19,29 +20,13 @@ test(`gets logo from uiSettings`, async () => { }; const { conditionalHeaders } = await getConditionalHeaders({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayloadPDF, filteredHeaders: permittedHeaders, server: mockServer, }); const { logo } = await getCustomLogo({ - job: { - title: 'cool-job-bro', - type: 'csv', - jobParams: { - savedObjectId: 'abc-123', - isImmediate: false, - savedObjectType: 'search', - }, - }, + job: {} as JobDocPayloadPDF, conditionalHeaders, server: mockServer, }); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts index b41e4c8218614..00cdd0410fac2 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_custom_logo.ts @@ -5,14 +5,15 @@ */ import { UI_SETTINGS_CUSTOM_PDF_LOGO } from '../../../common/constants'; -import { ConditionalHeaders, JobDocPayload, KbnServer } from '../../../types'; +import { ConditionalHeaders, KbnServer } from '../../../types'; +import { JobDocPayloadPDF } from '../../printable_pdf/types'; // Logo is PDF only export const getCustomLogo = async ({ job, conditionalHeaders, server, }: { - job: JobDocPayload; + job: JobDocPayloadPDF; conditionalHeaders: ConditionalHeaders; server: KbnServer; }) => { diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts new file mode 100644 index 0000000000000..d111b74eca927 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.test.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createMockServer } from '../../../test_helpers/create_mock_server'; +import { JobDocPayloadPNG } from '../../png/types'; +import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { getFullUrls } from './get_full_urls'; + +let mockServer: any; +beforeEach(() => { + mockServer = createMockServer(''); +}); + +test(`fails if no URL is passed`, async () => { + await expect( + getFullUrls({ + job: {} as JobDocPayloadPNG, + server: mockServer, + }) + ).rejects.toMatchInlineSnapshot( + `[Error: No valid URL fields found in Job Params! Expected \`job.relativeUrl\` or \`job.objects[{ relativeUrl }]\`]` + ); +}); + +test(`fails if URL does not route to a visualization`, async () => { + await expect( + getFullUrls({ + job: { + relativeUrl: '/app/phoney', + } as JobDocPayloadPNG, + server: mockServer, + }) + ).rejects.toMatchInlineSnapshot( + `[Error: No valid hash in the URL! A hash is expected for the application to route to the intended visualization.]` + ); +}); + +test(`adds forceNow to hash's query, if it exists`, async () => { + const forceNow = '2000-01-01T00:00:00.000Z'; + const { urls } = await getFullUrls({ + job: { + relativeUrl: '/app/kibana#/something', + forceNow, + } as JobDocPayloadPNG, + server: mockServer, + }); + + expect(urls[0]).toEqual( + 'http://localhost:5601/sbp/app/kibana#/something?forceNow=2000-01-01T00%3A00%3A00.000Z' + ); +}); + +test(`appends forceNow to hash's query, if it exists`, async () => { + const forceNow = '2000-01-01T00:00:00.000Z'; + + const { urls } = await getFullUrls({ + job: { + relativeUrl: '/app/kibana#/something?_g=something', + forceNow, + } as JobDocPayloadPNG, + server: mockServer, + }); + + expect(urls[0]).toEqual( + 'http://localhost:5601/sbp/app/kibana#/something?_g=something&forceNow=2000-01-01T00%3A00%3A00.000Z' + ); +}); + +test(`doesn't append forceNow query to url, if it doesn't exists`, async () => { + const { urls } = await getFullUrls({ + job: { + relativeUrl: '/app/kibana#/something', + } as JobDocPayloadPNG, + server: mockServer, + }); + + expect(urls[0]).toEqual('http://localhost:5601/sbp/app/kibana#/something'); +}); + +test(`adds forceNow to each of multiple urls`, async () => { + const forceNow = '2000-01-01T00:00:00.000Z'; + const { urls } = await getFullUrls({ + job: { + objects: [ + { relativeUrl: '/app/kibana#/something_aaa' }, + { relativeUrl: '/app/kibana#/something_bbb' }, + { relativeUrl: '/app/kibana#/something_ccc' }, + { relativeUrl: '/app/kibana#/something_ddd' }, + ], + forceNow, + } as JobDocPayloadPDF, + server: mockServer, + }); + + expect(urls).toEqual([ + 'http://localhost:5601/sbp/app/kibana#/something_aaa?forceNow=2000-01-01T00%3A00%3A00.000Z', + 'http://localhost:5601/sbp/app/kibana#/something_bbb?forceNow=2000-01-01T00%3A00%3A00.000Z', + 'http://localhost:5601/sbp/app/kibana#/something_ccc?forceNow=2000-01-01T00%3A00%3A00.000Z', + 'http://localhost:5601/sbp/app/kibana#/something_ddd?forceNow=2000-01-01T00%3A00%3A00.000Z', + ]); +}); diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.ts new file mode 100644 index 0000000000000..5bbc22a3e8757 --- /dev/null +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/get_full_urls.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + format as urlFormat, + parse as urlParse, + UrlWithStringQuery, + UrlWithParsedQuery, +} from 'url'; +import { getAbsoluteUrlFactory } from '../../../common/get_absolute_url'; +import { KbnServer } from '../../../types'; +import { JobDocPayloadPNG } from '../../png/types'; +import { JobDocPayloadPDF } from '../../printable_pdf/types'; + +interface KeyedRelativeUrl { + relativeUrl: string; +} + +export async function getFullUrls({ + job, + server, + ...mergeValues // pass-throughs +}: { + job: JobDocPayloadPNG | JobDocPayloadPDF; + server: KbnServer; +}) { + const getAbsoluteUrl = getAbsoluteUrlFactory(server); + + // PDF and PNG job params put in the url differently + let relativeUrls: string[] = []; + + if (job.relativeUrl) { + // single page (png) + relativeUrls = [job.relativeUrl]; + } else if (job.objects) { + // multi page (pdf) + relativeUrls = job.objects.map((obj: KeyedRelativeUrl) => obj.relativeUrl); + } else { + throw new Error( + `No valid URL fields found in Job Params! Expected \`job.relativeUrl\` or \`job.objects[{ relativeUrl }]\`` + ); + } + + const urls = relativeUrls.map(relativeUrl => { + const parsedRelative: UrlWithStringQuery = urlParse(relativeUrl); + const jobUrl = getAbsoluteUrl({ + basePath: job.basePath, + path: parsedRelative.pathname, + hash: parsedRelative.hash, + search: parsedRelative.search, + }); + + // capture the route to the visualization + const parsed: UrlWithParsedQuery = urlParse(jobUrl, true); + if (parsed.hash == null) { + throw new Error( + 'No valid hash in the URL! A hash is expected for the application to route to the intended visualization.' + ); + } + + // allow the hash check to perform first + if (!job.forceNow) { + return jobUrl; + } + + const visualizationRoute: UrlWithParsedQuery = urlParse(parsed.hash.replace(/^#/, ''), true); + + // combine the visualization route and forceNow parameter into a URL + const transformedHash = urlFormat({ + pathname: visualizationRoute.pathname, + query: { + ...visualizationRoute.query, + forceNow: job.forceNow, + }, + }); + + return urlFormat({ + ...parsed, + hash: transformedHash, + }); + }); + + return { job, urls, server, ...mergeValues }; +} diff --git a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/index.ts b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/index.ts index 531754b2f2851..b9d59b2be1296 100644 --- a/x-pack/legacy/plugins/reporting/export_types/common/execute_job/index.ts +++ b/x-pack/legacy/plugins/reporting/export_types/common/execute_job/index.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { addForceNowQuerystring } from './add_force_now_query_string'; export { decryptJobHeaders } from './decrypt_job_headers'; export { getConditionalHeaders } from './get_conditional_headers'; export { getCustomLogo } from './get_custom_logo'; +export { getFullUrls } from './get_full_urls'; export { omitBlacklistedHeaders } from './omit_blacklisted_headers'; diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts index 3f024264af4a5..07fdf42a15171 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/create_job/create_job.ts @@ -94,7 +94,6 @@ function createJobFn(server: KbnServer): CreateJobFn { }); return { - basePath: req.getBasePath(), headers: serializedEncryptedHeaders, jobParams: { ...jobParams, panel, visType }, type: null, // resolved in executeJob diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts index 8c1bf87e71a54..ece5217a56205 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/execute_job.ts @@ -14,15 +14,9 @@ import { CSV_FROM_SAVEDOBJECT_JOB_TYPE, PLUGIN_ID, } from '../../../common/constants'; -import { CsvResultFromSearch, JobDocPayloadPanelCsv } from '../types'; +import { CsvResultFromSearch, JobDocPayloadPanelCsv, FakeRequest } from '../types'; import { createGenerateCsv } from './lib'; -interface FakeRequest { - headers: any; - getBasePath: (opts: any) => string; - server: KbnServer; -} - type ExecuteJobFn = ( jobId: string | null, job: JobDocPayloadPanelCsv, @@ -31,8 +25,6 @@ type ExecuteJobFn = ( function executeJobFactoryFn(server: KbnServer): ExecuteJobFn { const crypto = cryptoFactory(server); - const config = server.config(); - const serverBasePath = config.get('server.basePath'); const logger = LevelLogger.createForServer(server, [ PLUGIN_ID, CSV_FROM_SAVEDOBJECT_JOB_TYPE, @@ -49,7 +41,7 @@ function executeJobFactoryFn(server: KbnServer): ExecuteJobFn { // Use the jobID as a logging tag or "immediate" const jobLogger = logger.clone([jobId === null ? 'immediate' : jobId]); - const { basePath, jobParams } = job; + const { jobParams } = job; const { isImmediate, panel, visType } = jobParams; jobLogger.debug(`Execute job generating [${visType}] csv`); @@ -80,7 +72,6 @@ function executeJobFactoryFn(server: KbnServer): ExecuteJobFn { requestObject = { headers: decryptedHeaders, - getBasePath: () => basePath || serverBasePath, server, }; } diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv.ts index d8a334f3fede1..aafad4674a1b2 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/server/lib/generate_csv.ts @@ -8,14 +8,9 @@ import { badRequest } from 'boom'; import { Request } from 'hapi'; import { KbnServer, Logger } from '../../../../types'; import { SearchPanel, VisPanel, JobParamsPanelCsv } from '../../types'; +import { FakeRequest } from '../../types'; import { generateCsvSearch } from './generate_csv_search'; -interface FakeRequest { - headers: any; - getBasePath: (opts: any) => string; - server: KbnServer; -} - export function createGenerateCsv(logger: Logger) { return async function generateCsv( request: Request | FakeRequest, diff --git a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/types.d.ts b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/types.d.ts index 916c0304f4b8b..db3ffe11931a9 100644 --- a/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/types.d.ts +++ b/x-pack/legacy/plugins/reporting/export_types/csv_from_savedobject/types.d.ts @@ -5,7 +5,12 @@ */ import { CancellationToken } from '../../common/cancellation_token'; -import { JobParams, JobParamPostPayload, JobDocPayload } from '../../types'; +import { JobParams, JobParamPostPayload, JobDocPayload, KbnServer } from '../../types'; + +export interface FakeRequest { + headers: any; + server: KbnServer; +} export interface JobParamsPostPayloadPanelCsv extends JobParamPostPayload { state?: any; diff --git a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.js b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.js index 1c59f0c8a79d4..2642d88983ecf 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.js +++ b/x-pack/legacy/plugins/reporting/export_types/png/server/execute_job/index.js @@ -14,7 +14,7 @@ import { decryptJobHeaders, omitBlacklistedHeaders, getConditionalHeaders, - addForceNowQuerystring, + getFullUrls, } from '../../../common/execute_job/'; function executeJobFn(server) { @@ -40,7 +40,7 @@ function executeJobFn(server) { }), map(omitBlacklistedHeaders), map(getConditionalHeaders), - mergeMap(addForceNowQuerystring), + mergeMap(getFullUrls), mergeMap(({ job, conditionalHeaders, urls }) => { const hashUrl = urls[0]; return generatePngObservable( diff --git a/x-pack/legacy/plugins/reporting/export_types/png/types.d.ts b/x-pack/legacy/plugins/reporting/export_types/png/types.d.ts index 541f9977fee45..f0590f98da362 100644 --- a/x-pack/legacy/plugins/reporting/export_types/png/types.d.ts +++ b/x-pack/legacy/plugins/reporting/export_types/png/types.d.ts @@ -8,7 +8,7 @@ import { Request } from 'hapi'; import { LayoutInstance } from '../common/layouts/layout'; import { ConditionalHeaders, KbnServer, JobDocPayload } from '../../types'; -// NOTE: this does not extend the main Params +// Job params: structure of incoming user request data export interface JobParamsPNG { objectType: string; title: string; @@ -17,13 +17,18 @@ export interface JobParamsPNG { layout: LayoutInstance; } +// Job payload: structure of stored job data provided by create_job +export interface JobDocPayloadPNG extends JobDocPayload { + basePath?: string; + browserTimezone: string; + forceNow?: string; + layout: any; + relativeUrl: string; + objects: undefined; +} + export type ESQueueCreateJobFnPNG = ( jobParams: JobParamsPNG, headers: ConditionalHeaders, request: Request ) => Promise; - -export interface JobDocPayloadPNG extends JobDocPayload { - browserTimezone: string; - layout: any; -} diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.js deleted file mode 100644 index f9a9786b35ebe..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.js +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import url from 'url'; -import { getAbsoluteUrlFactory } from '../../../../common/get_absolute_url'; -import { i18n } from '@kbn/i18n'; - -export function compatibilityShimFactory(server) { - const getAbsoluteUrl = getAbsoluteUrlFactory(server); - - const getSavedObjectAbsoluteUrl = (job, savedObject) => { - if (savedObject.urlHash) { - return getAbsoluteUrl({ hash: savedObject.urlHash }); - } - - if (savedObject.relativeUrl) { - const { pathname: path, hash, search } = url.parse(savedObject.relativeUrl); - return getAbsoluteUrl({ basePath: job.basePath, path, hash, search }); - } - - if (savedObject.url.startsWith(getAbsoluteUrl())) { - return savedObject.url; - } - - throw new Error(i18n.translate('xpack.reporting.exportTypes.printablePdf.compShim.unableToGenerateReportErrorMessage', { - defaultMessage: `Unable to generate report for url {savedObjUrl}, it's not a Kibana URL`, - values: { savedObjUrl: savedObject.url } - })); - }; - - return function (executeJob) { - return async function (jobId, job, cancellationToken) { - const jobToExecute = { - ...job, - urls: job.objects.map(savedObject => getSavedObjectAbsoluteUrl(job, savedObject)), - }; - - return await executeJob(jobId, jobToExecute, cancellationToken); - }; - }; -} diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.test.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.test.js deleted file mode 100644 index b5357262f998d..0000000000000 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/compatibility_shim.test.js +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { compatibilityShimFactory } from './compatibility_shim'; - -const createMockServer = () => { - const config = { - 'server.host': 'localhost', - 'server.port': '5601', - 'server.basePath': '', - }; - - return { - info: { - protocol: 'http' - }, - expose: jest.fn(), // fools once_per_server - log: jest.fn(), - config: () => { - return { - get: key => config[key] - }; - } - }; -}; - -const getMockExecutedJob = executeJobMock => executeJobMock.mock.calls[0][1]; - -test(`it throw error if full URL is provided that is not a Kibana URL`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - await expect(compatibilityShim(executeJobMock)('pdfJobToExecuteId', { query: '', objects: [ { url: 'https://localhost/app/kibana' } ] })).rejects.toBeDefined(); -}); - -test(`it passes url through if it is a Kibana URL`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const url = 'http://localhost:5601/app/kibana/#visualize'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { objects: [ { url } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.objects[0].url).toBe(url); -}); - -test(`it generates the absolute url if a urlHash is provided`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const urlHash = '#visualize'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { objects: [ { urlHash } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.urls[0]).toBe('http://localhost:5601/app/kibana#visualize'); -}); - -test(`it generates the absolute url using server's basePath if a relativeUrl is provided`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const relativeUrl = '/app/kibana#/visualize?'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { objects: [ { relativeUrl } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.urls[0]).toBe('http://localhost:5601/app/kibana#/visualize?'); -}); - -test(`it generates the absolute url using job's basePath if a relativeUrl is provided`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const relativeUrl = '/app/kibana#/visualize?'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { basePath: '/s/marketing', objects: [ { relativeUrl } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.urls[0]).toBe('http://localhost:5601/s/marketing/app/kibana#/visualize?'); -}); - -test(`it generates the absolute url using server's basePath if a relativeUrl with querystring is provided`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const relativeUrl = '/app/kibana?_t=123456789#/visualize?_g=()'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { objects: [ { relativeUrl } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.urls[0]).toBe('http://localhost:5601/app/kibana?_t=123456789#/visualize?_g=()'); -}); - -test(`it generates the absolute url using job's basePath if a relativeUrl with querystring is provided`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const relativeUrl = '/app/kibana?_t=123456789#/visualize?_g=()'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { basePath: '/s/marketing', objects: [ { relativeUrl } ] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.urls[0]).toBe('http://localhost:5601/s/marketing/app/kibana?_t=123456789#/visualize?_g=()'); -}); - -test(`it passes the provided browserTimezone through`, async () => { - const executeJobMock = jest.fn(); - const compatibilityShim = compatibilityShimFactory(createMockServer()); - - const browserTimezone = 'UTC'; - await compatibilityShim(executeJobMock)('pdfJobToExecuteId', { browserTimezone, objects: [] }); - expect(executeJobMock.mock.calls.length).toBe(1); - const executedJob = getMockExecutedJob(executeJobMock); - expect(executedJob.browserTimezone).toEqual(browserTimezone); -}); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.js b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.js index 3b6da18d398d3..d340a09728ca7 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.js +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/execute_job/index.js @@ -10,21 +10,19 @@ import { i18n } from '@kbn/i18n'; import { PLUGIN_ID, PDF_JOB_TYPE } from '../../../../common/constants'; import { LevelLogger, oncePerServer } from '../../../../server/lib'; import { generatePdfObservableFactory } from '../lib/generate_pdf'; -import { compatibilityShimFactory } from './compatibility_shim'; import { decryptJobHeaders, omitBlacklistedHeaders, getConditionalHeaders, - addForceNowQuerystring, + getFullUrls, getCustomLogo, } from '../../../common/execute_job/'; function executeJobFn(server) { const generatePdfObservable = generatePdfObservableFactory(server); - const compatibilityShim = compatibilityShimFactory(server); const logger = LevelLogger.createForServer(server, [PLUGIN_ID, PDF_JOB_TYPE, 'execute']); - return compatibilityShim(function executeJob(jobId, jobToExecute, cancellationToken) { + return function executeJob(jobId, jobToExecute, cancellationToken) { const jobLogger = logger.clone([jobId]); const process$ = Rx.of({ job: jobToExecute, server }).pipe( @@ -45,7 +43,7 @@ function executeJobFn(server) { map(omitBlacklistedHeaders), map(getConditionalHeaders), mergeMap(getCustomLogo), - mergeMap(addForceNowQuerystring), + mergeMap(getFullUrls), mergeMap(({ job, conditionalHeaders, logo, urls }) => { return generatePdfObservable( jobLogger, @@ -71,7 +69,7 @@ function executeJobFn(server) { const stop$ = Rx.fromEventPattern(cancellationToken.on); return process$.pipe(takeUntil(stop$)).toPromise(); - }); + }; } export const executeJobFactory = oncePerServer(executeJobFn); diff --git a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/types.d.ts b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/types.d.ts index f8eb65b47389d..d75dedad9a333 100644 --- a/x-pack/legacy/plugins/reporting/export_types/printable_pdf/types.d.ts +++ b/x-pack/legacy/plugins/reporting/export_types/printable_pdf/types.d.ts @@ -6,9 +6,9 @@ import { Request } from 'hapi'; import { LayoutInstance } from '../common/layouts/layout'; -import { ConditionalHeaders, KbnServer } from '../../types'; +import { ConditionalHeaders, KbnServer, JobDocPayload } from '../../types'; -// NOTE: this does not extend the main Params +// Job params: structure of incoming user request data export interface JobParamsPDF { objectType: string; title: string; @@ -17,6 +17,18 @@ export interface JobParamsPDF { layout: LayoutInstance; } +// Job payload: structure of stored job data provided by create_job +export interface JobDocPayloadPDF extends JobDocPayload { + basePath?: string; + browserTimezone: string; + forceNow?: string; + layout: any; + objects: Array<{ + relativeUrl: string; + }>; + relativeUrl: undefined; +} + export type ESQueueCreateJobFnPDF = ( jobParams: JobParamsPDF, headers: ConditionalHeaders, diff --git a/x-pack/legacy/plugins/reporting/types.d.ts b/x-pack/legacy/plugins/reporting/types.d.ts index 4392dc1176a9d..ff9a1b0f75d08 100644 --- a/x-pack/legacy/plugins/reporting/types.d.ts +++ b/x-pack/legacy/plugins/reporting/types.d.ts @@ -87,15 +87,10 @@ export interface JobParams { } export interface JobDocPayload { - basePath?: string; - forceNow?: string; headers?: Record; jobParams: JobParams; - relativeUrl?: string; - timeRange?: any; title: string; type: string | null; - urls?: string[]; } export interface JobDocOutput { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 520d602fcffbd..8320298fca25a 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8499,7 +8499,6 @@ "xpack.reporting.exportTypes.csv.hitIterator.expectedScrollIdErrorMessage": "次の Elasticsearch からの応答で期待される {scrollId}: {response}", "xpack.reporting.exportTypes.png.compShim.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました{encryptionKey} が設定されていることを確認してこのレポートを再生成してください。{err}", "xpack.reporting.exportTypes.printablePdf.compShim.failedToDecryptReportJobDataErrorMessage": "レポートジョブデータの解読に失敗しました{encryptionKey} が設定されていることを確認してこのレポートを再生成してください。{err}", - "xpack.reporting.exportTypes.printablePdf.compShim.unableToGenerateReportErrorMessage": "URL {savedObjUrl} のレポートを生成できません。Kibana URL ではありません。", "xpack.reporting.exportTypes.printablePdf.documentStreamIsNotgeneratedErrorMessage": "ドキュメントストリームが生成されていません。", "xpack.reporting.exportTypes.printablePdf.logoDescription": "Elastic 提供", "xpack.reporting.exportTypes.printablePdf.pagingDescription": "{pageCount} ページ中 {currentPage} ページ目", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 9167b2e428c84..b666233c45a9b 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8643,7 +8643,6 @@ "xpack.reporting.exportTypes.csv.hitIterator.expectedScrollIdErrorMessage": "在以下 Elasticsearch 响应中预期 {scrollId}:{response}", "xpack.reporting.exportTypes.png.compShim.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", "xpack.reporting.exportTypes.printablePdf.compShim.failedToDecryptReportJobDataErrorMessage": "无法解密报告作业数据。请确保已设置 {encryptionKey},然后重新生成此报告。{err}", - "xpack.reporting.exportTypes.printablePdf.compShim.unableToGenerateReportErrorMessage": "无法为 url {savedObjUrl} 生成报告,它不是 Kibana URL", "xpack.reporting.exportTypes.printablePdf.documentStreamIsNotgeneratedErrorMessage": "尚未生成文档流", "xpack.reporting.exportTypes.printablePdf.logoDescription": "由 Elastic 提供支持", "xpack.reporting.exportTypes.printablePdf.pagingDescription": "第 {currentPage} 页,共 {pageCount} 页",