diff --git a/x-pack/legacy/plugins/siem/server/lib/case/saved_object_mappings_temp.ts b/x-pack/legacy/plugins/siem/server/lib/case/saved_object_mappings_temp.ts index f9b3bb253a98e4..17fc8bbd390802 100644 --- a/x-pack/legacy/plugins/siem/server/lib/case/saved_object_mappings_temp.ts +++ b/x-pack/legacy/plugins/siem/server/lib/case/saved_object_mappings_temp.ts @@ -33,9 +33,6 @@ export const caseSavedObjectMappings: { }, }, }, - comments: { - type: 'keyword', - }, creation_date: { type: 'date', }, @@ -45,7 +42,7 @@ export const caseSavedObjectMappings: { last_edit_date: { type: 'date', }, - name: { + title: { type: 'keyword', }, reporter: { diff --git a/x-pack/plugins/case/README.md b/x-pack/plugins/case/README.md new file mode 100644 index 00000000000000..c0acb878352079 --- /dev/null +++ b/x-pack/plugins/case/README.md @@ -0,0 +1,9 @@ +# Case Workflow + +*Experimental Feature* + +Elastic is developing a Case Management Workflow. Follow our progress: + +- [Case API Documentation](https://documenter.getpostman.com/view/172706/SW7c2SuF?version=latest) +- [Github Meta](https://github.com/elastic/kibana/issues/50103) + diff --git a/x-pack/plugins/case/server/routes/api/delete_case.ts b/x-pack/plugins/case/server/routes/api/delete_case.ts index c59fb48f141ac6..a5ae72b8b46ff0 100644 --- a/x-pack/plugins/case/server/routes/api/delete_case.ts +++ b/x-pack/plugins/case/server/routes/api/delete_case.ts @@ -19,9 +19,9 @@ export function initDeleteCaseApi({ caseService, router }: RouteDeps) { }, }, async (context, request, response) => { - let theCase; + let allCaseComments; try { - theCase = await caseService.getCase({ + await caseService.deleteCase({ client: context.core.savedObjects.client, caseId: request.params.id, }); @@ -29,24 +29,25 @@ export function initDeleteCaseApi({ caseService, router }: RouteDeps) { return response.customError(wrapError(error)); } try { - const comments = theCase.attributes.comments; - await Promise.all( - comments.map((commentId: string) => - caseService.deleteComment({ - client: context.core.savedObjects.client, - commentId, - }) - ) - ); + allCaseComments = await caseService.getAllCaseComments({ + client: context.core.savedObjects.client, + caseId: request.params.id, + }); } catch (error) { return response.customError(wrapError(error)); } try { - await caseService.deleteCase({ - client: context.core.savedObjects.client, - caseId: request.params.id, - }); - return response.ok({ body: { deletedCase: true } }); + if (allCaseComments.saved_objects.length > 0) { + await Promise.all( + allCaseComments.saved_objects.map(({ id }) => + caseService.deleteComment({ + client: context.core.savedObjects.client, + commentId: id, + }) + ) + ); + } + return response.noContent(); } catch (error) { return response.customError(wrapError(error)); } diff --git a/x-pack/plugins/case/server/routes/api/delete_comment.ts b/x-pack/plugins/case/server/routes/api/delete_comment.ts index 4251776cc6db0f..8d70d6cebf6cf0 100644 --- a/x-pack/plugins/case/server/routes/api/delete_comment.ts +++ b/x-pack/plugins/case/server/routes/api/delete_comment.ts @@ -6,7 +6,7 @@ import { schema } from '@kbn/config-schema'; import { RouteDeps } from '.'; -import { formatUpdatedCase, wrapError } from './utils'; +import { wrapError } from './utils'; export function initDeleteCommentApi({ caseService, router }: RouteDeps) { router.delete( @@ -21,33 +21,12 @@ export function initDeleteCommentApi({ caseService, router }: RouteDeps) { }, async (context, request, response) => { const client = context.core.savedObjects.client; - let theCase; try { await caseService.deleteComment({ client, commentId: request.params.comment_id, }); - } catch (error) { - return response.customError(wrapError(error)); - } - try { - theCase = await caseService.getCase({ - client, - caseId: request.params.case_id, - }); - } catch (error) { - return response.customError(wrapError(error)); - } - try { - const comments = theCase.attributes!.comments.filter( - (comment: string) => comment !== request.params.comment_id - ); - const updatedCase = await caseService.updateCase({ - client: context.core.savedObjects.client, - caseId: request.params.case_id, - updatedAttributes: formatUpdatedCase({ comments }), - }); - return response.ok({ body: { deleted: true, updatedCase } }); + return response.noContent(); } catch (error) { return response.customError(wrapError(error)); } diff --git a/x-pack/plugins/case/server/routes/api/get_case.ts b/x-pack/plugins/case/server/routes/api/get_case.ts index 10cee6b7f81cce..a442b73878a3e7 100644 --- a/x-pack/plugins/case/server/routes/api/get_case.ts +++ b/x-pack/plugins/case/server/routes/api/get_case.ts @@ -19,12 +19,21 @@ export function initGetCaseApi({ caseService, router }: RouteDeps) { }, }, async (context, request, response) => { + let theCase; try { - const theCase = await caseService.getCase({ + theCase = await caseService.getCase({ client: context.core.savedObjects.client, caseId: request.params.id, }); - return response.ok({ body: theCase }); + } catch (error) { + return response.customError(wrapError(error)); + } + try { + const theComments = await caseService.getAllCaseComments({ + client: context.core.savedObjects.client, + caseId: request.params.id, + }); + return response.ok({ body: { case: theCase, comments: theComments } }); } catch (error) { return response.customError(wrapError(error)); } diff --git a/x-pack/plugins/case/server/routes/api/post_comment.ts b/x-pack/plugins/case/server/routes/api/post_comment.ts index 35e108d68474b4..f850ba8e6ca738 100644 --- a/x-pack/plugins/case/server/routes/api/post_comment.ts +++ b/x-pack/plugins/case/server/routes/api/post_comment.ts @@ -5,7 +5,7 @@ */ import { schema } from '@kbn/config-schema'; -import { formatUpdatedCase, formatNewComment, wrapError } from './utils'; +import { formatNewComment, wrapError } from './utils'; import { NewCommentSchema } from './schema'; import { RouteDeps } from '.'; @@ -23,11 +23,10 @@ export function initPostCommentApi({ caseService, router }: RouteDeps) { async (context, request, response) => { let user; let newComment; - let theCase; try { user = await caseService.getUser({ request, response }); - } catch (error) { - return response.customError(wrapError(error)); + } catch (e) { + return e; } try { newComment = await caseService.postNewComment({ @@ -39,28 +38,8 @@ export function initPostCommentApi({ caseService, router }: RouteDeps) { case_workflow_id: request.params.id, }), }); - } catch (error) { - return response.customError(wrapError(error)); - } - try { - theCase = await caseService.getCase({ - client: context.core.savedObjects.client, - caseId: request.params.id, - }); - } catch (error) { - return response.customError(wrapError(error)); - } - try { - const updatedCase = await caseService.updateCase({ - client: context.core.savedObjects.client, - caseId: request.params.id, - updatedAttributes: formatUpdatedCase({ - comments: theCase.attributes!.comments.length - ? [...theCase.attributes!.comments, newComment.id] - : [newComment.id], - }), - }); - return response.ok({ body: { newComment, updatedCase } }); + + return response.ok({ body: { newComment } }); } catch (error) { return response.customError(wrapError(error)); } diff --git a/x-pack/plugins/case/server/routes/api/schema.ts b/x-pack/plugins/case/server/routes/api/schema.ts index 20ef1b24455b9e..c4a3e621d95846 100644 --- a/x-pack/plugins/case/server/routes/api/schema.ts +++ b/x-pack/plugins/case/server/routes/api/schema.ts @@ -23,11 +23,15 @@ export const CommentSchema = schema.object({ case_workflow_id: schema.string(), }); +export const UpdatedCommentSchema = schema.object({ + comment: schema.string(), + last_edit_date: schema.number(), +}); + export const NewCaseSchema = schema.object({ assignees: schema.arrayOf(UserSchema, { defaultValue: [] }), - comments: schema.arrayOf(schema.string(), { defaultValue: [] }), description: schema.string(), - name: schema.string(), + title: schema.string(), state: schema.oneOf([schema.literal('open'), schema.literal('closed')], { defaultValue: 'open' }), tags: schema.arrayOf(schema.string(), { defaultValue: [] }), case_type: schema.string(), @@ -35,15 +39,9 @@ export const NewCaseSchema = schema.object({ export const UpdatedCaseSchema = schema.object({ assignees: schema.maybe(schema.arrayOf(UserSchema)), - comments: schema.maybe(schema.arrayOf(schema.string())), description: schema.maybe(schema.string()), - name: schema.maybe(schema.string()), + title: schema.maybe(schema.string()), state: schema.maybe(schema.oneOf([schema.literal('open'), schema.literal('closed')])), tags: schema.maybe(schema.arrayOf(schema.string())), case_type: schema.maybe(schema.string()), }); - -export const UpdatedCommentSchema = schema.object({ - comment: schema.string(), - last_edit_date: schema.number(), -}); diff --git a/x-pack/plugins/case/server/routes/api/types.ts b/x-pack/plugins/case/server/routes/api/types.ts index 9fa1608ae8615e..122ff500b9f80d 100644 --- a/x-pack/plugins/case/server/routes/api/types.ts +++ b/x-pack/plugins/case/server/routes/api/types.ts @@ -14,26 +14,11 @@ import { UserSchema, } from './schema'; +export type NewCaseType = TypeOf; +export type NewCommentFormatted = TypeOf; +export type NewCommentType = TypeOf; export type UpdatedCaseTyped = TypeOf; - -export interface UpdatedCaseType { - assignees?: UpdatedCaseTyped['assignees']; - comments?: UpdatedCaseTyped['comments']; - description?: UpdatedCaseTyped['description']; - name?: UpdatedCaseTyped['name']; - state?: UpdatedCaseTyped['state']; - tags?: UpdatedCaseTyped['tags']; - case_type?: UpdatedCaseTyped['case_type']; -} - export type UpdatedCommentType = TypeOf; - -export interface UpdatedCaseFormatted extends UpdatedCaseType { - last_edit_date: number; -} - -export type NewCaseType = TypeOf; - export type UserType = TypeOf; export interface NewCaseFormatted extends NewCaseType { @@ -42,6 +27,15 @@ export interface NewCaseFormatted extends NewCaseType { reporter: UserType; } -export type NewCommentType = TypeOf; +export interface UpdatedCaseFormatted extends UpdatedCaseType { + last_edit_date: number; +} -export type NewCommentFormatted = TypeOf; +export interface UpdatedCaseType { + assignees?: UpdatedCaseTyped['assignees']; + description?: UpdatedCaseTyped['description']; + title?: UpdatedCaseTyped['title']; + state?: UpdatedCaseTyped['state']; + tags?: UpdatedCaseTyped['tags']; + case_type?: UpdatedCaseTyped['case_type']; +} diff --git a/x-pack/plugins/case/server/routes/api/utils.ts b/x-pack/plugins/case/server/routes/api/utils.ts index 298dcebb85f2b7..d223cb03e8ea99 100644 --- a/x-pack/plugins/case/server/routes/api/utils.ts +++ b/x-pack/plugins/case/server/routes/api/utils.ts @@ -39,11 +39,11 @@ export const formatNewComment = ({ username, case_workflow_id, }: NewCommentArgs): NewCommentFormatted => ({ + ...newComment, creation_date: new Date().valueOf(), last_edit_date: new Date().valueOf(), user: { full_name, username }, case_workflow_id, - ...newComment, }); export const formatUpdatedCase = (updateCase: UpdatedCaseType): UpdatedCaseFormatted => ({ diff --git a/x-pack/plugins/case/server/services/index.ts b/x-pack/plugins/case/server/services/index.ts index fba8bdf122917c..56e48b45a1cc32 100644 --- a/x-pack/plugins/case/server/services/index.ts +++ b/x-pack/plugins/case/server/services/index.ts @@ -19,7 +19,6 @@ import { UpdatedCaseFormatted, UpdatedCommentType, } from '../routes/api/types'; -import { wrapError } from '../routes/api/utils'; import { PluginSetupContract as SecurityPluginSetup } from '../../../security/server/plugin'; interface ClientArgs { @@ -137,13 +136,18 @@ export class CaseService { user = await authentication!.getCurrentUser(request); } catch (error) { this.log.debug(`Error on GET user: ${error}`); - throw response.customError(wrapError(error)); + throw error; } if (!user) { this.log.debug(`Error on GET user: Bad User`); - throw response.customError( - wrapError({ name: 'Bad User', message: 'The user is not authenticated' }) - ); + throw response.badRequest({ + body: { + message: 'Bad User - the user is not authenticated', + attributes: { + requestBody: request.body, + }, + }, + }); } return user; },