Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
11ecb4e6fc
commit
f2a5c47484
|
@ -9,13 +9,11 @@ import * as rt from 'io-ts';
|
|||
|
||||
import { UserRT } from '../user';
|
||||
import { CaseConnectorRt, ConnectorMappingsRt, ESCaseConnector } from '../connectors';
|
||||
import { OmitProp } from '../runtime_types';
|
||||
import { OWNER_FIELD } from './constants';
|
||||
|
||||
// TODO: we will need to add this type rt.literal('close-by-third-party')
|
||||
const ClosureTypeRT = rt.union([rt.literal('close-by-user'), rt.literal('close-by-pushing')]);
|
||||
|
||||
const CasesConfigureBasicRt = rt.type({
|
||||
const CasesConfigureBasicWithoutOwnerRt = rt.type({
|
||||
/**
|
||||
* The external connector
|
||||
*/
|
||||
|
@ -24,15 +22,17 @@ const CasesConfigureBasicRt = rt.type({
|
|||
* Whether to close the case after it has been synced with the external system
|
||||
*/
|
||||
closure_type: ClosureTypeRT,
|
||||
/**
|
||||
* The plugin owner that manages this configuration
|
||||
*/
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
const CasesConfigureBasicWithoutOwnerRt = rt.type(
|
||||
OmitProp(CasesConfigureBasicRt.props, OWNER_FIELD)
|
||||
);
|
||||
const CasesConfigureBasicRt = rt.intersection([
|
||||
CasesConfigureBasicWithoutOwnerRt,
|
||||
rt.type({
|
||||
/**
|
||||
* The plugin owner that manages this configuration
|
||||
*/
|
||||
owner: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CasesConfigureRequestRt = CasesConfigureBasicRt;
|
||||
export const CasesConfigurePatchRt = rt.intersection([
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { omit } from 'lodash';
|
||||
import { either, fold } from 'fp-ts/lib/Either';
|
||||
import { identity } from 'fp-ts/lib/function';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
|
@ -14,9 +13,6 @@ import { isObject } from 'lodash/fp';
|
|||
|
||||
type ErrorFactory = (message: string) => Error;
|
||||
|
||||
export const OmitProp = <O extends rt.Props, K extends keyof O>(o: O, k: K): Omit<O, K> =>
|
||||
omit(o, k);
|
||||
|
||||
/**
|
||||
* @deprecated Use packages/kbn-securitysolution-io-ts-utils/src/format_errors/index.ts
|
||||
* Bug fix for the TODO is in the format_errors package
|
||||
|
|
|
@ -92,3 +92,6 @@ export const ENABLE_CASE_CONNECTOR = false;
|
|||
if (ENABLE_CASE_CONNECTOR) {
|
||||
SAVED_OBJECT_TYPES.push(SUB_CASE_SAVED_OBJECT);
|
||||
}
|
||||
|
||||
export const MAX_DOCS_PER_PAGE = 10000;
|
||||
export const MAX_CONCURRENT_SEARCHES = 10;
|
||||
|
|
|
@ -6,9 +6,15 @@
|
|||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../common/constants';
|
||||
import pMap from 'p-map';
|
||||
|
||||
import { AssociationType } from '../../../common/api';
|
||||
import { SavedObject } from 'kibana/public';
|
||||
import {
|
||||
CASE_SAVED_OBJECT,
|
||||
MAX_CONCURRENT_SEARCHES,
|
||||
SUB_CASE_SAVED_OBJECT,
|
||||
} from '../../../common/constants';
|
||||
import { AssociationType, CommentAttributes } from '../../../common/api';
|
||||
import { CasesClientArgs } from '../types';
|
||||
import { buildCommentUserActionItem } from '../../services/user_actions/helpers';
|
||||
import { createCaseError } from '../../common/error';
|
||||
|
@ -88,14 +94,16 @@ export async function deleteAll(
|
|||
})),
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
comments.saved_objects.map((comment) =>
|
||||
attachmentService.delete({
|
||||
unsecuredSavedObjectsClient,
|
||||
attachmentId: comment.id,
|
||||
})
|
||||
)
|
||||
);
|
||||
const mapper = async (comment: SavedObject<CommentAttributes>) =>
|
||||
attachmentService.delete({
|
||||
unsecuredSavedObjectsClient,
|
||||
attachmentId: comment.id,
|
||||
});
|
||||
|
||||
// Ensuring we don't too many concurrent deletions running.
|
||||
await pMap(comments.saved_objects, mapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
const deleteDate = new Date().toISOString();
|
||||
|
||||
|
|
|
@ -5,15 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import pMap from 'p-map';
|
||||
import { Boom } from '@hapi/boom';
|
||||
import { SavedObjectsClientContract } from 'kibana/server';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
import { SavedObject, SavedObjectsClientContract, SavedObjectsFindResponse } from 'kibana/server';
|
||||
import { ENABLE_CASE_CONNECTOR, MAX_CONCURRENT_SEARCHES } from '../../../common/constants';
|
||||
import { CasesClientArgs } from '..';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { AttachmentService, CasesService } from '../../services';
|
||||
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
|
||||
import { Operations, OwnerEntity } from '../../authorization';
|
||||
import { OWNER_FIELD } from '../../../common/api';
|
||||
import { OWNER_FIELD, SubCaseAttributes, CommentAttributes } from '../../../common/api';
|
||||
|
||||
async function deleteSubCases({
|
||||
attachmentService,
|
||||
|
@ -37,19 +38,24 @@ async function deleteSubCases({
|
|||
id: subCaseIDs,
|
||||
});
|
||||
|
||||
// This shouldn't actually delete anything because all the comments should be deleted when comments are deleted
|
||||
// per case ID
|
||||
await Promise.all(
|
||||
commentsForSubCases.saved_objects.map((commentSO) =>
|
||||
attachmentService.delete({ unsecuredSavedObjectsClient, attachmentId: commentSO.id })
|
||||
)
|
||||
);
|
||||
const commentMapper = (commentSO: SavedObject<CommentAttributes>) =>
|
||||
attachmentService.delete({ unsecuredSavedObjectsClient, attachmentId: commentSO.id });
|
||||
|
||||
await Promise.all(
|
||||
subCasesForCaseIds.saved_objects.map((subCaseSO) =>
|
||||
caseService.deleteSubCase(unsecuredSavedObjectsClient, subCaseSO.id)
|
||||
)
|
||||
);
|
||||
const subCasesMapper = (subCaseSO: SavedObject<SubCaseAttributes>) =>
|
||||
caseService.deleteSubCase(unsecuredSavedObjectsClient, subCaseSO.id);
|
||||
|
||||
/**
|
||||
* This shouldn't actually delete anything because
|
||||
* all the comments should be deleted when comments are deleted
|
||||
* per case ID. We also ensure that we don't too many concurrent deletions running.
|
||||
*/
|
||||
await pMap(commentsForSubCases.saved_objects, commentMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
await pMap(subCasesForCaseIds.saved_objects, subCasesMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,38 +94,46 @@ export async function deleteCases(ids: string[], clientArgs: CasesClientArgs): P
|
|||
entities: Array.from(entities.values()),
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
ids.map((id) =>
|
||||
caseService.deleteCase({
|
||||
unsecuredSavedObjectsClient,
|
||||
id,
|
||||
})
|
||||
)
|
||||
);
|
||||
const deleteCasesMapper = async (id: string) =>
|
||||
caseService.deleteCase({
|
||||
unsecuredSavedObjectsClient,
|
||||
id,
|
||||
});
|
||||
|
||||
const comments = await Promise.all(
|
||||
ids.map((id) =>
|
||||
caseService.getAllCaseComments({
|
||||
unsecuredSavedObjectsClient,
|
||||
id,
|
||||
})
|
||||
)
|
||||
);
|
||||
// Ensuring we don't too many concurrent deletions running.
|
||||
await pMap(ids, deleteCasesMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
if (comments.some((c) => c.saved_objects.length > 0)) {
|
||||
await Promise.all(
|
||||
comments.map((c) =>
|
||||
Promise.all(
|
||||
c.saved_objects.map(({ id }) =>
|
||||
attachmentService.delete({
|
||||
unsecuredSavedObjectsClient,
|
||||
attachmentId: id,
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
const getCommentsMapper = async (id: string) =>
|
||||
caseService.getAllCaseComments({
|
||||
unsecuredSavedObjectsClient,
|
||||
id,
|
||||
});
|
||||
|
||||
// Ensuring we don't too many concurrent get running.
|
||||
const comments = await pMap(ids, getCommentsMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
/**
|
||||
* This is a nested pMap.Mapper.
|
||||
* Each element of the comments array contains all comments of a particular case.
|
||||
* For that reason we need first to create a map that iterate over all cases
|
||||
* and return a pMap that deletes the comments for that case
|
||||
*/
|
||||
const deleteCommentsMapper = async (commentRes: SavedObjectsFindResponse<CommentAttributes>) =>
|
||||
pMap(commentRes.saved_objects, (comment) =>
|
||||
attachmentService.delete({
|
||||
unsecuredSavedObjectsClient,
|
||||
attachmentId: comment.id,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Ensuring we don't too many concurrent deletions running.
|
||||
await pMap(comments, deleteCommentsMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
if (ENABLE_CASE_CONNECTOR) {
|
||||
await deleteSubCases({
|
||||
|
|
|
@ -77,6 +77,7 @@ export const find = async (
|
|||
|
||||
ensureSavedObjectsAreAuthorized([...cases.casesMap.values()]);
|
||||
|
||||
// casesStatuses are bounded by us. No need to limit concurrent calls.
|
||||
const [openCases, inProgressCases, closedCases] = await Promise.all([
|
||||
...caseStatuses.map((status) => {
|
||||
const statusQuery = constructQueryOptions({ ...queryArgs, status, authorizationFilter });
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import pMap from 'p-map';
|
||||
import Boom from '@hapi/boom';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { fold } from 'fp-ts/lib/Either';
|
||||
|
@ -42,6 +43,7 @@ import { CasesService } from '../../services';
|
|||
import {
|
||||
CASE_COMMENT_SAVED_OBJECT,
|
||||
CASE_SAVED_OBJECT,
|
||||
MAX_CONCURRENT_SEARCHES,
|
||||
SUB_CASE_SAVED_OBJECT,
|
||||
} from '../../../common/constants';
|
||||
import {
|
||||
|
@ -162,9 +164,11 @@ async function throwIfInvalidUpdateOfTypeWithAlerts({
|
|||
};
|
||||
|
||||
const requestsUpdatingTypeField = requests.filter((req) => req.type === CaseType.collection);
|
||||
const casesAlertTotals = await Promise.all(
|
||||
requestsUpdatingTypeField.map((caseToUpdate) => getAlertsForID(caseToUpdate))
|
||||
);
|
||||
const getAlertsMapper = async (caseToUpdate: ESCasePatchRequest) => getAlertsForID(caseToUpdate);
|
||||
// Ensuring we don't too many concurrent get running.
|
||||
const casesAlertTotals = await pMap(requestsUpdatingTypeField, getAlertsMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
// grab the cases that have at least one alert comment attached to them
|
||||
const typeUpdateWithAlerts = casesAlertTotals.filter((caseInfo) => caseInfo.alerts.total > 0);
|
||||
|
|
|
@ -4,13 +4,19 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import pMap from 'p-map';
|
||||
import Boom from '@hapi/boom';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
import { fold } from 'fp-ts/lib/Either';
|
||||
import { identity } from 'fp-ts/lib/function';
|
||||
|
||||
import { SavedObjectsFindResponse, SavedObjectsUtils } from '../../../../../../src/core/server';
|
||||
import { SUPPORTED_CONNECTORS } from '../../../common/constants';
|
||||
import {
|
||||
SavedObject,
|
||||
SavedObjectsFindResponse,
|
||||
SavedObjectsUtils,
|
||||
} from '../../../../../../src/core/server';
|
||||
import { MAX_CONCURRENT_SEARCHES, SUPPORTED_CONNECTORS } from '../../../common/constants';
|
||||
import {
|
||||
CaseConfigureResponseRt,
|
||||
CasesConfigurePatch,
|
||||
|
@ -26,6 +32,7 @@ import {
|
|||
CaseConfigurationsResponseRt,
|
||||
CasesConfigurePatchRt,
|
||||
ConnectorMappings,
|
||||
ESCasesConfigureAttributes,
|
||||
} from '../../../common/api';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import {
|
||||
|
@ -175,8 +182,9 @@ async function get(
|
|||
}))
|
||||
);
|
||||
|
||||
const configurations = await Promise.all(
|
||||
myCaseConfigure.saved_objects.map(async (configuration) => {
|
||||
const configurations = await pMap(
|
||||
myCaseConfigure.saved_objects,
|
||||
async (configuration: SavedObject<ESCasesConfigureAttributes>) => {
|
||||
const { connector, ...caseConfigureWithoutConnector } = configuration?.attributes ?? {
|
||||
connector: null,
|
||||
};
|
||||
|
@ -204,7 +212,7 @@ async function get(
|
|||
error,
|
||||
id: configuration.id,
|
||||
};
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
return CaseConfigurationsResponseRt.encode(configurations);
|
||||
|
@ -400,11 +408,13 @@ async function create(
|
|||
);
|
||||
|
||||
if (myCaseConfigure.saved_objects.length > 0) {
|
||||
await Promise.all(
|
||||
myCaseConfigure.saved_objects.map((cc) =>
|
||||
caseConfigureService.delete({ unsecuredSavedObjectsClient, configurationId: cc.id })
|
||||
)
|
||||
);
|
||||
const deleteConfigurationMapper = async (c: SavedObject<ESCasesConfigureAttributes>) =>
|
||||
caseConfigureService.delete({ unsecuredSavedObjectsClient, configurationId: c.id });
|
||||
|
||||
// Ensuring we don't too many concurrent deletions running.
|
||||
await pMap(myCaseConfigure.saved_objects, deleteConfigurationMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
}
|
||||
|
||||
const savedObjectID = SavedObjectsUtils.generateId();
|
||||
|
|
|
@ -63,6 +63,7 @@ async function getStatusTotalsByType(
|
|||
ensureSavedObjectsAreAuthorized,
|
||||
} = await authorization.getAuthorizationFilter(Operations.getCaseStatuses);
|
||||
|
||||
// casesStatuses are bounded by us. No need to limit concurrent calls.
|
||||
const [openCases, inProgressCases, closedCases] = await Promise.all([
|
||||
...caseStatuses.map((status) => {
|
||||
const statusQuery = constructQueryOptions({
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import pMap from 'p-map';
|
||||
import Boom from '@hapi/boom';
|
||||
|
||||
import { SavedObject } from 'kibana/server';
|
||||
import {
|
||||
caseStatuses,
|
||||
CommentAttributes,
|
||||
SubCaseResponse,
|
||||
SubCaseResponseRt,
|
||||
SubCasesFindRequest,
|
||||
|
@ -19,7 +22,7 @@ import {
|
|||
import { CasesClientArgs, CasesClientInternal } from '..';
|
||||
import { countAlertsForID, flattenSubCaseSavedObject, transformSubCases } from '../../common';
|
||||
import { createCaseError } from '../../common/error';
|
||||
import { CASE_SAVED_OBJECT } from '../../../common/constants';
|
||||
import { CASE_SAVED_OBJECT, MAX_CONCURRENT_SEARCHES } from '../../../common/constants';
|
||||
import { buildCaseUserActionItem } from '../../services/user_actions/helpers';
|
||||
import { constructQueryOptions } from '../utils';
|
||||
import { defaultPage, defaultPerPage } from '../../routes/api';
|
||||
|
@ -121,13 +124,20 @@ async function deleteSubCase(ids: string[], clientArgs: CasesClientArgs): Promis
|
|||
return acc;
|
||||
}, new Map<string, string | undefined>());
|
||||
|
||||
await Promise.all(
|
||||
comments.saved_objects.map((comment) =>
|
||||
attachmentService.delete({ unsecuredSavedObjectsClient, attachmentId: comment.id })
|
||||
)
|
||||
);
|
||||
const deleteCommentMapper = async (comment: SavedObject<CommentAttributes>) =>
|
||||
attachmentService.delete({ unsecuredSavedObjectsClient, attachmentId: comment.id });
|
||||
|
||||
await Promise.all(ids.map((id) => caseService.deleteSubCase(unsecuredSavedObjectsClient, id)));
|
||||
const deleteSubCasesMapper = async (id: string) =>
|
||||
caseService.deleteSubCase(unsecuredSavedObjectsClient, id);
|
||||
|
||||
// Ensuring we don't too many concurrent deletions running.
|
||||
await pMap(comments.saved_objects, deleteCommentMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
await pMap(ids, deleteSubCasesMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
const deleteDate = new Date().toISOString();
|
||||
|
||||
|
@ -181,6 +191,7 @@ async function find(
|
|||
},
|
||||
});
|
||||
|
||||
// casesStatuses are bounded by us. No need to limit concurrent calls.
|
||||
const [open, inProgress, closed] = await Promise.all([
|
||||
...caseStatuses.map((status) => {
|
||||
const { subCase: statusQueryOptions } = constructQueryOptions({
|
||||
|
|
|
@ -34,7 +34,11 @@ import {
|
|||
flattenSubCaseSavedObject,
|
||||
transformNewComment,
|
||||
} from '..';
|
||||
import { CASE_SAVED_OBJECT, SUB_CASE_SAVED_OBJECT } from '../../../common/constants';
|
||||
import {
|
||||
CASE_SAVED_OBJECT,
|
||||
MAX_DOCS_PER_PAGE,
|
||||
SUB_CASE_SAVED_OBJECT,
|
||||
} from '../../../common/constants';
|
||||
import { AttachmentService, CasesService } from '../../services';
|
||||
import { createCaseError } from '../error';
|
||||
import { countAlertsForID } from '../index';
|
||||
|
@ -309,23 +313,13 @@ export class CommentableCase {
|
|||
|
||||
public async encode(): Promise<CaseResponse> {
|
||||
try {
|
||||
const collectionCommentStats = await this.caseService.getAllCaseComments({
|
||||
unsecuredSavedObjectsClient: this.unsecuredSavedObjectsClient,
|
||||
id: this.collection.id,
|
||||
options: {
|
||||
fields: [],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
},
|
||||
});
|
||||
|
||||
const collectionComments = await this.caseService.getAllCaseComments({
|
||||
unsecuredSavedObjectsClient: this.unsecuredSavedObjectsClient,
|
||||
id: this.collection.id,
|
||||
options: {
|
||||
fields: [],
|
||||
page: 1,
|
||||
perPage: collectionCommentStats.total,
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -335,7 +329,7 @@ export class CommentableCase {
|
|||
const caseResponse = {
|
||||
comments: flattenCommentSavedObjects(collectionComments.saved_objects),
|
||||
totalAlerts: collectionTotalAlerts,
|
||||
...this.formatCollectionForEncoding(collectionCommentStats.total),
|
||||
...this.formatCollectionForEncoding(collectionComments.total),
|
||||
};
|
||||
|
||||
if (this.subCase) {
|
||||
|
|
|
@ -57,10 +57,10 @@ export class AttachmentService {
|
|||
|
||||
public async delete({ unsecuredSavedObjectsClient, attachmentId }: GetAttachmentArgs) {
|
||||
try {
|
||||
this.log.debug(`Attempting to GET attachment ${attachmentId}`);
|
||||
this.log.debug(`Attempting to DELETE attachment ${attachmentId}`);
|
||||
return await unsecuredSavedObjectsClient.delete(CASE_COMMENT_SAVED_OBJECT, attachmentId);
|
||||
} catch (error) {
|
||||
this.log.error(`Error on GET attachment ${attachmentId}: ${error}`);
|
||||
this.log.error(`Error on DELETE attachment ${attachmentId}: ${error}`);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
import pMap from 'p-map';
|
||||
import {
|
||||
KibanaRequest,
|
||||
Logger,
|
||||
|
@ -43,7 +43,11 @@ import {
|
|||
groupTotalAlertsByID,
|
||||
SavedObjectFindOptionsKueryNode,
|
||||
} from '../../common';
|
||||
import { ENABLE_CASE_CONNECTOR } from '../../../common/constants';
|
||||
import {
|
||||
ENABLE_CASE_CONNECTOR,
|
||||
MAX_CONCURRENT_SEARCHES,
|
||||
MAX_DOCS_PER_PAGE,
|
||||
} from '../../../common/constants';
|
||||
import { defaultPage, defaultPerPage } from '../../routes/api';
|
||||
import {
|
||||
CASE_SAVED_OBJECT,
|
||||
|
@ -250,7 +254,7 @@ export class CasesService {
|
|||
filter,
|
||||
]);
|
||||
|
||||
let response = await unsecuredSavedObjectsClient.find<
|
||||
const response = await unsecuredSavedObjectsClient.find<
|
||||
CommentAttributes,
|
||||
GetCaseIdsByAlertIdAggs
|
||||
>({
|
||||
|
@ -259,23 +263,9 @@ export class CasesService {
|
|||
page: 1,
|
||||
perPage: 1,
|
||||
sortField: defaultSortField,
|
||||
aggs: this.buildCaseIdsAggs(),
|
||||
aggs: this.buildCaseIdsAggs(MAX_DOCS_PER_PAGE),
|
||||
filter: combinedFilter,
|
||||
});
|
||||
if (response.total > 100) {
|
||||
response = await unsecuredSavedObjectsClient.find<
|
||||
CommentAttributes,
|
||||
GetCaseIdsByAlertIdAggs
|
||||
>({
|
||||
type: CASE_COMMENT_SAVED_OBJECT,
|
||||
fields: includeFieldsRequiredForAuthentication(),
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
sortField: defaultSortField,
|
||||
aggs: this.buildCaseIdsAggs(response.total),
|
||||
filter: combinedFilter,
|
||||
});
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.log.error(`Error on GET all cases for alert id ${alertId}: ${error}`);
|
||||
|
@ -393,16 +383,6 @@ export class CasesService {
|
|||
ensureSavedObjectsAreAuthorized: EnsureSOAuthCallback;
|
||||
subCaseOptions?: SavedObjectFindOptionsKueryNode;
|
||||
}): Promise<number> {
|
||||
const casesStats = await this.findCases({
|
||||
unsecuredSavedObjectsClient,
|
||||
options: {
|
||||
...caseOptions,
|
||||
fields: [],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* This could be made more performant. What we're doing here is retrieving all cases
|
||||
* that match the API request's filters instead of just counts. This is because we need to grab
|
||||
|
@ -429,7 +409,7 @@ export class CasesService {
|
|||
...caseOptions,
|
||||
fields: includeFieldsRequiredForAuthentication([caseTypeField]),
|
||||
page: 1,
|
||||
perPage: casesStats.total,
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -447,7 +427,7 @@ export class CasesService {
|
|||
if (ENABLE_CASE_CONNECTOR && subCaseOptions) {
|
||||
subCasesTotal = await this.findSubCaseStatusStats({
|
||||
unsecuredSavedObjectsClient,
|
||||
options: cloneDeep(subCaseOptions),
|
||||
options: subCaseOptions,
|
||||
ids: caseIds,
|
||||
});
|
||||
}
|
||||
|
@ -505,16 +485,18 @@ export class CasesService {
|
|||
const refType =
|
||||
associationType === AssociationType.case ? CASE_SAVED_OBJECT : SUB_CASE_SAVED_OBJECT;
|
||||
|
||||
const allComments = await Promise.all(
|
||||
ids.map((id) =>
|
||||
this.getCommentsByAssociation({
|
||||
unsecuredSavedObjectsClient,
|
||||
associationType,
|
||||
id,
|
||||
options: { page: 1, perPage: 1 },
|
||||
})
|
||||
)
|
||||
);
|
||||
const getCommentsMapper = async (id: string) =>
|
||||
this.getCommentsByAssociation({
|
||||
unsecuredSavedObjectsClient,
|
||||
associationType,
|
||||
id,
|
||||
options: { page: 1, perPage: 1 },
|
||||
});
|
||||
|
||||
// Ensuring we don't too many concurrent get running.
|
||||
const allComments = await pMap(ids, getCommentsMapper, {
|
||||
concurrency: MAX_CONCURRENT_SEARCHES,
|
||||
});
|
||||
|
||||
const alerts = await this.getCommentsByAssociation({
|
||||
unsecuredSavedObjectsClient,
|
||||
|
@ -795,7 +777,7 @@ export class CasesService {
|
|||
this.log.debug(`Attempting to find cases`);
|
||||
return await unsecuredSavedObjectsClient.find<ESCaseAttributes>({
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
type: CASE_SAVED_OBJECT,
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -815,24 +797,16 @@ export class CasesService {
|
|||
if (options?.page !== undefined || options?.perPage !== undefined) {
|
||||
return unsecuredSavedObjectsClient.find<SubCaseAttributes>({
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
type: SUB_CASE_SAVED_OBJECT,
|
||||
});
|
||||
}
|
||||
|
||||
const stats = await unsecuredSavedObjectsClient.find<SubCaseAttributes>({
|
||||
fields: [],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
type: SUB_CASE_SAVED_OBJECT,
|
||||
});
|
||||
return unsecuredSavedObjectsClient.find<SubCaseAttributes>({
|
||||
page: 1,
|
||||
perPage: stats.total,
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
type: SUB_CASE_SAVED_OBJECT,
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -902,26 +876,16 @@ export class CasesService {
|
|||
return unsecuredSavedObjectsClient.find<CommentAttributes>({
|
||||
type: CASE_COMMENT_SAVED_OBJECT,
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
});
|
||||
}
|
||||
// get the total number of comments that are in ES then we'll grab them all in one go
|
||||
const stats = await unsecuredSavedObjectsClient.find<CommentAttributes>({
|
||||
type: CASE_COMMENT_SAVED_OBJECT,
|
||||
fields: [],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
sortField: defaultSortField,
|
||||
// spread the options after so the caller can override the default behavior if they want
|
||||
...cloneDeep(options),
|
||||
});
|
||||
|
||||
return unsecuredSavedObjectsClient.find<CommentAttributes>({
|
||||
type: CASE_COMMENT_SAVED_OBJECT,
|
||||
page: 1,
|
||||
perPage: stats.total,
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
sortField: defaultSortField,
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
});
|
||||
} catch (error) {
|
||||
this.log.error(`Error on GET all comments internal for ${JSON.stringify(id)}: ${error}`);
|
||||
|
@ -1022,20 +986,13 @@ export class CasesService {
|
|||
}: GetReportersArgs): Promise<SavedObjectsFindResponse<ESCaseAttributes>> {
|
||||
try {
|
||||
this.log.debug(`Attempting to GET all reporters`);
|
||||
const firstReporters = await unsecuredSavedObjectsClient.find({
|
||||
type: CASE_SAVED_OBJECT,
|
||||
fields: ['created_by', OWNER_FIELD],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
filter: cloneDeep(filter),
|
||||
});
|
||||
|
||||
return await unsecuredSavedObjectsClient.find<ESCaseAttributes>({
|
||||
type: CASE_SAVED_OBJECT,
|
||||
fields: ['created_by', OWNER_FIELD],
|
||||
page: 1,
|
||||
perPage: firstReporters.total,
|
||||
filter: cloneDeep(filter),
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
filter,
|
||||
});
|
||||
} catch (error) {
|
||||
this.log.error(`Error on GET all reporters: ${error}`);
|
||||
|
@ -1049,20 +1006,13 @@ export class CasesService {
|
|||
}: GetTagsArgs): Promise<SavedObjectsFindResponse<ESCaseAttributes>> {
|
||||
try {
|
||||
this.log.debug(`Attempting to GET all cases`);
|
||||
const firstTags = await unsecuredSavedObjectsClient.find({
|
||||
type: CASE_SAVED_OBJECT,
|
||||
fields: ['tags', OWNER_FIELD],
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
filter: cloneDeep(filter),
|
||||
});
|
||||
|
||||
return await unsecuredSavedObjectsClient.find<ESCaseAttributes>({
|
||||
type: CASE_SAVED_OBJECT,
|
||||
fields: ['tags', OWNER_FIELD],
|
||||
page: 1,
|
||||
perPage: firstTags.total,
|
||||
filter: cloneDeep(filter),
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
filter,
|
||||
});
|
||||
} catch (error) {
|
||||
this.log.error(`Error on GET tags: ${error}`);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { Logger, SavedObjectsClientContract } from 'kibana/server';
|
||||
|
||||
import { SavedObjectFindOptionsKueryNode } from '../../common';
|
||||
|
@ -63,7 +62,7 @@ export class CaseConfigureService {
|
|||
try {
|
||||
this.log.debug(`Attempting to find all case configuration`);
|
||||
return await unsecuredSavedObjectsClient.find<ESCasesConfigureAttributes>({
|
||||
...cloneDeep(options),
|
||||
...options,
|
||||
// Get the latest configuration
|
||||
sortField: 'created_at',
|
||||
sortOrder: 'desc',
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
CASE_USER_ACTION_SAVED_OBJECT,
|
||||
CASE_SAVED_OBJECT,
|
||||
SUB_CASE_SAVED_OBJECT,
|
||||
MAX_DOCS_PER_PAGE,
|
||||
} from '../../../common/constants';
|
||||
import { ClientArgs } from '..';
|
||||
|
||||
|
@ -36,19 +37,12 @@ export class CaseUserActionService {
|
|||
try {
|
||||
const id = subCaseId ?? caseId;
|
||||
const type = subCaseId ? SUB_CASE_SAVED_OBJECT : CASE_SAVED_OBJECT;
|
||||
const caseUserActionInfo = await unsecuredSavedObjectsClient.find<CaseUserActionAttributes>({
|
||||
type: CASE_USER_ACTION_SAVED_OBJECT,
|
||||
fields: [],
|
||||
hasReference: { type, id },
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
});
|
||||
|
||||
return await unsecuredSavedObjectsClient.find<CaseUserActionAttributes>({
|
||||
type: CASE_USER_ACTION_SAVED_OBJECT,
|
||||
hasReference: { type, id },
|
||||
page: 1,
|
||||
perPage: caseUserActionInfo.total,
|
||||
perPage: MAX_DOCS_PER_PAGE,
|
||||
sortField: 'action_at',
|
||||
sortOrder: 'asc',
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue