[maps] move routes from /api/maps to /internal/maps and add route versioning (#158328)

Fixes https://github.com/elastic/kibana/issues/157104 and
https://github.com/elastic/kibana/issues/156323

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-05-30 07:51:12 -06:00 committed by GitHub
parent ff8cebb407
commit 94d4574b58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 605 additions and 452 deletions

View file

@ -23,17 +23,16 @@ export const INITIAL_LAYERS_KEY = 'initialLayers';
export const MAPS_APP_PATH = `app/${APP_ID}`;
export const MAP_PATH = 'map';
export const GIS_API_PATH = `api/${APP_ID}`;
export const INDEX_SETTINGS_API_PATH = `${GIS_API_PATH}/indexSettings`;
export const FONTS_API_PATH = `${GIS_API_PATH}/fonts`;
export const INDEX_SOURCE_API_PATH = `${GIS_API_PATH}/docSource`;
export const API_ROOT_PATH = `/${GIS_API_PATH}`;
export const INDEX_FEATURE_PATH = `/${GIS_API_PATH}/feature`;
export const GET_MATCHING_INDEXES_PATH = `/${GIS_API_PATH}/getMatchingIndexes`;
export const CHECK_IS_DRAWING_INDEX = `/${GIS_API_PATH}/checkIsDrawingIndex`;
export const GIS_INTERNAL_PATH = `internal/${APP_ID}`;
export const INDEX_SETTINGS_API_PATH = `${GIS_INTERNAL_PATH}/indexSettings`;
export const FONTS_API_PATH = `${GIS_INTERNAL_PATH}/fonts`;
export const INDEX_SOURCE_API_PATH = `${GIS_INTERNAL_PATH}/docSource`;
export const INDEX_FEATURE_PATH = `/${GIS_INTERNAL_PATH}/feature`;
export const GET_MATCHING_INDEXES_PATH = `/${GIS_INTERNAL_PATH}/getMatchingIndexes`;
export const CHECK_IS_DRAWING_INDEX = `/${GIS_INTERNAL_PATH}/checkIsDrawingIndex`;
export const MVT_GETTILE_API_PATH = `/${GIS_INTERNAL_PATH}/mvt/getTile`;
export const MVT_GETGRIDTILE_API_PATH = `/${GIS_INTERNAL_PATH}/mvt/getGridTile`;
export const MVT_GETTILE_API_PATH = 'mvt/getTile';
export const MVT_GETGRIDTILE_API_PATH = 'mvt/getGridTile';
export const OPEN_LAYER_WIZARD = 'openLayerWizard';
// Identifies centroid feature.

View file

@ -1051,8 +1051,7 @@ export class AbstractVectorLayer extends AbstractLayer implements IVectorLayer {
async addFeature(geometry: Geometry | Position[]) {
const layerSource = this.getSource();
const defaultFields = await layerSource.getDefaultFields();
await layerSource.addFeature(geometry, defaultFields);
await layerSource.addFeature(geometry);
}
async deleteFeature(featureId: string) {

View file

@ -19,6 +19,7 @@ export const createNewIndexAndPattern = async ({
return await getHttp().fetch<CreateDocSourceResp>({
path: `/${INDEX_SOURCE_API_PATH}`,
method: 'POST',
version: '1',
body: JSON.stringify({
index: indexName,
mappings: {

View file

@ -313,7 +313,7 @@ describe('ESGeoGridSource', () => {
const tileUrl = await mvtGeogridSource.getTileUrl(vectorSourceRequestMeta, '1234', false, 5);
const urlParts = tileUrl.split('?');
expect(urlParts[0]).toEqual('rootdir/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf');
expect(urlParts[0]).toEqual('rootdir/internal/maps/mvt/getGridTile/{z}/{x}/{y}.pbf');
const params = new URLSearchParams(urlParts[1]);
expect(Object.fromEntries(params)).toEqual({

View file

@ -25,7 +25,6 @@ import {
ES_GEO_FIELD_TYPE,
GEOCENTROID_AGG_NAME,
GEOTILE_GRID_AGG_NAME,
GIS_API_PATH,
GRID_RESOLUTION,
MVT_GETGRIDTILE_API_PATH,
RENDER_AS,
@ -574,7 +573,7 @@ export class ESGeoGridSource extends AbstractESAggSource implements IMvtVectorSo
searchSource.setField('aggs', this.getValueAggsDsl(dataView));
const mvtUrlServicePath = getHttp().basePath.prepend(
`/${GIS_API_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`
`${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`
);
const tileUrlParams = getTileUrlParams({

View file

@ -122,7 +122,7 @@ describe('ESSearchSource', () => {
const tileUrl = await esSearchSource.getTileUrl(requestMeta, '1234', false, 5);
const urlParts = tileUrl.split('?');
expect(urlParts[0]).toEqual('rootdir/api/maps/mvt/getTile/{z}/{x}/{y}.pbf');
expect(urlParts[0]).toEqual('rootdir/internal/maps/mvt/getTile/{z}/{x}/{y}.pbf');
const params = new URLSearchParams(urlParts[1]);
expect(Object.fromEntries(params)).toEqual({

View file

@ -37,7 +37,6 @@ import {
ES_GEO_FIELD_TYPE,
FIELD_ORIGIN,
GEO_JSON_TYPE,
GIS_API_PATH,
MVT_GETTILE_API_PATH,
SCALING_TYPES,
SOURCE_TYPES,
@ -491,7 +490,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
return !!(scalingType === SCALING_TYPES.TOP_HITS && topHitsSplitField);
}
async getSourceIndexList(): Promise<string[]> {
async _getSourceIndexList(): Promise<string[]> {
const dataView = await this.getIndexPattern();
try {
const { success, matchingIndexes } = await getMatchingIndexes(dataView.getIndexPattern());
@ -503,12 +502,12 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
}
async supportsFeatureEditing(): Promise<boolean> {
const matchingIndexes = await this.getSourceIndexList();
const matchingIndexes = await this._getSourceIndexList();
// For now we only support 1:1 index-pattern:index matches
return matchingIndexes.length === 1;
}
async getDefaultFields(): Promise<Record<string, Record<string, string>>> {
async _getNewFeatureFields(): Promise<Record<string, Record<string, string>>> {
if (!(await this._isDrawingIndex())) {
return {};
}
@ -820,7 +819,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
}
async _getEditableIndex(): Promise<string> {
const indexList = await this.getSourceIndexList();
const indexList = await this._getSourceIndexList();
if (indexList.length === 0) {
throw new Error(
i18n.translate('xpack.maps.source.esSearch.indexZeroLengthEditError', {
@ -838,12 +837,14 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
return indexList[0];
}
async addFeature(
geometry: Geometry | Position[],
defaultFields: Record<string, Record<string, string>>
) {
async addFeature(geometry: Geometry | Position[]) {
const index = await this._getEditableIndex();
await addFeatureToIndex(index, geometry, this.getGeoFieldName(), defaultFields);
await addFeatureToIndex(
index,
geometry,
this.getGeoFieldName(),
await this._getNewFeatureFields()
);
}
async deleteFeature(featureId: string) {
@ -894,9 +895,7 @@ export class ESSearchSource extends AbstractESSource implements IMvtVectorSource
})
);
const mvtUrlServicePath = getHttp().basePath.prepend(
`/${GIS_API_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`
);
const mvtUrlServicePath = getHttp().basePath.prepend(`${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`);
const tileUrlParams = getTileUrlParams({
geometryFieldName: this._descriptor.geoField,

View file

@ -24,6 +24,7 @@ export const addFeatureToIndex = async (
return await getHttp().fetch({
path: `${INDEX_FEATURE_PATH}`,
method: 'POST',
version: '1',
body: JSON.stringify({
index: indexName,
data,
@ -35,6 +36,7 @@ export const deleteFeatureFromIndex = async (indexName: string, featureId: strin
return await getHttp().fetch({
path: `${INDEX_FEATURE_PATH}/${featureId}`,
method: 'DELETE',
version: '1',
body: JSON.stringify({
index: indexName,
}),
@ -48,6 +50,7 @@ export const getMatchingIndexes = async (indexPattern: string) => {
}>({
path: GET_MATCHING_INDEXES_PATH,
method: 'GET',
version: '1',
query: { indexPattern },
});
};
@ -59,6 +62,7 @@ export const getIsDrawLayer = async (index: string) => {
}>({
path: CHECK_IS_DRAWING_INDEX,
method: 'GET',
version: '1',
query: { index },
});
};

View file

@ -38,6 +38,7 @@ async function fetchIndexSettings(indexPatternTitle: string): Promise<INDEX_SETT
return await http.fetch(`/${INDEX_SETTINGS_API_PATH}`, {
method: 'GET',
credentials: 'same-origin',
version: '1',
query: {
indexPatternTitle,
},

View file

@ -233,10 +233,6 @@ export class MVTSingleLayerVectorSource extends AbstractSource implements IMvtVe
return false;
}
async getDefaultFields(): Promise<Record<string, Record<string, string>>> {
return {};
}
supportsJoins(): boolean {
return false;
}

View file

@ -122,11 +122,7 @@ export interface IVectorSource extends ISource {
getSourceStatus(sourceDataRequest?: DataRequest): SourceStatus;
getTimesliceMaskFieldName(): Promise<string | null>;
supportsFeatureEditing(): Promise<boolean>;
getDefaultFields(): Promise<Record<string, Record<string, string>>>;
addFeature(
geometry: Geometry | Position[],
defaultFields: Record<string, Record<string, string>>
): Promise<void>;
addFeature(geometry: Geometry | Position[]): Promise<void>;
deleteFeature(featureId: string): Promise<void>;
/*
@ -242,10 +238,7 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc
return null;
}
async addFeature(
geometry: Geometry | Position[],
defaultFields: Record<string, Record<string, string>>
) {
async addFeature(geometry: Geometry | Position[]) {
throw new Error('Should implement VectorSource#addFeature');
}
@ -257,10 +250,6 @@ export class AbstractVectorSource extends AbstractSource implements IVectorSourc
return false;
}
async getDefaultFields(): Promise<Record<string, Record<string, string>>> {
return {};
}
getFeatureActions({
addFilters,
geoFieldNames,

View file

@ -61,7 +61,7 @@ describe('EMS enabled', () => {
await getCanAccessEmsFonts();
expect(getGlyphs()).toEqual({
isEmsFont: false,
glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}',
glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}',
});
});
});
@ -108,7 +108,7 @@ describe('EMS disabled', () => {
test('should return kibana fonts template URL before canAccessEmsFontsPromise resolves', () => {
expect(getGlyphs()).toEqual({
isEmsFont: false,
glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}',
glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}',
});
});
@ -116,7 +116,7 @@ describe('EMS disabled', () => {
await getCanAccessEmsFonts();
expect(getGlyphs()).toEqual({
isEmsFont: false,
glyphUrlTemplate: 'abc/api/maps/fonts/{fontstack}/{range}',
glyphUrlTemplate: 'abc/internal/maps/fonts/{fontstack}/{range}',
});
});
});

View file

@ -51,6 +51,7 @@ import type { MapExtentState } from '../../reducers/map/types';
import { CUSTOM_ICON_PIXEL_RATIO, createSdfIcon } from '../../classes/styles/vector/symbol_utils';
import { MAKI_ICONS } from '../../classes/styles/vector/maki_icons';
import { KeydownScrollZoom } from './keydown_scroll_zoom/keydown_scroll_zoom';
import { transformRequest } from './transform_request';
export interface Props {
isMapReady: boolean;
@ -171,6 +172,7 @@ export class MbMap extends Component<Props, State> {
preserveDrawingBuffer: getPreserveDrawingBuffer(),
maxZoom: this.props.settings.maxZoom,
minZoom: this.props.settings.minZoom,
transformRequest,
};
if (initialView) {
options.zoom = initialView.zoom;

View file

@ -0,0 +1,46 @@
/*
* 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 { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import {
FONTS_API_PATH,
MVT_GETTILE_API_PATH,
MVT_GETGRIDTILE_API_PATH,
} from '../../../common/constants';
import { getHttp } from '../../kibana_services';
const FONTS = getHttp().basePath.prepend(FONTS_API_PATH);
const GETTILE = getHttp().basePath.prepend(MVT_GETTILE_API_PATH);
const GETGRIDTILE = getHttp().basePath.prepend(MVT_GETGRIDTILE_API_PATH);
export function transformRequest(url: string, resourceType: string | undefined) {
if (resourceType === 'Glyphs' && url.startsWith(FONTS)) {
return {
url,
method: 'GET' as 'GET',
headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' },
};
}
if (resourceType === 'Tile' && url.startsWith(GETTILE)) {
return {
url,
method: 'GET' as 'GET',
headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' },
};
}
if (resourceType === 'Tile' && url.startsWith(GETGRIDTILE)) {
return {
url,
method: 'GET' as 'GET',
headers: { [ELASTIC_HTTP_VERSION_HEADER]: '1' },
};
}
return { url };
}

View file

@ -11,7 +11,7 @@ test('Should return elasticsearch vector tile request for aggs tiles', () => {
expect(
getTileRequest({
layerId: '1',
tileUrl: `/pof/api/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=geo.coordinates&hasLabels=false&buffer=7&index=kibana_sample_data_logs&gridPrecision=8&requestBody=(_source%3A(excludes%3A!())%2Caggs%3A()%2Cfields%3A!((field%3A'%40timestamp'%2Cformat%3Adate_time)%2C(field%3Atimestamp%2Cformat%3Adate_time)%2C(field%3Autc_time%2Cformat%3Adate_time))%2Cquery%3A(bool%3A(filter%3A!((match_phrase%3A(machine.os.keyword%3Aios))%2C(range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A'2022-04-22T16%3A46%3A00.744Z'%2Clte%3A'2022-04-29T16%3A46%3A05.345Z'))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A'emit(doc%5B!'timestamp!'%5D.value.getHour())%3B')%2Ctype%3Along))%2Cscript_fields%3A()%2Csize%3A0%2Cstored_fields%3A!('*'))&renderAs=heatmap&token=e8bff005-ccea-464a-ae56-2061b4f8ce68`,
tileUrl: `/pof/internal/maps/mvt/getGridTile/{z}/{x}/{y}.pbf?geometryFieldName=geo.coordinates&hasLabels=false&buffer=7&index=kibana_sample_data_logs&gridPrecision=8&requestBody=(_source%3A(excludes%3A!())%2Caggs%3A()%2Cfields%3A!((field%3A'%40timestamp'%2Cformat%3Adate_time)%2C(field%3Atimestamp%2Cformat%3Adate_time)%2C(field%3Autc_time%2Cformat%3Adate_time))%2Cquery%3A(bool%3A(filter%3A!((match_phrase%3A(machine.os.keyword%3Aios))%2C(range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A'2022-04-22T16%3A46%3A00.744Z'%2Clte%3A'2022-04-29T16%3A46%3A05.345Z'))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A'emit(doc%5B!'timestamp!'%5D.value.getHour())%3B')%2Ctype%3Along))%2Cscript_fields%3A()%2Csize%3A0%2Cstored_fields%3A!('*'))&renderAs=heatmap&token=e8bff005-ccea-464a-ae56-2061b4f8ce68`,
x: 3,
y: 0,
z: 2,
@ -81,7 +81,7 @@ test('Should return elasticsearch vector tile request for hits tiles', () => {
expect(
getTileRequest({
layerId: '1',
tileUrl: `http://localhost:5601/zuv/api/maps/mvt/getTile/4/2/6.pbf?geometryFieldName=geo.coordinates&index=kibana_sample_data_logs&hasLabels=true&buffer=7&requestBody=(_source%3A!f%2Cfields%3A!((field%3A%27%40timestamp%27%2Cformat%3Aepoch_millis)%2Cbytes)%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-06-15T20%3A00%3A00.000Z%27%2Clte%3A%272022-06-16T20%3A48%3A02.517Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Csize%3A10000%2Csort%3A!((%27%40timestamp%27%3A(order%3Adesc%2Cunmapped_type%3Aboolean))))&token=7afe7c2d-c96b-4bdb-9b5e-819aceac80a1`,
tileUrl: `http://localhost:5601/zuv/internal/maps/mvt/getTile/4/2/6.pbf?geometryFieldName=geo.coordinates&index=kibana_sample_data_logs&hasLabels=true&buffer=7&requestBody=(_source%3A!f%2Cfields%3A!((field%3A%27%40timestamp%27%2Cformat%3Aepoch_millis)%2Cbytes)%2Cquery%3A(bool%3A(filter%3A!((range%3A(timestamp%3A(format%3Astrict_date_optional_time%2Cgte%3A%272022-06-15T20%3A00%3A00.000Z%27%2Clte%3A%272022-06-16T20%3A48%3A02.517Z%27))))%2Cmust%3A!()%2Cmust_not%3A!()%2Cshould%3A!()))%2Cruntime_mappings%3A(hour_of_day%3A(script%3A(source%3A%27emit(doc%5B!%27timestamp!%27%5D.value.getHour())%3B%27)%2Ctype%3Along))%2Csize%3A10000%2Csort%3A!((%27%40timestamp%27%3A(order%3Adesc%2Cunmapped_type%3Aboolean))))&token=7afe7c2d-c96b-4bdb-9b5e-819aceac80a1`,
x: 0,
y: 0,
z: 2,

View file

@ -33,193 +33,229 @@ export function initIndexingRoutes({
dataPlugin: DataPluginStart;
securityPlugin?: SecurityPluginStart;
}) {
router.post(
{
router.versioned
.post({
path: `/${INDEX_SOURCE_API_PATH}`,
validate: {
body: schema.object({
index: schema.string(),
mappings: schema.any(),
}),
},
access: 'internal',
options: {
body: {
accepts: ['application/json'],
},
},
},
async (context, request, response) => {
const coreContext = await context.core;
const { index, mappings } = request.body;
const indexPatternsService = await dataPlugin.indexPatterns.dataViewsServiceFactory(
coreContext.savedObjects.client,
coreContext.elasticsearch.client.asCurrentUser,
request
);
const result = await createDocSource(
index,
mappings,
coreContext.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: INDEX_FEATURE_PATH,
validate: {
body: schema.object({
index: schema.string(),
data: schema.any(),
}),
})
.addVersion(
{
version: '1',
validate: {
request: {
body: schema.object({
index: schema.string(),
mappings: schema.any(),
}),
},
},
},
async (context, request, response) => {
const coreContext = await context.core;
const { index, mappings } = request.body;
const indexPatternsService = await dataPlugin.indexPatterns.dataViewsServiceFactory(
coreContext.savedObjects.client,
coreContext.elasticsearch.client.asCurrentUser,
request
);
const result = await createDocSource(
index,
mappings,
coreContext.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.versioned
.post({
path: INDEX_FEATURE_PATH,
access: 'internal',
options: {
body: {
accepts: ['application/json'],
maxBytes: MAX_DRAWING_SIZE_BYTES,
},
},
},
async (context, request, response) => {
const coreContext = await context.core;
const result = await writeDataToIndex(
request.body.index,
request.body.data,
coreContext.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,
});
}
}
);
router.delete(
{
path: `${INDEX_FEATURE_PATH}/{featureId}`,
validate: {
params: schema.object({
featureId: schema.string(),
}),
body: schema.object({
index: schema.string(),
}),
})
.addVersion(
{
version: '1',
validate: {
request: {
body: schema.object({
index: schema.string(),
data: schema.any(),
}),
},
},
},
},
async (context, request, response) => {
try {
async (context, request, response) => {
const coreContext = await context.core;
const resp = await coreContext.elasticsearch.client.asCurrentUser.delete({
index: request.body.index,
id: request.params.featureId,
refresh: true,
});
// @ts-expect-error always false
if (resp.result === 'Error') {
throw resp;
} else {
return response.ok({ body: { success: true } });
}
} catch (error) {
logger.error(error);
const errorStatusCode = error.meta?.statusCode;
if (errorStatusCode === 401) {
return response.unauthorized({
body: {
message: 'User not authorized to delete indexed feature',
},
});
} else if (errorStatusCode === 403) {
return response.forbidden({
body: {
message: 'Access to delete indexed feature forbidden',
},
});
} else if (errorStatusCode === 404) {
return response.notFound({
body: { message: 'Feature not found' },
});
const result = await writeDataToIndex(
request.body.index,
request.body.data,
coreContext.elasticsearch.client.asCurrentUser
);
if (result.success) {
return response.ok({ body: result });
} else {
logger.error(result.error);
return response.custom({
body: 'Unknown error deleting feature',
body: result.error.message,
statusCode: 500,
});
}
}
}
);
);
router.get(
{
path: GET_MATCHING_INDEXES_PATH,
validate: {
query: schema.object({
indexPattern: schema.string(),
}),
router.versioned
.delete({
path: `${INDEX_FEATURE_PATH}/{featureId}`,
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({
featureId: schema.string(),
}),
body: schema.object({
index: schema.string(),
}),
},
},
},
},
async (context, request, response) => {
const coreContext = await context.core;
return await getMatchingIndexes(
request.query.indexPattern,
coreContext.elasticsearch.client,
response,
logger
);
}
);
router.get(
{
path: CHECK_IS_DRAWING_INDEX,
validate: {
query: schema.object({
index: schema.string(),
}),
},
},
async (context, request, response) => {
const { index } = request.query;
try {
const coreContext = await context.core;
const mappingsResp =
await coreContext.elasticsearch.client.asCurrentUser.indices.getMapping({
index: request.query.index,
async (context, request, response) => {
try {
const coreContext = await context.core;
const resp = await coreContext.elasticsearch.client.asCurrentUser.delete({
index: request.body.index,
id: request.params.featureId,
refresh: true,
});
const isDrawingIndex =
mappingsResp[index].mappings?._meta?.created_by === MAPS_NEW_VECTOR_LAYER_META_CREATED_BY;
return response.ok({
body: {
success: true,
isDrawingIndex,
},
});
} catch (error) {
// Index likely doesn't exist
return response.ok({
body: {
success: false,
error,
},
});
// @ts-expect-error always false
if (resp.result === 'Error') {
throw resp;
} else {
return response.ok({ body: { success: true } });
}
} catch (error) {
logger.error(error);
const errorStatusCode = error.meta?.statusCode;
if (errorStatusCode === 401) {
return response.unauthorized({
body: {
message: 'User not authorized to delete indexed feature',
},
});
} else if (errorStatusCode === 403) {
return response.forbidden({
body: {
message: 'Access to delete indexed feature forbidden',
},
});
} else if (errorStatusCode === 404) {
return response.notFound({
body: { message: 'Feature not found' },
});
} else {
return response.custom({
body: 'Unknown error deleting feature',
statusCode: 500,
});
}
}
}
}
);
);
router.versioned
.get({
path: GET_MATCHING_INDEXES_PATH,
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
query: schema.object({
indexPattern: schema.string(),
}),
},
},
},
async (context, request, response) => {
const coreContext = await context.core;
return await getMatchingIndexes(
request.query.indexPattern,
coreContext.elasticsearch.client,
response,
logger
);
}
);
router.versioned
.get({
path: CHECK_IS_DRAWING_INDEX,
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
query: schema.object({
index: schema.string(),
}),
},
},
},
async (context, request, response) => {
const { index } = request.query;
try {
const coreContext = await context.core;
const mappingsResp =
await coreContext.elasticsearch.client.asCurrentUser.indices.getMapping({
index: request.query.index,
});
const isDrawingIndex =
mappingsResp[index].mappings?._meta?.created_by ===
MAPS_NEW_VECTOR_LAYER_META_CREATED_BY;
return response.ok({
body: {
success: true,
isDrawingIndex,
},
});
} catch (error) {
// Index likely doesn't exist
return response.ok({
body: {
success: false,
error,
},
});
}
}
);
}

View file

@ -17,7 +17,6 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import {
APP_ID,
MVT_GETTILE_API_PATH,
API_ROOT_PATH,
MVT_GETGRIDTILE_API_PATH,
RENDER_AS,
} from '../../common/constants';
@ -34,147 +33,161 @@ export function initMVTRoutes({
logger: Logger;
core: CoreStart;
}) {
router.get(
{
path: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`,
validate: {
params: schema.object({
x: schema.number(),
y: schema.number(),
z: schema.number(),
}),
query: schema.object({
buffer: schema.maybe(schema.number()),
geometryFieldName: schema.string(),
hasLabels: schema.boolean(),
requestBody: schema.string(),
index: schema.string(),
token: schema.maybe(schema.string()),
executionContextId: schema.maybe(schema.string()),
}),
router.versioned
.get({
path: `${MVT_GETTILE_API_PATH}/{z}/{x}/{y}.pbf`,
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({
x: schema.number(),
y: schema.number(),
z: schema.number(),
}),
query: schema.object({
buffer: schema.maybe(schema.number()),
geometryFieldName: schema.string(),
hasLabels: schema.boolean(),
requestBody: schema.string(),
index: schema.string(),
token: schema.maybe(schema.string()),
executionContextId: schema.maybe(schema.string()),
}),
},
},
},
},
async (
context: DataRequestHandlerContext,
request: KibanaRequest<unknown, Record<string, any>, unknown>,
response: KibanaResponseFactory
) => {
const { query, params } = request;
const x = parseInt((params as any).x, 10) as number;
const y = parseInt((params as any).y, 10) as number;
const z = parseInt((params as any).z, 10) as number;
async (
context: DataRequestHandlerContext,
request: KibanaRequest<unknown, Record<string, any>, unknown>,
response: KibanaResponseFactory
) => {
const { query, params } = request;
const x = parseInt((params as any).x, 10) as number;
const y = parseInt((params as any).y, 10) as number;
const z = parseInt((params as any).z, 10) as number;
let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = {
path: '',
body: {},
};
try {
tileRequest = getHitsTileRequest({
buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5,
risonRequestBody: query.requestBody as string,
geometryFieldName: query.geometryFieldName as string,
hasLabels: query.hasLabels as boolean,
index: query.index as string,
x,
y,
z,
let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = {
path: '',
body: {},
};
try {
tileRequest = getHitsTileRequest({
buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5,
risonRequestBody: query.requestBody as string,
geometryFieldName: query.geometryFieldName as string,
hasLabels: query.hasLabels as boolean,
index: query.index as string,
x,
y,
z,
});
} catch (e) {
return response.badRequest();
}
const { stream, headers, statusCode } = await getTile({
abortController: makeAbortController(request),
body: tileRequest.body,
context,
core,
executionContext: makeExecutionContext({
type: 'server',
name: APP_ID,
description: 'mvt:get_hits_tile',
url: `${MVT_GETTILE_API_PATH}/${z}/${x}/${y}.pbf`,
id: query.executionContextId,
}),
logger,
path: tileRequest.path,
});
} catch (e) {
return response.badRequest();
return sendResponse(response, stream, headers, statusCode);
}
);
const { stream, headers, statusCode } = await getTile({
abortController: makeAbortController(request),
body: tileRequest.body,
context,
core,
executionContext: makeExecutionContext({
type: 'server',
name: APP_ID,
description: 'mvt:get_hits_tile',
url: `${API_ROOT_PATH}/${MVT_GETTILE_API_PATH}/${z}/${x}/${y}.pbf`,
id: query.executionContextId,
}),
logger,
path: tileRequest.path,
});
return sendResponse(response, stream, headers, statusCode);
}
);
router.get(
{
path: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`,
validate: {
params: schema.object({
x: schema.number(),
y: schema.number(),
z: schema.number(),
}),
query: schema.object({
buffer: schema.maybe(schema.number()),
geometryFieldName: schema.string(),
hasLabels: schema.boolean(),
requestBody: schema.string(),
index: schema.string(),
renderAs: schema.string(),
token: schema.maybe(schema.string()),
gridPrecision: schema.number(),
executionContextId: schema.maybe(schema.string()),
}),
router.versioned
.get({
path: `${MVT_GETGRIDTILE_API_PATH}/{z}/{x}/{y}.pbf`,
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({
x: schema.number(),
y: schema.number(),
z: schema.number(),
}),
query: schema.object({
buffer: schema.maybe(schema.number()),
geometryFieldName: schema.string(),
hasLabels: schema.boolean(),
requestBody: schema.string(),
index: schema.string(),
renderAs: schema.string(),
token: schema.maybe(schema.string()),
gridPrecision: schema.number(),
executionContextId: schema.maybe(schema.string()),
}),
},
},
},
},
async (
context: DataRequestHandlerContext,
request: KibanaRequest<unknown, Record<string, any>, unknown>,
response: KibanaResponseFactory
) => {
const { query, params } = request;
const x = parseInt((params as any).x, 10) as number;
const y = parseInt((params as any).y, 10) as number;
const z = parseInt((params as any).z, 10) as number;
async (
context: DataRequestHandlerContext,
request: KibanaRequest<unknown, Record<string, any>, unknown>,
response: KibanaResponseFactory
) => {
const { query, params } = request;
const x = parseInt((params as any).x, 10) as number;
const y = parseInt((params as any).y, 10) as number;
const z = parseInt((params as any).z, 10) as number;
let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = {
path: '',
body: {},
};
try {
tileRequest = getAggsTileRequest({
buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5,
risonRequestBody: query.requestBody as string,
geometryFieldName: query.geometryFieldName as string,
gridPrecision: parseInt(query.gridPrecision, 10),
hasLabels: query.hasLabels as boolean,
index: query.index as string,
renderAs: query.renderAs as RENDER_AS,
x,
y,
z,
let tileRequest: { path: string; body: estypes.SearchMvtRequest['body'] } = {
path: '',
body: {},
};
try {
tileRequest = getAggsTileRequest({
buffer: 'buffer' in query ? parseInt(query.buffer, 10) : 5,
risonRequestBody: query.requestBody as string,
geometryFieldName: query.geometryFieldName as string,
gridPrecision: parseInt(query.gridPrecision, 10),
hasLabels: query.hasLabels as boolean,
index: query.index as string,
renderAs: query.renderAs as RENDER_AS,
x,
y,
z,
});
} catch (e) {
return response.badRequest();
}
const { stream, headers, statusCode } = await getTile({
abortController: makeAbortController(request),
body: tileRequest.body,
context,
core,
executionContext: makeExecutionContext({
type: 'server',
name: APP_ID,
description: 'mvt:get_aggs_tile',
url: `${MVT_GETGRIDTILE_API_PATH}/${z}/${x}/${y}.pbf`,
id: query.executionContextId,
}),
logger,
path: tileRequest.path,
});
} catch (e) {
return response.badRequest();
return sendResponse(response, stream, headers, statusCode);
}
const { stream, headers, statusCode } = await getTile({
abortController: makeAbortController(request),
body: tileRequest.body,
context,
core,
executionContext: makeExecutionContext({
type: 'server',
name: APP_ID,
description: 'mvt:get_aggs_tile',
url: `${API_ROOT_PATH}/${MVT_GETGRIDTILE_API_PATH}/${z}/${x}/${y}.pbf`,
id: query.executionContextId,
}),
logger,
path: tileRequest.path,
});
return sendResponse(response, stream, headers, statusCode);
}
);
);
}
async function getTile({

View file

@ -21,79 +21,93 @@ export async function initRoutes(coreSetup: CoreSetup, logger: Logger): Promise<
const [coreStart, { data: dataPlugin }]: [CoreStart, StartDeps] =
(await coreSetup.getStartServices()) as unknown as [CoreStart, StartDeps];
router.get(
{
router.versioned
.get({
path: `/${FONTS_API_PATH}/{fontstack}/{range}`,
validate: {
params: schema.object({
fontstack: schema.string(),
range: schema.string(),
}),
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({
fontstack: schema.string(),
range: schema.string(),
}),
},
},
},
},
(context, request, response) => {
const range = path.normalize(request.params.range);
const rootPath = path.resolve(__dirname, 'fonts', 'open_sans');
const fontPath = path.resolve(rootPath, `${range}.pbf`);
return !fontPath.startsWith(rootPath)
? response.notFound()
: new Promise((resolve) => {
fs.readFile(fontPath, (error, data) => {
if (error) {
resolve(response.notFound());
} else {
resolve(
response.ok({
body: data,
})
);
}
(context, request, response) => {
const range = path.normalize(request.params.range);
const rootPath = path.resolve(__dirname, 'fonts', 'open_sans');
const fontPath = path.resolve(rootPath, `${range}.pbf`);
return !fontPath.startsWith(rootPath)
? response.notFound()
: new Promise((resolve) => {
fs.readFile(fontPath, (error, data) => {
if (error) {
resolve(response.notFound());
} else {
resolve(
response.ok({
body: data,
})
);
}
});
});
});
}
);
}
);
router.get(
{
router.versioned
.get({
path: `/${INDEX_SETTINGS_API_PATH}`,
validate: {
query: schema.object({
indexPatternTitle: schema.string(),
}),
access: 'internal',
})
.addVersion(
{
version: '1',
validate: {
request: {
query: schema.object({
indexPatternTitle: schema.string(),
}),
},
},
},
},
async (context, request, response) => {
const { query } = request;
if (!query.indexPatternTitle) {
logger.warn(`Required query parameter 'indexPatternTitle' not provided.`);
return response.custom({
body: `Required query parameter 'indexPatternTitle' not provided.`,
statusCode: 400,
});
}
async (context, request, response) => {
const { query } = request;
if (!query.indexPatternTitle) {
logger.warn(`Required query parameter 'indexPatternTitle' not provided.`);
return response.custom({
body: `Required query parameter 'indexPatternTitle' not provided.`,
statusCode: 400,
});
}
try {
const coreContext = await context.core;
const resp = await coreContext.elasticsearch.client.asCurrentUser.indices.getSettings({
index: query.indexPatternTitle,
});
const indexPatternSettings = getIndexPatternSettings(
resp as unknown as Record<string, string | number | boolean>
);
return response.ok({
body: indexPatternSettings,
});
} catch (error) {
logger.warn(
`Cannot load index settings for data view '${query.indexPatternTitle}', error: ${error.message}.`
);
return response.custom({
body: 'Error loading index settings',
statusCode: 400,
});
try {
const coreContext = await context.core;
const resp = await coreContext.elasticsearch.client.asCurrentUser.indices.getSettings({
index: query.indexPatternTitle,
});
const indexPatternSettings = getIndexPatternSettings(
resp as unknown as Record<string, string | number | boolean>
);
return response.ok({
body: indexPatternSettings,
});
} catch (error) {
logger.warn(
`Cannot load index settings for data view '${query.indexPatternTitle}', error: ${error.message}.`
);
return response.custom({
body: 'Error loading index settings',
statusCode: 400,
});
}
}
}
);
);
initMVTRoutes({ router, logger, core: coreStart });
initIndexingRoutes({ router, logger, dataPlugin });

View file

@ -70,6 +70,7 @@
"@kbn/content-management-utils",
"@kbn/core-saved-objects-server",
"@kbn/maps-vector-tile-utils",
"@kbn/core-http-common",
],
"exclude": [
"target/**/*",

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
@ -13,8 +14,9 @@ export default function ({ getService }) {
describe('doc source creation', () => {
it('should create a new index and pattern but not clobber an existing one', async () => {
const resp = await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'testing123',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
@ -25,8 +27,9 @@ export default function ({ getService }) {
// Repeated index fails. We don't want the user clobbering indexes
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'testing123',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
@ -36,8 +39,9 @@ export default function ({ getService }) {
it('should fail to create index and pattern with invalid index', async () => {
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: '_testing456',
mappings: { properties: { coordinates: { type: 'geo_point' } } },

View file

@ -5,14 +5,17 @@
* 2.0.
*/
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
describe('doc feature deletion', () => {
it('should delete a valid feature document', async () => {
await supertest
.delete(`/api/maps/feature/999`)
.delete(`/internal/maps/feature/999`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'drawing_data',
})
@ -21,8 +24,9 @@ export default function ({ getService }) {
it('previously deleted document no longer exists in index', async () => {
await supertest
.delete(`/api/maps/feature/999`)
.delete(`/internal/maps/feature/999`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'drawing_data',
})
@ -31,8 +35,9 @@ export default function ({ getService }) {
it('should fail if not a valid document', async () => {
await supertest
.delete(`/api/maps/feature/998`)
.delete(`/internal/maps/feature/998`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'drawing_data',
})

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import path from 'path';
import { copyFile, rm } from 'fs/promises';
@ -35,7 +36,8 @@ export default function ({ getService }) {
it('should return fonts', async () => {
const resp = await supertest
.get(`/api/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255`)
.get(`/internal/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255`)
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.length).to.be(74696);
@ -43,16 +45,25 @@ export default function ({ getService }) {
it('should return 404 when file not found', async () => {
await supertest
.get(`/api/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/noGonaFindMe`)
.get(
`/internal/maps/fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/noGonaFindMe`
)
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(404);
});
it('should return 404 when file is not in font folder (..)', async () => {
await supertest.get(`/api/maps/fonts/open_sans/..%2f0-255`).expect(404);
await supertest
.get(`/internal/maps/fonts/open_sans/..%2f0-255`)
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(404);
});
it('should return 404 when file is not in font folder (./..)', async () => {
await supertest.get(`/api/maps/fonts/open_sans/.%2f..%2f0-255`).expect(404);
await supertest
.get(`/internal/maps/fonts/open_sans/.%2f..%2f0-255`)
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(404);
});
});
}

View file

@ -9,6 +9,7 @@ import { VectorTile } from '@mapbox/vector-tile';
import Protobuf from 'pbf';
import expect from '@kbn/expect';
import { getTileUrlParams } from '@kbn/maps-vector-tile-utils';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
function findFeature(layer, callbackFn) {
for (let i = 0; i < layer.length; i++) {
@ -71,8 +72,9 @@ export default function ({ getService }) {
it('should return vector tile with expected headers', async () => {
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -84,8 +86,9 @@ export default function ({ getService }) {
it('should return vector tile containing clusters when renderAs is "point"', async () => {
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -114,8 +117,9 @@ export default function ({ getService }) {
renderAs: 'heatmap',
});
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -144,8 +148,9 @@ export default function ({ getService }) {
renderAs: 'grid',
});
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -181,8 +186,9 @@ export default function ({ getService }) {
renderAs: 'hex',
});
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -221,8 +227,9 @@ export default function ({ getService }) {
renderAs: 'hex',
});
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -248,8 +255,9 @@ export default function ({ getService }) {
it('should return vector tile with meta layer', async () => {
const resp = await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + getTileUrlParams(defaultParams))
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -293,8 +301,9 @@ export default function ({ getService }) {
index: 'notRealIndex',
});
await supertest
.get('/api/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.get('/internal/maps/mvt/getGridTile/3/2/3.pbf?' + tileUrlParams)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(404);
});

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
@ -13,8 +14,9 @@ export default function ({ getService }) {
describe('get matching index patterns', () => {
it('should return an array containing indexes matching pattern', async () => {
const resp = await supertest
.get(`/api/maps/getMatchingIndexes?indexPattern=geo_shapes`)
.get(`/internal/maps/getMatchingIndexes?indexPattern=geo_shapes`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send()
.expect(200);
@ -24,8 +26,9 @@ export default function ({ getService }) {
it('should return an empty array when no indexes match pattern', async () => {
const resp = await supertest
.get(`/api/maps/getMatchingIndexes?indexPattern=notAnIndex`)
.get(`/internal/maps/getMatchingIndexes?indexPattern=notAnIndex`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send()
.expect(200);

View file

@ -8,6 +8,7 @@
import { VectorTile } from '@mapbox/vector-tile';
import Protobuf from 'pbf';
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { getTileUrlParams } from '@kbn/maps-vector-tile-utils';
function findFeature(layer, callbackFn) {
@ -71,8 +72,9 @@ export default function ({ getService }) {
it('should return ES vector tile containing documents and metadata', async () => {
const resp = await supertest
.get(`/api/maps/mvt/getTile/2/1/1.pbf?${getTileUrlParams(defaultParams)}`)
.get(`/internal/maps/mvt/getTile/2/1/1.pbf?${getTileUrlParams(defaultParams)}`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -133,8 +135,9 @@ export default function ({ getService }) {
hasLabels: true,
});
const resp = await supertest
.get(`/api/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`)
.get(`/internal/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(200);
@ -176,8 +179,9 @@ export default function ({ getService }) {
index: 'notRealIndex',
});
await supertest
.get(`/api/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`)
.get(`/internal/maps/mvt/getTile/2/1/1.pbf?${tileUrlParams}`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.responseType('blob')
.expect(404);
});

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
@ -13,16 +14,18 @@ export default function ({ getService }) {
describe('index feature data', () => {
it('should add point data to an existing index', async () => {
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-point-feature-index',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
});
const resp = await supertest
.post(`/api/maps/feature`)
.post(`/internal/maps/feature`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-point-feature-index',
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },
@ -34,16 +37,18 @@ export default function ({ getService }) {
it('should add shape data to an existing index', async () => {
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-shape-feature-index',
mappings: { properties: { coordinates: { type: 'geo_shape' } } },
});
const resp = await supertest
.post(`/api/maps/feature`)
.post(`/internal/maps/feature`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-shape-feature-index',
data: {
@ -68,15 +73,17 @@ export default function ({ getService }) {
it('should fail if data is invalid', async () => {
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-feature-index2',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
});
await supertest
.post(`/api/maps/feature`)
.post(`/internal/maps/feature`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'new-feature-index2',
data: { coordinates: [600, 800], name: 'Never Gonna Happen Islands' },
@ -86,8 +93,9 @@ export default function ({ getService }) {
it('should fail if index does not exist', async () => {
await supertest
.post(`/api/maps/feature`)
.post(`/internal/maps/feature`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'not-an-index',
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
@ -13,8 +14,9 @@ export default function ({ getService }) {
describe('index settings', () => {
it('should return default index settings when max_result_window and max_inner_result_window are not set', async () => {
const resp = await supertest
.get(`/api/maps/indexSettings?indexPatternTitle=logstash*`)
.get(`/internal/maps/indexSettings?indexPatternTitle=logstash*`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.maxResultWindow).to.be(10000);
@ -23,8 +25,9 @@ export default function ({ getService }) {
it('should return index settings', async () => {
const resp = await supertest
.get(`/api/maps/indexSettings?indexPatternTitle=geo_shape*`)
.get(`/internal/maps/indexSettings?indexPatternTitle=geo_shape*`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.maxResultWindow).to.be(10001);

View file

@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
export default function ({ getService }) {
const supertest = getService('supertest');
@ -13,16 +14,18 @@ export default function ({ getService }) {
describe('validate drawing index', () => {
it('confirm valid drawing index', async () => {
await supertest
.post(`/api/maps/docSource`)
.post(`/internal/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.send({
index: 'valid-drawing-index',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
});
const resp = await supertest
.get(`/api/maps/checkIsDrawingIndex?index=valid-drawing-index`)
.get(`/internal/maps/checkIsDrawingIndex?index=valid-drawing-index`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.success).to.be(true);
@ -31,8 +34,9 @@ export default function ({ getService }) {
it('confirm valid index that is not a drawing index', async () => {
const resp = await supertest
.get(`/api/maps/checkIsDrawingIndex?index=geo_shapes`)
.get(`/internal/maps/checkIsDrawingIndex?index=geo_shapes`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.success).to.be(true);
@ -41,8 +45,9 @@ export default function ({ getService }) {
it('confirm invalid index', async () => {
const resp = await supertest
.get(`/api/maps/checkIsDrawingIndex?index=not-an-index`)
.get(`/internal/maps/checkIsDrawingIndex?index=not-an-index`)
.set('kbn-xsrf', 'kibana')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.expect(200);
expect(resp.body.success).to.be(false);

View file

@ -37,7 +37,9 @@ export default function ({ getPageObjects, getService }) {
);
const searchParams = Object.fromEntries(tileUrl.searchParams);
expect(tileUrl.pathname).to.equal('/api/maps/mvt/getGridTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf');
expect(tileUrl.pathname).to.equal(
'/internal/maps/mvt/getGridTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf'
);
// token is an unique id that changes between runs
expect(typeof searchParams.token).to.equal('string');

View file

@ -35,14 +35,14 @@ export default function ({ getPageObjects, getService }) {
mapboxStyle = await PageObjects.maps.getMapboxStyle();
});
it('should request tiles from /api/maps/mvt/getTile', async () => {
it('should request tiles from /internal/maps/mvt/getTile', async () => {
const tileUrl = new URL(
mapboxStyle.sources[VECTOR_SOURCE_ID].tiles[0],
'http://absolute_path'
);
const searchParams = Object.fromEntries(tileUrl.searchParams);
expect(tileUrl.pathname).to.equal('/api/maps/mvt/getTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf');
expect(tileUrl.pathname).to.equal('/internal/maps/mvt/getTile/%7Bz%7D/%7Bx%7D/%7By%7D.pbf');
// token is an unique id that changes between runs
expect(typeof searchParams.token).to.equal('string');