-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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 delete files case deletion #153979
Cases delete files case deletion #153979
Conversation
…les-case-deletion
@@ -105,5 +105,5 @@ export interface FindFileArgs extends Pagination { | |||
/** | |||
* File metadata values. These values are governed by the consumer. | |||
*/ | |||
meta?: Record<string, string>; | |||
meta?: Record<string, string | string[]>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid typescript complaining we need this as a string array because we want to find any files that are associated to an array of ids.
When I looked at the way the metadata query is being built here: https://github.com/elastic/kibana/blob/main/src/plugins/files/server/file_client/file_metadata_client/adapters/query_filters.ts it looks like the file service already handles an array of strings. Let me know if that's not correct though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it seems so 👍
@@ -39,6 +40,10 @@ export const getCaseCommentDetailsUrl = (caseId: string, commentId: string): str | |||
return CASE_COMMENT_DETAILS_URL.replace('{case_id}', caseId).replace('{comment_id}', commentId); | |||
}; | |||
|
|||
export const getCaseFindAttachmentsUrl = (caseId: string): string => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just adding this to make the integration tests a little easier
@@ -77,3 +88,29 @@ export async function deleteCases(ids: string[], clientArgs: CasesClientArgs): P | |||
}); | |||
} | |||
} | |||
|
|||
export const getFileEntities = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Chunking logic is here
import { MAX_CONCURRENT_SEARCHES } from '../../../common/constants'; | ||
import type { OwnerEntity } from '../../authorization'; | ||
|
||
export const createFileEntities = (files: FileJSON[]): OwnerEntity[] => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just moved these to be shared between the bulk delete files API within cases and the delete case code.
}; | ||
|
||
export const deleteFiles = async (fileIds: string[], fileService: FileServiceStart) => { | ||
pMap(fileIds, async (fileId: string) => fileService.delete({ id: fileId }), { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@elastic/appex-sharedux how feasible would it be to have a bulk delete files API?
Issue: #154286
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for creating an issue, we will triage.
I am not sure if there were any technical or API design limitations to not adding this api.
ids: schema.arrayOf(schema.string()), | ||
ids: schema.arrayOf(schema.string({ minLength: 1 }), { | ||
minSize: 1, | ||
maxSize: MAX_DELETE_CASE_IDS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Limiting the deletion API based on the issue here: #146945
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, we cannot do that as it will be a breaking change.
…les-case-deletion
Pinging @elastic/response-ops (Team:ResponseOps) |
Pinging @elastic/response-ops-cases (Feature:Cases) |
@@ -105,5 +105,5 @@ export interface FindFileArgs extends Pagination { | |||
/** | |||
* File metadata values. These values are governed by the consumer. | |||
*/ | |||
meta?: Record<string, string>; | |||
meta?: Record<string, string | string[]>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it seems so 👍
}; | ||
|
||
export const deleteFiles = async (fileIds: string[], fileService: FileServiceStart) => { | ||
pMap(fileIds, async (fileId: string) => fileService.delete({ id: fileId }), { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for creating an issue, we will triage.
I am not sure if there were any technical or API design limitations to not adding this api.
…les-case-deletion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! I left some comments.
@@ -47,6 +47,7 @@ export const CASE_CONFIGURE_DETAILS_URL = `${CASES_URL}/configure/{configuration | |||
export const CASE_CONFIGURE_CONNECTORS_URL = `${CASE_CONFIGURE_URL}/connectors` as const; | |||
|
|||
export const CASE_COMMENTS_URL = `${CASE_DETAILS_URL}/comments` as const; | |||
export const CASE_FIND_ATTACHMENTS_URL = `${CASE_COMMENTS_URL}/_find` as const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind if you change the path
attribute here x-pack/plugins/cases/server/routes/api/comments/find_comments.ts
to use the new variable (CASE_FIND_ATTACHMENTS_URL
)?
ids: schema.arrayOf(schema.string()), | ||
ids: schema.arrayOf(schema.string({ minLength: 1 }), { | ||
minSize: 1, | ||
maxSize: MAX_DELETE_CASE_IDS, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, we cannot do that as it will be a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some unit tests for the two functions?
const chunkSize = MAX_DELETE_CASE_IDS / 2; | ||
const chunkedIds = chunk(caseIds, chunkSize); | ||
|
||
const fileResults = await pMap(chunkedIds, async (ids: string[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between this and createPointInTimeFinder
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We talked about this offline, unfortunately we can't use a createPointInTimeFinder
here since we're leveraging the file service.
const files = fileResults.flatMap((res) => res.files); | ||
const fileEntities = createFileEntities(files); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to do it inside pMap
so we don't have to iterate a large list of files?
💚 Build Succeeded
Metrics [docs]Page load bundle
Unknown metric groupsESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment with: |
This PR extends the case deletion functionality to delete any files that are attached to the case when a case is deleted.
To avoid attempting to delete too many files at once I chunk case ids into 50 at a time such that we're at most only deleting 5000 (50 case * 100 files per case) at once. That way we don't exceed the 10k find api limit.
Testing
Run the python script from here: https://github.com/elastic/cases-files-generator to generate some files for a case
Deleting the case should remove all files