Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cases] Move remaining HTTP functionality to client #96507

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions x-pack/plugins/cases/server/client/attachments/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { identity } from 'fp-ts/lib/function';

import { SavedObject, SavedObjectsClientContract, Logger } from 'src/core/server';
import { nodeBuilder } from '../../../../../../src/plugins/data/common';
import { decodeCommentRequest, isCommentRequestTypeGenAlert } from '../../routes/api/utils';

import {
throwErrors,
Expand All @@ -33,7 +32,11 @@ import {
} from '../../services/user_actions/helpers';

import { AttachmentService, CaseService, CaseUserActionService } from '../../services';
import { CommentableCase, createAlertUpdateRequest } from '../../common';
import {
CommentableCase,
createAlertUpdateRequest,
isCommentRequestTypeGenAlert,
} from '../../common';
import { CasesClientArgs, CasesClientInternal } from '..';
import { createCaseError } from '../../common/error';
import {
Expand All @@ -42,6 +45,8 @@ import {
ENABLE_CASE_CONNECTOR,
} from '../../../common/constants';

import { decodeCommentRequest } from '../utils';

async function getSubCase({
caseService,
savedObjectsClient,
Expand Down
26 changes: 24 additions & 2 deletions x-pack/plugins/cases/server/client/attachments/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,34 @@
* 2.0.
*/

import { CaseResponse, CommentRequest as AttachmentsRequest } from '../../../common/api';
import {
AllCommentsResponse,
CaseResponse,
CommentRequest as AttachmentsRequest,
CommentResponse,
CommentsResponse,
} from '../../../common/api';

import { CasesClientInternal } from '../client_internal';
import { CasesClientArgs } from '../types';
import { addComment } from './add';
import { DeleteAllArgs, deleteAll, DeleteArgs, deleteComment } from './delete';
import { find, FindArgs, get, getAll, GetAllArgs, GetArgs } from './get';
import { update, UpdateArgs } from './update';

export interface AttachmentsAdd {
jonathan-buttner marked this conversation as resolved.
Show resolved Hide resolved
interface AttachmentsAdd {
caseId: string;
comment: AttachmentsRequest;
}

export interface AttachmentsSubClient {
add(args: AttachmentsAdd): Promise<CaseResponse>;
deleteAll(deleteAllArgs: DeleteAllArgs): Promise<void>;
delete(deleteArgs: DeleteArgs): Promise<void>;
find(findArgs: FindArgs): Promise<CommentsResponse>;
getAll(getAllArgs: GetAllArgs): Promise<AllCommentsResponse>;
get(getArgs: GetArgs): Promise<CommentResponse>;
update(updateArgs: UpdateArgs): Promise<CaseResponse>;
}

export const createAttachmentsSubClient = (
Expand All @@ -31,6 +47,12 @@ export const createAttachmentsSubClient = (
caseId,
comment,
}),
deleteAll: (deleteAllArgs: DeleteAllArgs) => deleteAll(deleteAllArgs, args),
delete: (deleteArgs: DeleteArgs) => deleteComment(deleteArgs, args),
find: (findArgs: FindArgs) => find(findArgs, args),
getAll: (getAllArgs: GetAllArgs) => getAll(getAllArgs, args),
get: (getArgs: GetArgs) => get(getArgs, args),
update: (updateArgs: UpdateArgs) => update(updateArgs, args),
};

return Object.freeze(attachmentSubClient);
Expand Down
154 changes: 154 additions & 0 deletions x-pack/plugins/cases/server/client/attachments/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* 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 Boom from '@hapi/boom';
import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../common/constants';

import { AssociationType } from '../../../common/api';
import { CasesClientArgs } from '../types';
import { buildCommentUserActionItem } from '../../services/user_actions/helpers';
import { createCaseError } from '../../common/error';
import { checkEnabledCaseConnectorOrThrow } from '../../common';

/**
* Parameters for deleting all comments of a case or sub case.
*/
export interface DeleteAllArgs {
caseID: string;
subCaseID?: string;
}

/**
* Parameters for deleting a single comment of a case or sub case.
*/
export interface DeleteArgs {
caseID: string;
attachmentID: string;
subCaseID?: string;
}

/**
* Delete all comments for a case or sub case.
*/
export async function deleteAll(
{ caseID, subCaseID }: DeleteAllArgs,
clientArgs: CasesClientArgs
): Promise<void> {
const {
user,
savedObjectsClient: soClient,
caseService,
attachmentService,
userActionService,
logger,
} = clientArgs;

try {
checkEnabledCaseConnectorOrThrow(subCaseID);

const id = subCaseID ?? caseID;
const comments = await caseService.getCommentsByAssociation({
soClient,
id,
associationType: subCaseID ? AssociationType.subCase : AssociationType.case,
});

await Promise.all(
comments.saved_objects.map((comment) =>
attachmentService.delete({
soClient,
attachmentId: comment.id,
})
)
);

const deleteDate = new Date().toISOString();

await userActionService.bulkCreate({
soClient,
actions: comments.saved_objects.map((comment) =>
buildCommentUserActionItem({
action: 'delete',
actionAt: deleteDate,
actionBy: user,
caseId: caseID,
subCaseId: subCaseID,
commentId: comment.id,
fields: ['comment'],
})
),
});
} catch (error) {
throw createCaseError({
message: `Failed to delete all comments case id: ${caseID} sub case id: ${subCaseID}: ${error}`,
error,
logger,
});
}
}

export async function deleteComment(
{ caseID, attachmentID, subCaseID }: DeleteArgs,
clientArgs: CasesClientArgs
) {
const {
user,
savedObjectsClient: soClient,
attachmentService,
userActionService,
logger,
} = clientArgs;

try {
checkEnabledCaseConnectorOrThrow(subCaseID);

const deleteDate = new Date().toISOString();

const myComment = await attachmentService.get({
soClient,
attachmentId: attachmentID,
});

if (myComment == null) {
throw Boom.notFound(`This comment ${attachmentID} does not exist anymore.`);
}

const type = subCaseID ? SUB_CASE_SAVED_OBJECT : CASE_SAVED_OBJECT;
const id = subCaseID ?? caseID;

const caseRef = myComment.references.find((c) => c.type === type);
if (caseRef == null || (caseRef != null && caseRef.id !== id)) {
throw Boom.notFound(`This comment ${attachmentID} does not exist in ${id}.`);
}

await attachmentService.delete({
soClient,
attachmentId: attachmentID,
});

await userActionService.bulkCreate({
soClient,
actions: [
buildCommentUserActionItem({
action: 'delete',
actionAt: deleteDate,
actionBy: user,
caseId: id,
subCaseId: subCaseID,
commentId: attachmentID,
fields: ['comment'],
}),
],
});
} catch (error) {
throw createCaseError({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question about createCaseError: are these messages shown to users, including via HTTP responses? If so, I'm wondering if they should be internationalized.

Copy link
Member

@cnasikas cnasikas Apr 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oatkiller That's a good question. Yes, some of them are being shown to the users. I think i18n is not supported for the backend. Do you know how to internationalize these messages?

Copy link
Contributor Author

@jonathan-buttner jonathan-buttner Apr 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of these messages are just logged to the console/some file but some of them do get bubbled up to the user. @XavierM @legrego @kobelb should we internationalize server side error and audit log messages?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we internationalize server side error and audit log messages?

I don't know of an official stance, but personally I'd vote to keep them in English. That makes for a consistent auditing, debugging, and triaging experience, and makes searching for solutions based on error messages much easier

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonathan-buttner I don't think we have an official stance, but +1 for keeping them in English.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should still i18n the messages that are show to the user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@legrego @kobelb @jonathan-buttner @cnasikas I opened a discuss issue about this: #97650

message: `Failed to delete comment in route case id: ${caseID} comment id: ${attachmentID} sub case id: ${subCaseID}: ${error}`,
error,
logger,
});
}
}
Loading