Skip to content

Commit

Permalink
[ML] New Platform server shim: update calendar routes to use new plat…
Browse files Browse the repository at this point in the history
…form router (#56264)

* migrate calendar routes to NP

* add proper types for calendars and events

* set actual client in constructor so isLegacy is not stored

* remove unnecessary comments

* fix calendar schema for missing calendar_id and event_id properties
  • Loading branch information
alvarezmelissa87 authored Jan 30, 2020
1 parent a8622cf commit fb334ef
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,44 @@
* you may not use this file except in compliance with the Elastic License.
*/

import _ from 'lodash';
import { difference } from 'lodash';
import Boom from 'boom';
import { EventManager } from './event_manager';
import { EventManager, CalendarEvent } from './event_manager';

interface BasicCalendar {
job_ids: string[];
description?: string;
events: CalendarEvent[];
}

export interface Calendar extends BasicCalendar {
calendar_id: string;
}

export interface FormCalendar extends BasicCalendar {
calendarId: string;
}

export class CalendarManager {
constructor(callWithRequest) {
this.callWithRequest = callWithRequest;
this.eventManager = new EventManager(callWithRequest);
private _client: any;
private _eventManager: any;

constructor(isLegacy: boolean, client: any) {
const actualClient = isLegacy === true ? client : client.ml!.mlClient.callAsCurrentUser;
this._client = actualClient;
this._eventManager = new EventManager(actualClient);
}

async getCalendar(calendarId) {
async getCalendar(calendarId: string) {
try {
const resp = await this.callWithRequest('ml.calendars', { calendarId });
const resp = await this._client('ml.calendars', {
calendarId,
});

const calendars = resp.calendars;
if (calendars.length) {
const calendar = calendars[0];
calendar.events = await this.eventManager.getCalendarEvents(calendarId);
calendar.events = await this._eventManager.getCalendarEvents(calendarId);
return calendar;
} else {
throw Boom.notFound(`Calendar with the id "${calendarId}" not found`);
Expand All @@ -32,9 +53,10 @@ export class CalendarManager {

async getAllCalendars() {
try {
const calendarsResp = await this.callWithRequest('ml.calendars');
const events = await this.eventManager.getAllEvents();
const calendars = calendarsResp.calendars;
const calendarsResp = await this._client('ml.calendars');

const events: CalendarEvent[] = await this._eventManager.getAllEvents();
const calendars: Calendar[] = calendarsResp.calendars;
calendars.forEach(cal => (cal.events = []));

// loop events and combine with related calendars
Expand All @@ -55,24 +77,28 @@ export class CalendarManager {
* @param calendarIds
* @returns {Promise<*>}
*/
async getCalendarsByIds(calendarIds) {
async getCalendarsByIds(calendarIds: string) {
try {
const calendars = await this.getAllCalendars();
const calendars: Calendar[] = await this.getAllCalendars();
return calendars.filter(calendar => calendarIds.includes(calendar.calendar_id));
} catch (error) {
throw Boom.badRequest(error);
}
}

async newCalendar(calendar) {
async newCalendar(calendar: FormCalendar) {
const calendarId = calendar.calendarId;
const events = calendar.events;
delete calendar.calendarId;
delete calendar.events;
try {
await this.callWithRequest('ml.addCalendar', { calendarId, body: calendar });
await this._client('ml.addCalendar', {
calendarId,
body: calendar,
});

if (events.length) {
await this.eventManager.addEvents(calendarId, events);
await this._eventManager.addEvents(calendarId, events);
}

// return the newly created calendar
Expand All @@ -82,52 +108,52 @@ export class CalendarManager {
}
}

async updateCalendar(calendarId, calendar) {
const origCalendar = await this.getCalendar(calendarId);
async updateCalendar(calendarId: string, calendar: Calendar) {
const origCalendar: Calendar = await this.getCalendar(calendarId);
try {
// update job_ids
const jobsToAdd = _.difference(calendar.job_ids, origCalendar.job_ids);
const jobsToRemove = _.difference(origCalendar.job_ids, calendar.job_ids);
const jobsToAdd = difference(calendar.job_ids, origCalendar.job_ids);
const jobsToRemove = difference(origCalendar.job_ids, calendar.job_ids);

// workout the differences between the original events list and the new one
// if an event has no event_id, it must be new
const eventsToAdd = calendar.events.filter(
event => origCalendar.events.find(e => this.eventManager.isEqual(e, event)) === undefined
event => origCalendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// if an event in the original calendar cannot be found, it must have been deleted
const eventsToRemove = origCalendar.events.filter(
event => calendar.events.find(e => this.eventManager.isEqual(e, event)) === undefined
const eventsToRemove: CalendarEvent[] = origCalendar.events.filter(
event => calendar.events.find(e => this._eventManager.isEqual(e, event)) === undefined
);

// note, both of the loops below could be removed if the add and delete endpoints
// allowed multiple job_ids

//add all new jobs
// add all new jobs
if (jobsToAdd.length) {
await this.callWithRequest('ml.addJobToCalendar', {
await this._client('ml.addJobToCalendar', {
calendarId,
jobId: jobsToAdd.join(','),
});
}

//remove all removed jobs
// remove all removed jobs
if (jobsToRemove.length) {
await this.callWithRequest('ml.removeJobFromCalendar', {
await this._client('ml.removeJobFromCalendar', {
calendarId,
jobId: jobsToRemove.join(','),
});
}

// add all new events
if (eventsToAdd.length !== 0) {
await this.eventManager.addEvents(calendarId, eventsToAdd);
await this._eventManager.addEvents(calendarId, eventsToAdd);
}

// remove all removed events
await Promise.all(
eventsToRemove.map(async event => {
await this.eventManager.deleteEvent(calendarId, event.event_id);
await this._eventManager.deleteEvent(calendarId, event.event_id);
})
);
} catch (error) {
Expand All @@ -138,7 +164,7 @@ export class CalendarManager {
return await this.getCalendar(calendarId);
}

async deleteCalendar(calendarId) {
return this.callWithRequest('ml.deleteCalendar', { calendarId });
async deleteCalendar(calendarId: string) {
return this._client('ml.deleteCalendar', { calendarId });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,63 @@

import Boom from 'boom';

export interface CalendarEvent {
calendar_id?: string;
event_id?: string;
description: string;
start_time: number;
end_time: number;
}

export class EventManager {
constructor(callWithRequest) {
this.callWithRequest = callWithRequest;
private _client: any;
constructor(client: any) {
this._client = client;
}

async getCalendarEvents(calendarId) {
async getCalendarEvents(calendarId: string) {
try {
const resp = await this.callWithRequest('ml.events', { calendarId });
const resp = await this._client('ml.events', { calendarId });

return resp.events;
} catch (error) {
throw Boom.badRequest(error);
}
}

// jobId is optional
async getAllEvents(jobId) {
async getAllEvents(jobId?: string) {
const calendarId = '_all';
try {
const resp = await this.callWithRequest('ml.events', { calendarId, jobId });
const resp = await this._client('ml.events', {
calendarId,
jobId,
});

return resp.events;
} catch (error) {
throw Boom.badRequest(error);
}
}

async addEvents(calendarId, events) {
async addEvents(calendarId: string, events: CalendarEvent[]) {
const body = { events };

try {
return await this.callWithRequest('ml.addEvent', { calendarId, body });
return await this._client('ml.addEvent', {
calendarId,
body,
});
} catch (error) {
throw Boom.badRequest(error);
}
}

async deleteEvent(calendarId, eventId) {
return this.callWithRequest('ml.deleteEvent', { calendarId, eventId });
async deleteEvent(calendarId: string, eventId: string) {
return this._client('ml.deleteEvent', { calendarId, eventId });
}

isEqual(ev1, ev2) {
isEqual(ev1: CalendarEvent, ev2: CalendarEvent) {
return (
ev1.event_id === ev2.event_id &&
ev1.description === ev2.description &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/

export { CalendarManager } from './calendar_manager';
export { CalendarManager, Calendar, FormCalendar } from './calendar_manager';
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { CalendarManager } from '../calendar';

export function groupsProvider(callWithRequest) {
const calMngr = new CalendarManager(callWithRequest);
const calMngr = new CalendarManager(true, callWithRequest);

async function getAllGroups() {
const groups = {};
Expand Down
2 changes: 1 addition & 1 deletion x-pack/legacy/plugins/ml/server/models/job_service/jobs.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function jobsProvider(callWithRequest) {
const { forceDeleteDatafeed, getDatafeedIdsByJobId } = datafeedsProvider(callWithRequest);
const { getAuditMessagesSummary } = jobAuditMessagesProvider(callWithRequest);
const { getLatestBucketTimestampByJob } = resultsServiceProvider(callWithRequest);
const calMngr = new CalendarManager(callWithRequest);
const calMngr = new CalendarManager(true, callWithRequest);

async function forceDeleteJob(jobId) {
return callWithRequest('ml.deleteJob', { jobId, force: true });
Expand Down
25 changes: 25 additions & 0 deletions x-pack/legacy/plugins/ml/server/new_platform/calendars_schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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 { schema } from '@kbn/config-schema';

export const calendarSchema = {
calendar_id: schema.maybe(schema.string()),
calendarId: schema.string(),
job_ids: schema.arrayOf(schema.maybe(schema.string())),
description: schema.maybe(schema.string()),
events: schema.arrayOf(
schema.maybe(
schema.object({
event_id: schema.maybe(schema.string()),
calendar_id: schema.maybe(schema.string()),
description: schema.maybe(schema.string()),
start_time: schema.any(),
end_time: schema.any(),
})
)
),
};
2 changes: 0 additions & 2 deletions x-pack/legacy/plugins/ml/server/new_platform/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,11 @@ import { makeMlUsageCollector } from '../lib/ml_telemetry';
import { notificationRoutes } from '../routes/notification_settings';
// @ts-ignore: could not find declaration file for module
import { systemRoutes } from '../routes/system';
// @ts-ignore: could not find declaration file for module
import { dataFrameAnalyticsRoutes } from '../routes/data_frame_analytics';
// @ts-ignore: could not find declaration file for module
import { dataRecognizer } from '../routes/modules';
// @ts-ignore: could not find declaration file for module
import { dataVisualizerRoutes } from '../routes/data_visualizer';
// @ts-ignore: could not find declaration file for module
import { calendars } from '../routes/calendars';
// @ts-ignore: could not find declaration file for module
import { fieldsService } from '../routes/fields_service';
Expand Down
Loading

0 comments on commit fb334ef

Please sign in to comment.