Skip to content

Commit

Permalink
[RAM][HTTP Versioning] Version Rule Bulk Edit Endpoint (#161912)
Browse files Browse the repository at this point in the history
## Summary

Resolves: #161395
Parent Issue: #157883

Adds versioned types to the rule `bulk_edit` endpoint.

This PR also moves around the folder structure slightly, by adding a sub
folder for the `data`/`route`/`application` methods:

## Before

![image](https://github.com/elastic/kibana/assets/74562234/3ae19871-cc5c-4180-b099-5fed86c3870b)

## After

![image](https://github.com/elastic/kibana/assets/74562234/bbd67bb4-4899-4f65-966e-64964f994a04)

Notice I added a `methods` folder to contain the methods, I did the same
for the `data` and `route` folders as well. I think this improves the
hierarchy of these modules, If folks are ok with it then I will update
the doc with the new folder structure.

### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
JiaweiWu and kibanamachine authored Jul 25, 2023
1 parent 71ebc38 commit d4e6a19
Show file tree
Hide file tree
Showing 101 changed files with 2,290 additions and 1,254 deletions.
12 changes: 12 additions & 0 deletions x-pack/plugins/alerting/common/routes/r_rule/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

export { rRuleSchema } from './schemas/latest';
export type { RRule } from './types/latest';

export { rRuleSchema as rRuleSchemaV1 } from './schemas/v1';
export type { RRule as RRuleV1 } from './types/latest';
51 changes: 51 additions & 0 deletions x-pack/plugins/alerting/common/routes/r_rule/schemas/v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 {
validateStartDateV1,
validateEndDateV1,
createValidateRecurrenceByV1,
} from '../validation';

export const rRuleSchema = schema.object({
dtstart: schema.string({ validate: validateStartDateV1 }),
tzid: schema.string(),
freq: schema.maybe(
schema.oneOf([schema.literal(0), schema.literal(1), schema.literal(2), schema.literal(3)])
),
interval: schema.maybe(
schema.number({
validate: (interval: number) => {
if (interval < 1) return 'rRule interval must be > 0';
},
})
),
until: schema.maybe(schema.string({ validate: validateEndDateV1 })),
count: schema.maybe(
schema.number({
validate: (count: number) => {
if (count < 1) return 'rRule count must be > 0';
},
})
),
byweekday: schema.maybe(
schema.arrayOf(schema.string(), {
validate: createValidateRecurrenceByV1('byweekday'),
})
),
bymonthday: schema.maybe(
schema.arrayOf(schema.number(), {
validate: createValidateRecurrenceByV1('bymonthday'),
})
),
bymonth: schema.maybe(
schema.arrayOf(schema.number(), {
validate: createValidateRecurrenceByV1('bymonth'),
})
),
});
10 changes: 10 additions & 0 deletions x-pack/plugins/alerting/common/routes/r_rule/types/v1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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 type { TypeOf } from '@kbn/config-schema';
import { rRuleSchemaV1 } from '..';

export type RRule = TypeOf<typeof rRuleSchemaV1>;
14 changes: 14 additions & 0 deletions x-pack/plugins/alerting/common/routes/r_rule/validation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.
*/

export { validateStartDate } from './validate_start_date/latest';
export { validateEndDate } from './validate_end_date/latest';
export { createValidateRecurrenceBy } from './validate_recurrence_by/latest';

export { validateStartDate as validateStartDateV1 } from './validate_start_date/v1';
export { validateEndDate as validateEndDateV1 } from './validate_end_date/v1';
export { createValidateRecurrenceBy as createValidateRecurrenceByV1 } from './validate_recurrence_by/v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* 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.
*/

export const validateEndDate = (date: string) => {
const parsedValue = Date.parse(date);
if (isNaN(parsedValue)) return `Invalid date: ${date}`;
if (parsedValue <= Date.now()) return `Invalid snooze date as it is in the past: ${date}`;
return;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* 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.
*/

export const validateRecurrenceBy = <T>(name: string, array: T[]) => {
if (array.length === 0) {
return `rRule ${name} cannot be empty`;
}
};

export const createValidateRecurrenceBy = <T>(name: string) => {
return (array: T[]) => validateRecurrenceBy(name, array);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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.
*/

export const validateStartDate = (date: string) => {
const parsedValue = Date.parse(date);
if (isNaN(parsedValue)) return `Invalid date: ${date}`;
return;
};
28 changes: 28 additions & 0 deletions x-pack/plugins/alerting/common/routes/rule/apis/bulk_edit/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.
*/

export {
ruleSnoozeScheduleSchema,
bulkEditOperationsSchema,
bulkEditRulesRequestBodySchema,
} from './schemas/latest';
export type {
RuleSnoozeSchedule,
BulkEditRulesRequestBody,
BulkEditRulesResponse,
} from './types/latest';

export {
ruleSnoozeScheduleSchema as ruleSnoozeScheduleSchemaV1,
bulkEditOperationsSchema as bulkEditOperationsSchemaV1,
bulkEditRulesRequestBodySchema as bulkEditRulesRequestBodySchemaV1,
} from './schemas/v1';
export type {
RuleSnoozeSchedule as RuleSnoozeScheduleV1,
BulkEditRulesRequestBody as BulkEditRulesRequestBodyV1,
BulkEditRulesResponse as BulkEditRulesResponseV1,
} from './types/v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* 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 { validateDurationV1, validateNotifyWhenV1 } from '../../../validation';
import { validateSnoozeScheduleV1 } from '../validation';
import { rRuleSchemaV1 } from '../../../../r_rule';
import { ruleNotifyWhenV1 } from '../../../response';

const notifyWhenSchema = schema.oneOf(
[
schema.literal(ruleNotifyWhenV1.CHANGE),
schema.literal(ruleNotifyWhenV1.ACTIVE),
schema.literal(ruleNotifyWhenV1.THROTTLE),
],
{ validate: validateNotifyWhenV1 }
);

export const scheduleIdsSchema = schema.maybe(schema.arrayOf(schema.string()));

export const ruleSnoozeScheduleSchema = schema.object({
id: schema.maybe(schema.string()),
duration: schema.number(),
rRule: rRuleSchemaV1,
});

const ruleSnoozeScheduleSchemaWithValidation = schema.object(
{
id: schema.maybe(schema.string()),
duration: schema.number(),
rRule: rRuleSchemaV1,
},
{ validate: validateSnoozeScheduleV1 }
);

const ruleActionSchema = schema.object({
group: schema.string(),
id: schema.string(),
params: schema.recordOf(schema.string(), schema.any(), { defaultValue: {} }),
uuid: schema.maybe(schema.string()),
frequency: schema.maybe(
schema.object({
summary: schema.boolean(),
throttle: schema.nullable(schema.string()),
notifyWhen: notifyWhenSchema,
})
),
});

export const bulkEditOperationsSchema = schema.arrayOf(
schema.oneOf([
schema.object({
operation: schema.oneOf([
schema.literal('add'),
schema.literal('delete'),
schema.literal('set'),
]),
field: schema.literal('tags'),
value: schema.arrayOf(schema.string()),
}),
schema.object({
operation: schema.oneOf([schema.literal('add'), schema.literal('set')]),
field: schema.literal('actions'),
value: schema.arrayOf(ruleActionSchema),
}),
schema.object({
operation: schema.literal('set'),
field: schema.literal('schedule'),
value: schema.object({ interval: schema.string({ validate: validateDurationV1 }) }),
}),
schema.object({
operation: schema.literal('set'),
field: schema.literal('throttle'),
value: schema.nullable(schema.string()),
}),
schema.object({
operation: schema.literal('set'),
field: schema.literal('notifyWhen'),
value: notifyWhenSchema,
}),
schema.object({
operation: schema.oneOf([schema.literal('set')]),
field: schema.literal('snoozeSchedule'),
value: ruleSnoozeScheduleSchemaWithValidation,
}),
schema.object({
operation: schema.oneOf([schema.literal('delete')]),
field: schema.literal('snoozeSchedule'),
value: schema.maybe(scheduleIdsSchema),
}),
schema.object({
operation: schema.literal('set'),
field: schema.literal('apiKey'),
}),
]),
{ minSize: 1 }
);

export const bulkEditRulesRequestBodySchema = schema.object({
filter: schema.maybe(schema.string()),
ids: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })),
operations: bulkEditOperationsSchema,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export * from './v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* 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 type { TypeOf } from '@kbn/config-schema';
import { RuleParamsV1, RuleResponseV1 } from '../../../response';
import { ruleSnoozeScheduleSchemaV1, bulkEditRulesRequestBodySchemaV1 } from '..';

export type RuleSnoozeSchedule = TypeOf<typeof ruleSnoozeScheduleSchemaV1>;
export type BulkEditRulesRequestBody = TypeOf<typeof bulkEditRulesRequestBodySchemaV1>;

interface BulkEditActionSkippedResult {
id: RuleResponseV1['id'];
name?: RuleResponseV1['name'];
skip_reason: 'RULE_NOT_MODIFIED';
}

interface BulkEditOperationError {
message: string;
status?: number;
rule: {
id: string;
name: string;
};
}

export interface BulkEditRulesResponse<Params extends RuleParamsV1 = never> {
body: {
rules: Array<RuleResponseV1<Params>>;
skipped: BulkEditActionSkippedResult[];
errors: BulkEditOperationError[];
total: number;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* 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.
*/

export { validateSnoozeSchedule } from './validate_snooze_schedule/latest';

export { validateSnoozeSchedule as validateSnoozeScheduleV1 } from './validate_snooze_schedule/v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export * from './v1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* 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 { Frequency } from '@kbn/rrule';
import moment from 'moment';
import { RuleSnoozeScheduleV1 } from '../..';

export const validateSnoozeSchedule = (schedule: RuleSnoozeScheduleV1) => {
const intervalIsDaily = schedule.rRule.freq === Frequency.DAILY;
const durationInDays = moment.duration(schedule.duration, 'milliseconds').asDays();
if (intervalIsDaily && schedule.rRule.interval && durationInDays >= schedule.rRule.interval) {
return 'Recurrence interval must be longer than the snooze duration';
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export * from './v1';
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
*/

import { schema } from '@kbn/config-schema';
import { ruleNotifyWhenV1 } from '../../rule_response';
import { ruleNotifyWhenV1 } from '../../../response';
import {
validateNotifyWhenV1,
validateDurationV1,
validateHoursV1,
validateTimezoneV1,
} from '../../validation';
} from '../../../validation';

export const notifyWhenSchema = schema.oneOf(
[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* 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.
*/

export * from './v1';
Loading

0 comments on commit d4e6a19

Please sign in to comment.