[RAM] Fix case conversion of frequency.notify_when in API (#148838)

## Summary

Closes #148572

Fixes an issue where rules APIs required `frequency.notifyWhen` to be
sent/received instead of `frequency.notify_when`


### 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: Julia <iuliia.guskova@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Zacqary Adam Xeper 2023-01-24 16:53:59 -06:00 committed by GitHub
parent 2228086ae6
commit cb2f07b570
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 84 additions and 45 deletions

View file

@ -12,7 +12,9 @@ type RenameActionToConnector<K extends string> = K extends `actionTypeId`
: K;
export type AsApiContract<T> = {
[K in keyof T as CamelToSnake<RenameActionToConnector<Extract<K, string>>>]: T[K];
[K in keyof T as CamelToSnake<RenameActionToConnector<Extract<K, string>>>]: K extends 'frequency'
? AsApiContract<T[K]>
: T[K];
};
export type RewriteRequestCase<T> = (requested: AsApiContract<T>) => T;

View file

@ -15,8 +15,20 @@ import {
} from '../../common';
function transformAction(input: AsApiContract<RuleAction>): RuleAction {
const { connector_type_id: actionTypeId, ...rest } = input;
return { actionTypeId, ...rest };
const { connector_type_id: actionTypeId, frequency, ...rest } = input;
return {
actionTypeId,
...(frequency
? {
frequency: {
summary: frequency.summary,
throttle: frequency.throttle,
notifyWhen: frequency.notify_when,
},
}
: {}),
...rest,
};
}
// AsApiContract does not deal with object properties that are dates - the

View file

@ -13,6 +13,7 @@ import {
RewriteResponseCase,
handleDisabledApiKeysError,
rewriteRuleLastRun,
rewriteActionsRes,
} from './lib';
import {
RuleTypeParams,
@ -69,13 +70,7 @@ const rewriteBodyRes: RewriteResponseCase<PartialRule<RuleTypeParams>> = ({
: {}),
...(actions
? {
actions: actions.map(({ group, id, actionTypeId, params, frequency }) => ({
group,
id,
params,
connector_type_id: actionTypeId,
frequency,
})),
actions: rewriteActionsRes(actions),
}
: {}),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),

View file

@ -11,7 +11,8 @@ import { CreateOptions } from '../rules_client';
import {
RewriteRequestCase,
RewriteResponseCase,
rewriteActions,
rewriteActionsReq,
rewriteActionsRes,
handleDisabledApiKeysError,
verifyAccessAndContext,
countUsageOfPredefinedIds,
@ -45,11 +46,13 @@ export const bodySchema = schema.object({
const rewriteBodyReq: RewriteRequestCase<CreateOptions<RuleTypeParams>['data']> = ({
rule_type_id: alertTypeId,
notify_when: notifyWhen,
actions,
...rest
}) => ({
...rest,
alertTypeId,
notifyWhen,
actions: rewriteActionsReq(actions),
});
const rewriteBodyRes: RewriteResponseCase<SanitizedRule<RuleTypeParams>> = ({
@ -87,12 +90,7 @@ const rewriteBodyRes: RewriteResponseCase<SanitizedRule<RuleTypeParams>> = ({
last_execution_date: lastExecutionDate,
last_duration: lastDuration,
},
actions: actions.map(({ group, id, actionTypeId, params }) => ({
group,
id,
params,
connector_type_id: actionTypeId,
})),
actions: rewriteActionsRes(actions),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
...(nextRun ? { next_run: nextRun } : {}),
});
@ -128,7 +126,6 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt
await rulesClient.create<RuleTypeParams>({
data: rewriteBodyReq({
...rule,
actions: rewriteActions(rule.actions),
notify_when: rule.notify_when as RuleNotifyWhenType,
}),
options: { id: params?.id },

View file

@ -64,7 +64,13 @@ const rewriteBodyRes: RewriteResponseCase<SanitizedRule<RuleTypeParams>> = ({
id,
params,
connector_type_id: actionTypeId,
frequency,
frequency: frequency
? {
summary: frequency.summary,
notify_when: frequency.notifyWhen,
throttle: frequency.throttle,
}
: undefined,
})),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
...(nextRun ? { next_run: nextRun } : {}),

View file

@ -18,7 +18,7 @@ export type {
} from './rewrite_request_case';
export { verifyAccessAndContext } from './verify_access_and_context';
export { countUsageOfPredefinedIds } from './count_usage_of_predefined_ids';
export { rewriteActions } from './rewrite_actions';
export { rewriteActionsReq, rewriteActionsRes } from './rewrite_actions';
export { actionsSchema } from './actions_schema';
export { rewriteRule, rewriteRuleLastRun } from './rewrite_rule';
export { rewriteNamespaces } from './rewrite_namespaces';

View file

@ -14,7 +14,7 @@ type ReqRuleAction = Omit<RuleAction, 'actionTypeId' | 'frequency'> & {
>[K];
};
};
export const rewriteActions: (
export const rewriteActionsReq: (
actions?: ReqRuleAction[]
) => Array<Omit<RuleAction, 'actionTypeId'>> = (actions) => {
const rewriteFrequency: RewriteRequestCase<NonNullable<RuleAction['frequency']>> = ({
@ -30,3 +30,16 @@ export const rewriteActions: (
} as RuleAction)
);
};
export const rewriteActionsRes = (actions?: RuleAction[]) => {
const rewriteFrequency = ({ notifyWhen, ...rest }: NonNullable<RuleAction['frequency']>) => ({
...rest,
notify_when: notifyWhen,
});
if (!actions) return [];
return actions.map(({ actionTypeId, frequency, ...action }) => ({
...action,
connector_type_id: actionTypeId,
...(frequency ? { frequency: rewriteFrequency(frequency) } : {}),
}));
};

View file

@ -24,7 +24,7 @@ type RenameAlertToRule<K extends string> = K extends `alertTypeId`
export type AsApiContract<
T,
ComplexPropertyKeys = `actions` | `executionStatus` | 'lastRun',
ComplexPropertyKeys = 'actions' | 'executionStatus' | 'lastRun' | 'frequency',
OpaquePropertyKeys = `params`
> = T extends Array<infer I>
? Array<AsApiContract<I>>
@ -32,7 +32,7 @@ export type AsApiContract<
[K in keyof T as CamelToSnake<
RenameAlertToRule<Extract<K, string>>
>]: K extends OpaquePropertyKeys
? // don't convert explciitly opaque types which we treat as a black box
? // don't convert explcitly opaque types which we treat as a black box
T[K]
: T[K] extends undefined
? AsApiContract<Exclude<T[K], undefined>> | undefined

View file

@ -63,7 +63,9 @@ export const rewriteRule = ({
connector_type_id: actionTypeId,
...(frequency
? {
frequency,
summary: frequency.summary,
notify_when: frequency.notifyWhen,
throttle: frequency.throttle,
}
: {}),
})),

View file

@ -9,7 +9,12 @@ import { omit } from 'lodash';
import { schema } from '@kbn/config-schema';
import { IRouter } from '@kbn/core/server';
import { ILicenseState } from '../lib';
import { verifyAccessAndContext, RewriteResponseCase, rewriteRuleLastRun } from './lib';
import {
verifyAccessAndContext,
RewriteResponseCase,
rewriteRuleLastRun,
rewriteActionsRes,
} from './lib';
import {
RuleTypeParams,
AlertingRequestHandlerContext,
@ -54,13 +59,7 @@ const rewriteBodyRes: RewriteResponseCase<ResolvedSanitizedRule<RuleTypeParams>>
last_execution_date: executionStatus.lastExecutionDate,
last_duration: executionStatus.lastDuration,
},
actions: actions.map(({ group, id, actionTypeId, params, frequency }) => ({
group,
id,
params,
connector_type_id: actionTypeId,
frequency,
})),
actions: rewriteActionsRes(actions),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
...(nextRun ? { next_run: nextRun } : {}),
});

View file

@ -15,7 +15,8 @@ import {
RewriteResponseCase,
RewriteRequestCase,
handleDisabledApiKeysError,
rewriteActions,
rewriteActionsReq,
rewriteActionsRes,
actionsSchema,
rewriteRuleLastRun,
} from './lib';
@ -44,12 +45,13 @@ const bodySchema = schema.object({
});
const rewriteBodyReq: RewriteRequestCase<UpdateOptions<RuleTypeParams>> = (result) => {
const { notify_when: notifyWhen, ...rest } = result.data;
const { notify_when: notifyWhen, actions, ...rest } = result.data;
return {
...result,
data: {
...rest,
notifyWhen,
actions: rewriteActionsReq(actions),
},
};
};
@ -96,13 +98,7 @@ const rewriteBodyRes: RewriteResponseCase<PartialRule<RuleTypeParams>> = ({
: {}),
...(actions
? {
actions: actions.map(({ group, id, actionTypeId, params, frequency }) => ({
group,
id,
params,
connector_type_id: actionTypeId,
frequency,
})),
actions: rewriteActionsRes(actions),
}
: {}),
...(lastRun ? { last_run: rewriteRuleLastRun(lastRun) } : {}),
@ -133,7 +129,6 @@ export const updateRuleRoute = (
id,
data: {
...rule,
actions: rewriteActions(rule.actions),
notify_when: rule.notify_when as RuleNotifyWhenType,
},
})

View file

@ -38,7 +38,7 @@ describe('cloneRule', () => {
message: 'alert ',
},
frequency: {
notifyWhen: 'onActionGroupChange',
notify_when: 'onActionGroupChange',
throttle: null,
summary: false,
},

View file

@ -19,7 +19,15 @@ const transformAction: RewriteRequestCase<RuleAction> = ({
id,
params,
actionTypeId,
frequency,
...(frequency
? {
frequency: {
summary: frequency.summary,
notifyWhen: frequency.notify_when,
throttle: frequency.throttle,
},
}
: {}),
});
const transformExecutionStatus: RewriteRequestCase<RuleExecutionStatus> = ({

View file

@ -42,7 +42,7 @@ describe('createRule', () => {
},
connector_type_id: '.server-log',
frequency: {
notifyWhen: 'onActionGroupChange',
notify_when: 'onActionGroupChange',
throttle: null,
summary: false,
},

View file

@ -51,6 +51,11 @@ describe('resolveRule', () => {
id: '1',
params: { documents: [{ dsfsdf: 1212 }] },
connector_type_id: '.index',
frequency: {
summary: null,
notify_when: 'onActiveAlert',
throttle: null,
},
},
],
outcome: 'aliasMatch',
@ -95,6 +100,11 @@ describe('resolveRule', () => {
id: '1',
params: { documents: [{ dsfsdf: 1212 }] },
actionTypeId: '.index',
frequency: {
summary: null,
notifyWhen: 'onActiveAlert',
throttle: null,
},
},
],
outcome: 'aliasMatch',