diff --git a/x-pack/plugins/case/server/routes/api/cases/mock.ts b/x-pack/plugins/case/server/client/cases/mock.ts similarity index 98% rename from x-pack/plugins/case/server/routes/api/cases/mock.ts rename to x-pack/plugins/case/server/client/cases/mock.ts index 6d0e4a382fabfec..feb427190b9ca8b 100644 --- a/x-pack/plugins/case/server/routes/api/cases/mock.ts +++ b/x-pack/plugins/case/server/client/cases/mock.ts @@ -8,7 +8,7 @@ import { CommentResponse, CommentType, ConnectorMappingsAttributes, -} from '../../../../common/api'; +} from '../../../common/api'; export const updateUser = { updatedAt: '2020-03-13T08:34:53.450Z', diff --git a/x-pack/plugins/case/server/client/cases/push.ts b/x-pack/plugins/case/server/client/cases/push.ts new file mode 100644 index 000000000000000..5ece8e476dbc78d --- /dev/null +++ b/x-pack/plugins/case/server/client/cases/push.ts @@ -0,0 +1,225 @@ +/* + * 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 { isEmpty } from 'lodash/fp'; +import Boom from '@hapi/boom'; + +import { flattenCaseSavedObject } from '../../routes/api/utils'; + +import { + ActionConnector, + CaseResponseRt, + CaseResponse, + CaseStatuses, + ExternalServiceResponse, +} from '../../../common/api'; +import { buildCaseUserActionItem } from '../../services/user_actions/helpers'; + +import { CaseClientPush, CaseClientFactoryArguments } from '../types'; +import { createIncident, getCommentContextFromAttributes, isCommentAlertType } from './utils'; + +export const push = ({ + savedObjectsClient, + caseService, + caseConfigureService, + userActionService, + request, + response, +}: CaseClientFactoryArguments) => async ({ + actionsClient, + caseClient, + caseId, + connectorId, +}: CaseClientPush): Promise => { + /* Start of push to external service */ + const connector = await actionsClient.get({ id: connectorId }); + const theCase = await caseClient.get({ id: caseId, includeComments: true }); + const userActions = await caseClient.getUserActions({ caseId }); + const alerts = await caseClient.getAlerts({ + ids: theCase.comments?.filter(isCommentAlertType).map((comment) => comment.alertId) ?? [], + }); + + const connectorMappings = await caseClient.getMappings({ + actionsClient, + caseClient, + connectorId: connector.id, + connectorType: connector.actionTypeId, + }); + + const res = await createIncident({ + actionsClient, + theCase, + userActions, + connector: connector as ActionConnector, + mappings: connectorMappings, + alerts, + }); + + const pushRes = await actionsClient.execute({ + actionId: params.connector_id, + params: { + subAction: 'pushToService', + subActionParams: res, + }, + }); + + if (pushRes.status === 'error') { + throw new Error(pushRes.serviceMessage ?? pushRes.message ?? 'Error pushing to service'); + } + + /* End of push to external service */ + + /* Start of update case with push information */ + // eslint-disable-next-line @typescript-eslint/naming-convention + const { username, full_name, email } = await caseService.getUser({ request, response }); + + const pushedDate = new Date().toISOString(); + + const [myCase, myCaseConfigure, totalCommentsFindByCases, connectors] = await Promise.all([ + caseService.getCase({ + client: savedObjectsClient, + caseId, + }), + caseConfigureService.find({ client: savedObjectsClient }), + caseService.getAllCaseComments({ + client: savedObjectsClient, + caseId, + options: { + fields: [], + page: 1, + perPage: 1, + }, + }), + actionsClient.getAll(), + ]); + + if (myCase.attributes.status === CaseStatuses.closed) { + throw Boom.conflict( + `This case ${myCase.attributes.title} is closed. You can not pushed if the case is closed.` + ); + } + + const comments = await caseService.getAllCaseComments({ + client: savedObjectsClient, + caseId, + options: { + fields: [], + page: 1, + perPage: totalCommentsFindByCases.total, + }, + }); + + const externalServiceResponse = pushRes.data as ExternalServiceResponse; + + const externalService = { + pushed_at: pushedDate, + pushed_by: { username, full_name, email }, + connector_id: connector.id, + connector_name: connector.name, + external_id: externalServiceResponse.id, + external_title: externalServiceResponse.title, + external_url: externalServiceResponse.url, + }; + + const updateConnector = myCase.attributes.connector; + + if ( + isEmpty(updateConnector) || + (updateConnector != null && updateConnector.id === 'none') || + !connectors.some((c) => c.id === updateConnector.id) + ) { + throw Boom.notFound('Connector not found or set to none'); + } + + const [updatedCase, updatedComments] = await Promise.all([ + caseService.patchCase({ + client: savedObjectsClient, + caseId, + updatedAttributes: { + ...(myCaseConfigure.total > 0 && + myCaseConfigure.saved_objects[0].attributes.closure_type === 'close-by-pushing' + ? { + status: CaseStatuses.closed, + closed_at: pushedDate, + closed_by: { email, full_name, username }, + } + : {}), + external_service: externalService, + updated_at: pushedDate, + updated_by: { username, full_name, email }, + }, + version: myCase.version, + }), + + caseService.patchComments({ + client: savedObjectsClient, + comments: comments.saved_objects + .filter((comment) => comment.attributes.pushed_at == null) + .map((comment) => ({ + commentId: comment.id, + updatedAttributes: { + pushed_at: pushedDate, + pushed_by: { username, full_name, email }, + }, + version: comment.version, + })), + }), + + userActionService.postUserActions({ + client: savedObjectsClient, + actions: [ + ...(myCaseConfigure.total > 0 && + myCaseConfigure.saved_objects[0].attributes.closure_type === 'close-by-pushing' + ? [ + buildCaseUserActionItem({ + action: 'update', + actionAt: pushedDate, + actionBy: { username, full_name, email }, + caseId, + fields: ['status'], + newValue: CaseStatuses.closed, + oldValue: myCase.attributes.status, + }), + ] + : []), + buildCaseUserActionItem({ + action: 'push-to-service', + actionAt: pushedDate, + actionBy: { username, full_name, email }, + caseId, + fields: ['pushed'], + newValue: JSON.stringify(externalService), + }), + ], + }), + ]); + /* End of update case with push information */ + + return CaseResponseRt.encode( + flattenCaseSavedObject({ + savedObject: { + ...myCase, + ...updatedCase, + attributes: { ...myCase.attributes, ...updatedCase?.attributes }, + references: myCase.references, + }, + comments: comments.saved_objects.map((origComment) => { + const updatedComment = updatedComments.saved_objects.find((c) => c.id === origComment.id); + return { + ...origComment, + ...updatedComment, + attributes: { + ...origComment.attributes, + ...updatedComment?.attributes, + ...getCommentContextFromAttributes(origComment.attributes), + }, + version: updatedComment?.version ?? origComment.version, + references: origComment?.references ?? [], + }; + }), + }) + ); +}; diff --git a/x-pack/plugins/case/server/routes/api/cases/utils.test.ts b/x-pack/plugins/case/server/client/cases/utils.test.ts similarity index 98% rename from x-pack/plugins/case/server/routes/api/cases/utils.test.ts rename to x-pack/plugins/case/server/client/cases/utils.test.ts index 7d1af578802efab..e36006f27cf81ba 100644 --- a/x-pack/plugins/case/server/routes/api/cases/utils.test.ts +++ b/x-pack/plugins/case/server/client/cases/utils.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { BasicParams, ExternalServiceParams, Incident } from '../../../../common/api'; +import { BasicParams, ExternalServiceParams, Incident } from '../../../common/api'; import { createIncident, @@ -15,9 +15,9 @@ import { } from './utils'; import { comment as commentObj, mappings, defaultPipes, basicParams, updateUser } from './mock'; -import { actionsClientMock } from '../../../../../actions/server/actions_client.mock'; -import { flattenCaseSavedObject } from '../utils'; -import { mockCases } from '../__fixtures__'; +import { actionsClientMock } from '../../../../actions/server/actions_client.mock'; +import { flattenCaseSavedObject } from '../../routes/api/utils'; +import { mockCases } from '../../routes/api/__fixtures__'; const formatComment = { commentId: commentObj.id, diff --git a/x-pack/plugins/case/server/routes/api/cases/utils.ts b/x-pack/plugins/case/server/client/cases/utils.ts similarity index 92% rename from x-pack/plugins/case/server/routes/api/cases/utils.ts rename to x-pack/plugins/case/server/client/cases/utils.ts index d5f12932587e17f..754beaea8147a95 100644 --- a/x-pack/plugins/case/server/routes/api/cases/utils.ts +++ b/x-pack/plugins/case/server/client/cases/utils.ts @@ -27,10 +27,14 @@ import { Transformer, TransformerArgs, TransformFieldsArgs, -} from '../../../../common/api'; -import { ActionsClient } from '../../../../../actions/server'; -import { externalServiceFormatters, FormatterConnectorTypes } from '../../../connectors'; -import { CaseClientGetAlertsResponse } from '../../../client/alerts/types'; + CommentAttributes, + CommentRequestUserType, + CommentRequestAlertType, +} from '../../../common/api'; +import { ActionsClient } from '../../../../actions/server'; +import { externalServiceFormatters, FormatterConnectorTypes } from '../../connectors'; +import { CaseClientGetAlertsResponse } from '../../client/alerts/types'; +import { isUserContext } from '../../routes/api/utils'; export const getLatestPushInfo = ( connectorId: string, @@ -289,3 +293,17 @@ export const transformComments = ( export const isCommentAlertType = ( comment: CommentResponse ): comment is CommentResponseAlertsType => comment.type === CommentType.alert; + +export const getCommentContextFromAttributes = ( + attributes: CommentAttributes +): CommentRequestUserType | CommentRequestAlertType => + isUserContext(attributes) + ? { + type: CommentType.user, + comment: attributes.comment, + } + : { + type: CommentType.alert, + alertId: attributes.alertId, + index: attributes.index, + }; diff --git a/x-pack/plugins/case/server/client/index.ts b/x-pack/plugins/case/server/client/index.ts index 62fa899ce59da61..468b795f3937eec 100644 --- a/x-pack/plugins/case/server/client/index.ts +++ b/x-pack/plugins/case/server/client/index.ts @@ -8,6 +8,7 @@ import { CaseClientFactoryArguments, CaseClient } from './types'; import { create } from './cases/create'; import { get } from './cases/get'; import { update } from './cases/update'; +import { push } from './cases/push'; import { addComment } from './comments/add'; import { getFields } from './configure/get_fields'; import { getMappings } from './configure/get_mappings'; @@ -23,6 +24,7 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, alertsService, @@ -35,6 +37,7 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), @@ -44,6 +47,7 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), @@ -53,15 +57,28 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), + push: push({ + alertsService, + caseConfigureService, + caseService, + connectorMappingsService, + request, + response, + savedObjectsClient, + userActionService, + context, + }), addComment: addComment({ alertsService, caseConfigureService, caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), @@ -72,6 +89,7 @@ export const createCaseClient = ({ connectorMappingsService, context, request, + response, savedObjectsClient, userActionService, }), @@ -82,6 +100,7 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), @@ -91,6 +110,7 @@ export const createCaseClient = ({ caseService, connectorMappingsService, request, + response, savedObjectsClient, userActionService, }), @@ -101,6 +121,7 @@ export const createCaseClient = ({ connectorMappingsService, context, request, + response, savedObjectsClient, userActionService, }), diff --git a/x-pack/plugins/case/server/client/types.ts b/x-pack/plugins/case/server/client/types.ts index 076c319eae754aa..26320b2b7b25778 100644 --- a/x-pack/plugins/case/server/client/types.ts +++ b/x-pack/plugins/case/server/client/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { KibanaRequest, SavedObjectsClientContract } from 'kibana/server'; +import { KibanaRequest, KibanaResponseFactory, SavedObjectsClientContract } from 'kibana/server'; import { ActionsClient } from '../../../actions/server'; import { CasePostRequest, @@ -41,6 +41,13 @@ export interface CaseClientGet { includeComments?: boolean; } +export interface CaseClientPush { + actionsClient: ActionsClient; + caseClient: CaseClient; + caseId: string; + connectorId: string; +} + export interface CaseClientAddComment { caseClient: CaseClient; caseId: string; @@ -65,6 +72,7 @@ export interface CaseClientFactoryArguments { caseService: CaseServiceSetup; connectorMappingsService: ConnectorMappingsServiceSetup; request: KibanaRequest; + response: KibanaResponseFactory; savedObjectsClient: SavedObjectsClientContract; userActionService: CaseUserActionServiceSetup; alertsService: AlertServiceContract; @@ -84,6 +92,7 @@ export interface CaseClient { getFields: (args: ConfigureFields) => Promise; getMappings: (args: MappingsClient) => Promise; getUserActions: (args: CaseClientGetUserActions) => Promise; + push: (args: CaseClientPush) => Promise; update: (args: CaseClientUpdate) => Promise; updateAlertsStatus: (args: CaseClientUpdateAlertsStatus) => Promise; } diff --git a/x-pack/plugins/case/server/plugin.ts b/x-pack/plugins/case/server/plugin.ts index 0b9712e78c2bc9f..914b269c416d2c9 100644 --- a/x-pack/plugins/case/server/plugin.ts +++ b/x-pack/plugins/case/server/plugin.ts @@ -5,7 +5,13 @@ */ import { first, map } from 'rxjs/operators'; -import { IContextProvider, KibanaRequest, Logger, PluginInitializerContext } from 'kibana/server'; +import { + IContextProvider, + KibanaRequest, + KibanaResponseFactory, + Logger, + PluginInitializerContext, +} from 'kibana/server'; import { CoreSetup, CoreStart } from 'src/core/server'; import { SecurityPluginSetup } from '../../security/server'; @@ -123,11 +129,13 @@ export class CasePlugin { const getCaseClientWithRequestAndContext = async ( context: CasesRequestHandlerContext, - request: KibanaRequest + request: KibanaRequest, + response: KibanaResponseFactory ) => { return createCaseClient({ savedObjectsClient: core.savedObjects.getScopedClient(request), request, + response, caseService: this.caseService!, caseConfigureService: this.caseConfigureService!, connectorMappingsService: this.connectorMappingsService!, @@ -161,7 +169,7 @@ export class CasePlugin { userActionService: CaseUserActionServiceSetup; alertsService: AlertServiceContract; }): IContextProvider => { - return async (context, request) => { + return async (context, request, response) => { const [{ savedObjects }] = await core.getStartServices(); return { getCaseClient: () => { @@ -172,8 +180,9 @@ export class CasePlugin { connectorMappingsService, userActionService, alertsService, - request, context, + request, + response, }); }, }; diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts index 6ee8b5d7e4fc2f7..3616964fb7592ac 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_configure.ts @@ -32,7 +32,7 @@ export function initGetCaseConfigure({ caseConfigureService, router }: RouteDeps throw Boom.badRequest('RouteHandlerContext is not registered for cases'); } const caseClient = context.case.getCaseClient(); - const actionsClient = await context.actions?.getActionsClient(); + const actionsClient = context.actions?.getActionsClient(); if (actionsClient == null) { throw Boom.notFound('Action client have not been found'); } diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts index ab9a737fb5454e9..69184649971375c 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts @@ -35,7 +35,7 @@ export function initCaseConfigureGetActionConnector({ router }: RouteDeps) { }, async (context, request, response) => { try { - const actionsClient = await context.actions?.getActionsClient(); + const actionsClient = context.actions?.getActionsClient(); if (actionsClient == null) { throw Boom.notFound('Action client have not been found'); diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts index d2f3ea2bec5b98f..26ab8cc162c4a34 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/patch_configure.ts @@ -65,7 +65,7 @@ export function initPatchCaseConfigure({ caseConfigureService, caseService, rout throw Boom.badRequest('RouteHandlerContext is not registered for cases'); } const caseClient = context.case.getCaseClient(); - const actionsClient = await context.actions?.getActionsClient(); + const actionsClient = context.actions?.getActionsClient(); if (actionsClient == null) { throw Boom.notFound('Action client have not been found'); } diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts index b90bdd448d4da68..a0a040abdbd6f46 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/post_configure.ts @@ -38,7 +38,7 @@ export function initPostCaseConfigure({ caseConfigureService, caseService, route throw Boom.badRequest('RouteHandlerContext is not registered for cases'); } const caseClient = context.case.getCaseClient(); - const actionsClient = await context.actions?.getActionsClient(); + const actionsClient = context.actions?.getActionsClient(); if (actionsClient == null) { throw Boom.notFound('Action client have not been found'); } diff --git a/x-pack/plugins/case/server/routes/api/cases/push_case.ts b/x-pack/plugins/case/server/routes/api/cases/push_case.ts index c812ae86d48d4cd..8cdc15b8014185d 100644 --- a/x-pack/plugins/case/server/routes/api/cases/push_case.ts +++ b/x-pack/plugins/case/server/routes/api/cases/push_case.ts @@ -5,37 +5,17 @@ */ import Boom from '@hapi/boom'; -import isEmpty from 'lodash/isEmpty'; import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; -import { - flattenCaseSavedObject, - wrapError, - escapeHatch, - getCommentContextFromAttributes, -} from '../utils'; +import { wrapError, escapeHatch } from '../utils'; -import { - ActionConnector, - CaseResponseRt, - ExternalServiceResponse, - throwErrors, - CaseStatuses, - CasePushRequestParamsRt, -} from '../../../../common/api'; -import { buildCaseUserActionItem } from '../../../services/user_actions/helpers'; +import { throwErrors, CasePushRequestParamsRt } from '../../../../common/api'; import { RouteDeps } from '../types'; import { CASE_PUSH_URL } from '../../../../common/constants'; -import { createIncident, isCommentAlertType } from './utils'; -export function initPushCaseApi({ - caseConfigureService, - caseService, - router, - userActionService, -}: RouteDeps) { +export function initPushCaseApi({ router }: RouteDeps) { router.post( { path: CASE_PUSH_URL, @@ -45,222 +25,30 @@ export function initPushCaseApi({ }, }, async (context, request, response) => { - try { - if (!context.case) { - throw Boom.badRequest('RouteHandlerContext is not registered for cases'); - } - - const savedObjectsClient = context.core.savedObjects.client; - const caseClient = context.case.getCaseClient(); - const actionsClient = await context.actions?.getActionsClient(); - - if (actionsClient == null) { - throw Boom.notFound('Action client have not been found'); - } - - const params = pipe( - CasePushRequestParamsRt.decode(request.params), - fold(throwErrors(Boom.badRequest), identity) - ); - - if (actionsClient == null) { - throw Boom.notFound('Action client have not been found'); - } - - const caseId = params.case_id; - const connectorId = params.connector_id; - - /* Start of push to external service */ - const connector = await actionsClient.get({ id: connectorId }); - const theCase = await caseClient.get({ id: caseId, includeComments: true }); - const userActions = await caseClient.getUserActions({ caseId }); - const alerts = await caseClient.getAlerts({ - ids: theCase.comments?.filter(isCommentAlertType).map((comment) => comment.alertId) ?? [], - }); - - const connectorMappings = await caseClient.getMappings({ - actionsClient, - caseClient, - connectorId: connector.id, - connectorType: connector.actionTypeId, - }); - - const res = await createIncident({ - actionsClient, - theCase, - userActions, - connector: connector as ActionConnector, - mappings: connectorMappings, - alerts, - }); - - const pushRes = await actionsClient.execute({ - actionId: params.connector_id, - params: { - subAction: 'pushToService', - subActionParams: res, - }, - }); - - if (pushRes.status === 'error') { - throw new Error(pushRes.serviceMessage ?? pushRes.message ?? 'Error pushing to service'); - } - - /* End of push to external service */ - - /* Start of update case with push information */ - // eslint-disable-next-line @typescript-eslint/naming-convention - const { username, full_name, email } = await caseService.getUser({ request, response }); - - const pushedDate = new Date().toISOString(); - - const [myCase, myCaseConfigure, totalCommentsFindByCases, connectors] = await Promise.all([ - caseService.getCase({ - client: savedObjectsClient, - caseId, - }), - caseConfigureService.find({ client: savedObjectsClient }), - caseService.getAllCaseComments({ - client: savedObjectsClient, - caseId, - options: { - fields: [], - page: 1, - perPage: 1, - }, - }), - actionsClient.getAll(), - ]); - - if (myCase.attributes.status === CaseStatuses.closed) { - throw Boom.conflict( - `This case ${myCase.attributes.title} is closed. You can not pushed if the case is closed.` - ); - } - - const comments = await caseService.getAllCaseComments({ - client: savedObjectsClient, - caseId, - options: { - fields: [], - page: 1, - perPage: totalCommentsFindByCases.total, - }, - }); - - const externalServiceResponse = pushRes.data as ExternalServiceResponse; - - const externalService = { - pushed_at: pushedDate, - pushed_by: { username, full_name, email }, - connector_id: connector.id, - connector_name: connector.name, - external_id: externalServiceResponse.id, - external_title: externalServiceResponse.title, - external_url: externalServiceResponse.url, - }; - - const updateConnector = myCase.attributes.connector; - - if ( - isEmpty(updateConnector) || - (updateConnector != null && updateConnector.id === 'none') || - !connectors.some((c) => c.id === updateConnector.id) - ) { - throw Boom.notFound('Connector not found or set to none'); - } + if (!context.case) { + throw Boom.badRequest('RouteHandlerContext is not registered for cases'); + } - const [updatedCase, updatedComments] = await Promise.all([ - caseService.patchCase({ - client: savedObjectsClient, - caseId, - updatedAttributes: { - ...(myCaseConfigure.total > 0 && - myCaseConfigure.saved_objects[0].attributes.closure_type === 'close-by-pushing' - ? { - status: CaseStatuses.closed, - closed_at: pushedDate, - closed_by: { email, full_name, username }, - } - : {}), - external_service: externalService, - updated_at: pushedDate, - updated_by: { username, full_name, email }, - }, - version: myCase.version, - }), + const caseClient = context.case.getCaseClient(); + const actionsClient = context.actions?.getActionsClient(); - caseService.patchComments({ - client: savedObjectsClient, - comments: comments.saved_objects - .filter((comment) => comment.attributes.pushed_at == null) - .map((comment) => ({ - commentId: comment.id, - updatedAttributes: { - pushed_at: pushedDate, - pushed_by: { username, full_name, email }, - }, - version: comment.version, - })), - }), + if (actionsClient == null) { + throw Boom.notFound('Action client have not been found'); + } - userActionService.postUserActions({ - client: savedObjectsClient, - actions: [ - ...(myCaseConfigure.total > 0 && - myCaseConfigure.saved_objects[0].attributes.closure_type === 'close-by-pushing' - ? [ - buildCaseUserActionItem({ - action: 'update', - actionAt: pushedDate, - actionBy: { username, full_name, email }, - caseId, - fields: ['status'], - newValue: CaseStatuses.closed, - oldValue: myCase.attributes.status, - }), - ] - : []), - buildCaseUserActionItem({ - action: 'push-to-service', - actionAt: pushedDate, - actionBy: { username, full_name, email }, - caseId, - fields: ['pushed'], - newValue: JSON.stringify(externalService), - }), - ], - }), - ]); - /* End of update case with push information */ + const params = pipe( + CasePushRequestParamsRt.decode(request.params), + fold(throwErrors(Boom.badRequest), identity) + ); + try { return response.ok({ - body: CaseResponseRt.encode( - flattenCaseSavedObject({ - savedObject: { - ...myCase, - ...updatedCase, - attributes: { ...myCase.attributes, ...updatedCase?.attributes }, - references: myCase.references, - }, - comments: comments.saved_objects.map((origComment) => { - const updatedComment = updatedComments.saved_objects.find( - (c) => c.id === origComment.id - ); - return { - ...origComment, - ...updatedComment, - attributes: { - ...origComment.attributes, - ...updatedComment?.attributes, - ...getCommentContextFromAttributes(origComment.attributes), - }, - version: updatedComment?.version ?? origComment.version, - references: origComment?.references ?? [], - }; - }), - }) - ), + body: await caseClient.push({ + caseClient, + actionsClient, + caseId: params.case_id, + connectorId: params.connector_id, + }), }); } catch (error) { return response.customError(wrapError(error)); diff --git a/x-pack/plugins/case/server/routes/api/utils.ts b/x-pack/plugins/case/server/routes/api/utils.ts index 917afb487b1f44b..bd8d3d63c3a558f 100644 --- a/x-pack/plugins/case/server/routes/api/utils.ts +++ b/x-pack/plugins/case/server/routes/api/utils.ts @@ -190,11 +190,11 @@ export const sortToSnake = (sortField: string): SortFieldCase => { export const escapeHatch = schema.object({}, { unknowns: 'allow' }); -const isUserContext = (context: CommentRequest): context is CommentRequestUserType => { +export const isUserContext = (context: CommentRequest): context is CommentRequestUserType => { return context.type === CommentType.user; }; -const isAlertContext = (context: CommentRequest): context is CommentRequestAlertType => { +export const isAlertContext = (context: CommentRequest): context is CommentRequestAlertType => { return context.type === CommentType.alert; }; @@ -205,17 +205,3 @@ export const decodeComment = (comment: CommentRequest) => { pipe(excess(ContextTypeAlertRt).decode(comment), fold(throwErrors(badRequest), identity)); } }; - -export const getCommentContextFromAttributes = ( - attributes: CommentAttributes -): CommentRequestUserType | CommentRequestAlertType => - isUserContext(attributes) - ? { - type: CommentType.user, - comment: attributes.comment, - } - : { - type: CommentType.alert, - alertId: attributes.alertId, - index: attributes.index, - };