[Maps] Add drawing index data endpoint (#94728)
This commit is contained in:
parent
68722313f2
commit
d89ede9834
|
@ -298,3 +298,5 @@ export type RawValue = string | number | boolean | undefined | null;
|
|||
export type FieldFormatter = (value: RawValue) => string | number;
|
||||
|
||||
export const INDEX_META_DATA_CREATED_BY = 'maps-drawing-data-ingest';
|
||||
|
||||
export const MAX_DRAWING_SIZE_BYTES = 10485760; // 10MB
|
||||
|
|
|
@ -22,3 +22,9 @@ export interface IndexSourceMappings {
|
|||
export interface BodySettings {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface WriteSettings {
|
||||
index: string;
|
||||
body: object;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import {
|
|||
CreateDocSourceResp,
|
||||
IndexSourceMappings,
|
||||
BodySettings,
|
||||
} from '../common';
|
||||
import { IndexPatternsService } from '../../../../src/plugins/data/common';
|
||||
} from '../../common';
|
||||
import { IndexPatternsCommonService } from '../../../../../src/plugins/data/server';
|
||||
|
||||
const DEFAULT_SETTINGS = { number_of_shards: 1 };
|
||||
const DEFAULT_MAPPINGS = {
|
||||
|
@ -25,16 +25,11 @@ export async function createDocSource(
|
|||
index: string,
|
||||
mappings: IndexSourceMappings,
|
||||
{ asCurrentUser }: IScopedClusterClient,
|
||||
indexPatternsService: IndexPatternsService
|
||||
indexPatternsService: IndexPatternsCommonService
|
||||
): Promise<CreateDocSourceResp> {
|
||||
try {
|
||||
await createIndex(index, mappings, asCurrentUser);
|
||||
await indexPatternsService.createAndSave(
|
||||
{
|
||||
title: index,
|
||||
},
|
||||
true
|
||||
);
|
||||
await indexPatternsService.createAndSave({ title: index }, true);
|
||||
|
||||
return {
|
||||
success: true,
|
45
x-pack/plugins/maps/server/data_indexing/index_data.ts
Normal file
45
x-pack/plugins/maps/server/data_indexing/index_data.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ElasticsearchClient } from 'kibana/server';
|
||||
import { WriteSettings } from '../../common';
|
||||
|
||||
export async function writeDataToIndex(
|
||||
index: string,
|
||||
data: object,
|
||||
asCurrentUser: ElasticsearchClient
|
||||
) {
|
||||
try {
|
||||
const { body: indexExists } = await asCurrentUser.indices.exists({ index });
|
||||
if (!indexExists) {
|
||||
throw new Error(
|
||||
i18n.translate('xpack.maps.indexData.indexExists', {
|
||||
defaultMessage: `Index: '{index}' not found. A valid index must be provided`,
|
||||
values: {
|
||||
index,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
const settings: WriteSettings = { index, body: data };
|
||||
const { body: resp } = await asCurrentUser.index(settings);
|
||||
if (resp.result === 'Error') {
|
||||
throw resp;
|
||||
} else {
|
||||
return {
|
||||
success: true,
|
||||
data,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
104
x-pack/plugins/maps/server/data_indexing/indexing_routes.ts
Normal file
104
x-pack/plugins/maps/server/data_indexing/indexing_routes.ts
Normal file
|
@ -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
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import { Logger } from 'src/core/server';
|
||||
import { IRouter } from 'src/core/server';
|
||||
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
|
||||
import {
|
||||
INDEX_SOURCE_API_PATH,
|
||||
GIS_API_PATH,
|
||||
MAX_DRAWING_SIZE_BYTES,
|
||||
} from '../../common/constants';
|
||||
import { createDocSource } from './create_doc_source';
|
||||
import { writeDataToIndex } from './index_data';
|
||||
import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server';
|
||||
|
||||
export function initIndexingRoutes({
|
||||
router,
|
||||
logger,
|
||||
dataPlugin,
|
||||
}: {
|
||||
router: IRouter<DataRequestHandlerContext>;
|
||||
logger: Logger;
|
||||
dataPlugin: DataPluginStart;
|
||||
}) {
|
||||
router.post(
|
||||
{
|
||||
path: `/${INDEX_SOURCE_API_PATH}`,
|
||||
validate: {
|
||||
body: schema.object({
|
||||
index: schema.string(),
|
||||
mappings: schema.any(),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
body: {
|
||||
accepts: ['application/json'],
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const { index, mappings } = request.body;
|
||||
const indexPatternsService = await dataPlugin.indexPatterns.indexPatternsServiceFactory(
|
||||
context.core.savedObjects.client,
|
||||
context.core.elasticsearch.client.asCurrentUser
|
||||
);
|
||||
const result = await createDocSource(
|
||||
index,
|
||||
mappings,
|
||||
context.core.elasticsearch.client,
|
||||
indexPatternsService
|
||||
);
|
||||
if (result.success) {
|
||||
return response.ok({ body: result });
|
||||
} else {
|
||||
if (result.error) {
|
||||
logger.error(result.error);
|
||||
}
|
||||
return response.custom({
|
||||
body: result?.error?.message,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
{
|
||||
path: `/${GIS_API_PATH}/feature`,
|
||||
validate: {
|
||||
body: schema.object({
|
||||
index: schema.string(),
|
||||
data: schema.any(),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
body: {
|
||||
accepts: ['application/json'],
|
||||
maxBytes: MAX_DRAWING_SIZE_BYTES,
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const result = await writeDataToIndex(
|
||||
request.body.index,
|
||||
request.body.data,
|
||||
context.core.elasticsearch.client.asCurrentUser
|
||||
);
|
||||
if (result.success) {
|
||||
return response.ok({ body: result });
|
||||
} else {
|
||||
logger.error(result.error);
|
||||
return response.custom({
|
||||
body: result.error.message,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -24,8 +24,7 @@ import {
|
|||
INDEX_SETTINGS_API_PATH,
|
||||
FONTS_API_PATH,
|
||||
API_ROOT_PATH,
|
||||
INDEX_SOURCE_API_PATH,
|
||||
} from '../common/constants';
|
||||
} from '../common';
|
||||
import { EMSClient } from '@elastic/ems-client';
|
||||
import fetch from 'node-fetch';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -34,7 +33,7 @@ import { schema } from '@kbn/config-schema';
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { initMVTRoutes } from './mvt/mvt_routes';
|
||||
import { createDocSource } from './create_doc_source';
|
||||
import { initIndexingRoutes } from './data_indexing/indexing_routes';
|
||||
|
||||
const EMPTY_EMS_CLIENT = {
|
||||
async getFileLayers() {
|
||||
|
@ -594,47 +593,6 @@ export async function initRoutes(
|
|||
}
|
||||
);
|
||||
|
||||
if (drawingFeatureEnabled) {
|
||||
router.post(
|
||||
{
|
||||
path: `/${INDEX_SOURCE_API_PATH}`,
|
||||
validate: {
|
||||
body: schema.object({
|
||||
index: schema.string(),
|
||||
mappings: schema.any(),
|
||||
}),
|
||||
},
|
||||
options: {
|
||||
body: {
|
||||
accepts: ['application/json'],
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const { index, mappings } = request.body;
|
||||
const indexPatternsService = await dataPlugin.indexPatterns.indexPatternsServiceFactory(
|
||||
context.core.savedObjects.client,
|
||||
context.core.elasticsearch.client.asCurrentUser
|
||||
);
|
||||
const result = await createDocSource(
|
||||
index,
|
||||
mappings,
|
||||
context.core.elasticsearch.client,
|
||||
indexPatternsService
|
||||
);
|
||||
if (result.success) {
|
||||
return response.ok({ body: result });
|
||||
} else {
|
||||
logger.error(result.error);
|
||||
return response.custom({
|
||||
body: result.error.message,
|
||||
statusCode: 500,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function checkEMSProxyEnabled() {
|
||||
const proxyEMSInMaps = emsSettings.isProxyElasticMapsServiceInMaps();
|
||||
if (!proxyEMSInMaps) {
|
||||
|
@ -666,4 +624,7 @@ export async function initRoutes(
|
|||
}
|
||||
|
||||
initMVTRoutes({ router, logger });
|
||||
if (drawingFeatureEnabled) {
|
||||
initIndexingRoutes({ router, logger, dataPlugin });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ export default function ({ loadTestFile, getService }) {
|
|||
|
||||
describe('', () => {
|
||||
loadTestFile(require.resolve('./create_doc_source'));
|
||||
loadTestFile(require.resolve('./index_data'));
|
||||
loadTestFile(require.resolve('./fonts_api'));
|
||||
loadTestFile(require.resolve('./index_settings'));
|
||||
loadTestFile(require.resolve('./migrations'));
|
||||
|
|
98
x-pack/test/api_integration/apis/maps/index_data.js
Normal file
98
x-pack/test/api_integration/apis/maps/index_data.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('index feature data', () => {
|
||||
it('should add point data to an existing index', async () => {
|
||||
await supertest
|
||||
.post(`/api/maps/docSource`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-point-feature-index',
|
||||
mappings: { properties: { coordinates: { type: 'geo_point' } } },
|
||||
});
|
||||
|
||||
const resp = await supertest
|
||||
.post(`/api/maps/feature`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-point-feature-index',
|
||||
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(resp.body.success).to.be(true);
|
||||
});
|
||||
|
||||
it('should add shape data to an existing index', async () => {
|
||||
await supertest
|
||||
.post(`/api/maps/docSource`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-shape-feature-index',
|
||||
mappings: { properties: { coordinates: { type: 'geo_shape' } } },
|
||||
});
|
||||
|
||||
const resp = await supertest
|
||||
.post(`/api/maps/feature`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-shape-feature-index',
|
||||
data: {
|
||||
coordinates: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[-20.91796875, 25.64152637306577],
|
||||
[-13.0517578125, 25.64152637306577],
|
||||
[-13.0517578125, 31.203404950917395],
|
||||
[-20.91796875, 31.203404950917395],
|
||||
[-20.91796875, 25.64152637306577],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
expect(resp.body.success).to.be(true);
|
||||
});
|
||||
|
||||
it('should fail if data is invalid', async () => {
|
||||
await supertest
|
||||
.post(`/api/maps/docSource`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-feature-index2',
|
||||
mappings: { properties: { coordinates: { type: 'geo_point' } } },
|
||||
});
|
||||
await supertest
|
||||
.post(`/api/maps/feature`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'new-feature-index2',
|
||||
data: { coordinates: [600, 800], name: 'Never Gonna Happen Islands' },
|
||||
})
|
||||
.expect(500);
|
||||
});
|
||||
|
||||
it('should fail if index does not exist', async () => {
|
||||
await supertest
|
||||
.post(`/api/maps/feature`)
|
||||
.set('kbn-xsrf', 'kibana')
|
||||
.send({
|
||||
index: 'not-an-index',
|
||||
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },
|
||||
})
|
||||
.expect(500);
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue