From d009e54199a3ae17139d6389be18bc0618a99a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Fri, 15 Oct 2021 16:06:59 +0100 Subject: [PATCH] [Runtime field editor] Fix preview error when not enough privileges (#115070) --- .../field_editor_flyout_preview.test.ts | 1 + .../preview/field_preview_context.tsx | 1 + .../public/lib/api.ts | 3 ++ .../server/routes/field_preview.ts | 40 ++++++++++++------- .../field_preview.ts | 20 ++++++++-- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/plugins/index_pattern_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts b/src/plugins/index_pattern_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts index 65089bc24317bd..67309aab44a767 100644 --- a/src/plugins/index_pattern_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts +++ b/src/plugins/index_pattern_field_editor/__jest__/client_integration/field_editor_flyout_preview.test.ts @@ -366,6 +366,7 @@ describe('Field editor Preview panel', () => { subTitle: 'First doc - subTitle', title: 'First doc - title', }, + documentId: '001', index: 'testIndex', script: { source: 'echo("hello")', diff --git a/src/plugins/index_pattern_field_editor/public/components/preview/field_preview_context.tsx b/src/plugins/index_pattern_field_editor/public/components/preview/field_preview_context.tsx index e49e0ef6885d06..21ab055c9b05eb 100644 --- a/src/plugins/index_pattern_field_editor/public/components/preview/field_preview_context.tsx +++ b/src/plugins/index_pattern_field_editor/public/components/preview/field_preview_context.tsx @@ -335,6 +335,7 @@ export const FieldPreviewProvider: FunctionComponent = ({ children }) => { document: params.document!, context: `${params.type!}_field` as FieldPreviewContext, script: params.script!, + documentId: currentDocId, }); if (currentApiCall !== previewCount.current) { diff --git a/src/plugins/index_pattern_field_editor/public/lib/api.ts b/src/plugins/index_pattern_field_editor/public/lib/api.ts index 9325b5c2faf47a..9641619640a52b 100644 --- a/src/plugins/index_pattern_field_editor/public/lib/api.ts +++ b/src/plugins/index_pattern_field_editor/public/lib/api.ts @@ -16,11 +16,13 @@ export const initApi = (httpClient: HttpSetup) => { context, script, document, + documentId, }: { index: string; context: FieldPreviewContext; script: { source: string } | null; document: Record; + documentId: string; }) => { return sendRequest(httpClient, { path: `${API_BASE_PATH}/field_preview`, @@ -30,6 +32,7 @@ export const initApi = (httpClient: HttpSetup) => { context, script, document, + documentId, }, }); }; diff --git a/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts b/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts index 11ec1ca7d56666..847dd41e0082bc 100644 --- a/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts +++ b/src/plugins/index_pattern_field_editor/server/routes/field_preview.ts @@ -6,8 +6,8 @@ * Side Public License, v 1. */ +import { estypes } from '@elastic/elasticsearch'; import { schema } from '@kbn/config-schema'; -import { HttpResponsePayload } from 'kibana/server'; import { API_BASE_PATH } from '../../common/constants'; import { RouteDependencies } from '../types'; @@ -26,6 +26,7 @@ const bodySchema = schema.object({ schema.literal('long_field'), ]), document: schema.object({}, { unknowns: 'allow' }), + documentId: schema.string(), }); export const registerFieldPreviewRoute = ({ router }: RouteDependencies): void => { @@ -39,30 +40,41 @@ export const registerFieldPreviewRoute = ({ router }: RouteDependencies): void = async (ctx, req, res) => { const { client } = ctx.core.elasticsearch; - const body = JSON.stringify({ - script: req.body.script, - context: req.body.context, - context_setup: { - document: req.body.document, - index: req.body.index, - } as any, - }); + const type = req.body.context.split('_field')[0] as estypes.MappingRuntimeFieldType; + const body = { + runtime_mappings: { + my_runtime_field: { + type, + script: req.body.script, + }, + }, + size: 1, + query: { + term: { + _id: req.body.documentId, + }, + }, + fields: ['my_runtime_field'], + }; try { - const response = await client.asCurrentUser.scriptsPainlessExecute({ - // @ts-expect-error `ExecutePainlessScriptRequest.body` does not allow `string` + const response = await client.asCurrentUser.search({ + index: req.body.index, body, }); - const fieldValue = response.body.result as any[] as HttpResponsePayload; + const fieldValue = response.body.hits.hits[0]?.fields?.my_runtime_field ?? ''; return res.ok({ body: { values: fieldValue } }); - } catch (error) { + } catch (error: any) { // Assume invalid painless script was submitted // Return 200 with error object const handleCustomError = () => { return res.ok({ - body: { values: [], ...error.body }, + body: { + values: [], + error: error.body.error.failed_shards[0]?.reason ?? {}, + }, }); }; diff --git a/test/api_integration/apis/index_pattern_field_editor/field_preview.ts b/test/api_integration/apis/index_pattern_field_editor/field_preview.ts index a84accc8e5f03a..7123be1deb18a5 100644 --- a/test/api_integration/apis/index_pattern_field_editor/field_preview.ts +++ b/test/api_integration/apis/index_pattern_field_editor/field_preview.ts @@ -12,11 +12,14 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { API_BASE_PATH } from './constants'; const INDEX_NAME = 'api-integration-test-field-preview'; +const DOC_ID = '1'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('es'); + const document = { foo: 1, bar: 'hello' }; + const createIndex = async () => { await es.indices.create({ index: INDEX_NAME, @@ -35,6 +38,15 @@ export default function ({ getService }: FtrProviderContext) { }); }; + const addDoc = async () => { + await es.index({ + index: INDEX_NAME, + id: DOC_ID, + body: document, + refresh: 'wait_for', + }); + }; + const deleteIndex = async () => { await es.indices.delete({ index: INDEX_NAME, @@ -42,12 +54,13 @@ export default function ({ getService }: FtrProviderContext) { }; describe('Field preview', function () { - before(async () => await createIndex()); + before(async () => { + await createIndex(); + await addDoc(); + }); after(async () => await deleteIndex()); describe('should return the script value', () => { - const document = { foo: 1, bar: 'hello' }; - const tests = [ { context: 'keyword_field', @@ -77,6 +90,7 @@ export default function ({ getService }: FtrProviderContext) { const payload = { script: test.script, document, + documentId: DOC_ID, context: test.context, index: INDEX_NAME, };