Skip to content

Commit

Permalink
[ResponseOps][Cases] Get reporters and tags by aggregation (elastic#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
cnasikas authored Jan 25, 2022
1 parent 2ebc8d2 commit 08f87f0
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 65 deletions.
57 changes: 10 additions & 47 deletions x-pack/plugins/cases/server/client/cases/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
CaseResolveResponseRt,
CaseResolveResponse,
User,
UsersRt,
AllTagsFindRequest,
AllTagsFindRequestRt,
excess,
Expand Down Expand Up @@ -329,34 +328,18 @@ export async function getTags(
fold(throwErrors(Boom.badRequest), identity)
);

const { filter: authorizationFilter, ensureSavedObjectsAreAuthorized } =
await authorization.getAuthorizationFilter(Operations.findCases);
const { filter: authorizationFilter } = await authorization.getAuthorizationFilter(
Operations.findCases
);

const filter = combineAuthorizedAndOwnerFilter(queryParams.owner, authorizationFilter);

const cases = await caseService.getTags({
const tags = await caseService.getTags({
unsecuredSavedObjectsClient,
filter,
});

const tags = new Set<string>();
const mappedCases: Array<{
owner: string;
id: string;
}> = [];

// Gather all necessary information in one pass
cases.saved_objects.forEach((theCase) => {
theCase.attributes.tags.forEach((tag) => tags.add(tag));
mappedCases.push({
id: theCase.id,
owner: theCase.attributes.owner,
});
});

ensureSavedObjectsAreAuthorized(mappedCases);

return [...tags.values()];
return tags;
} catch (error) {
throw createCaseError({ message: `Failed to get tags: ${error}`, error, logger });
}
Expand All @@ -377,38 +360,18 @@ export async function getReporters(
fold(throwErrors(Boom.badRequest), identity)
);

const { filter: authorizationFilter, ensureSavedObjectsAreAuthorized } =
await authorization.getAuthorizationFilter(Operations.getReporters);
const { filter: authorizationFilter } = await authorization.getAuthorizationFilter(
Operations.getReporters
);

const filter = combineAuthorizedAndOwnerFilter(queryParams.owner, authorizationFilter);

const cases = await caseService.getReporters({
const reporters = await caseService.getReporters({
unsecuredSavedObjectsClient,
filter,
});

const reporters = new Map<string, User>();
const mappedCases: Array<{
owner: string;
id: string;
}> = [];

// Gather all necessary information in one pass
cases.saved_objects.forEach((theCase) => {
const user = theCase.attributes.created_by;
if (user.username != null) {
reporters.set(user.username, user);
}

mappedCases.push({
id: theCase.id,
owner: theCase.attributes.owner,
});
});

ensureSavedObjectsAreAuthorized(mappedCases);

return UsersRt.encode([...reporters.values()]);
return reporters;
} catch (error) {
throw createCaseError({ message: `Failed to get reporters: ${error}`, error, logger });
}
Expand Down
77 changes: 65 additions & 12 deletions x-pack/plugins/cases/server/services/cases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
SUB_CASE_SAVED_OBJECT,
} from '../../../common/constants';
import {
OWNER_FIELD,
GetCaseIdsByAlertIdAggs,
AssociationType,
CaseResponse,
Expand Down Expand Up @@ -1021,37 +1020,91 @@ export class CasesService {
public async getReporters({
unsecuredSavedObjectsClient,
filter,
}: GetReportersArgs): Promise<SavedObjectsFindResponse<ESCaseAttributes>> {
}: GetReportersArgs): Promise<User[]> {
try {
this.log.debug(`Attempting to GET all reporters`);

return await unsecuredSavedObjectsClient.find<ESCaseAttributes>({
const results = await unsecuredSavedObjectsClient.find<
ESCaseAttributes,
{
reporters: {
buckets: Array<{
key: string;
top_docs: { hits: { hits: Array<{ _source: { cases: { created_by: User } } }> } };
}>;
};
}
>({
type: CASE_SAVED_OBJECT,
fields: ['created_by', OWNER_FIELD],
page: 1,
perPage: MAX_DOCS_PER_PAGE,
perPage: 1,
filter,
aggs: {
reporters: {
terms: {
field: `${CASE_SAVED_OBJECT}.attributes.created_by.username`,
size: MAX_DOCS_PER_PAGE,
order: { _key: 'asc' },
},
aggs: {
top_docs: {
top_hits: {
sort: [
{
[`${CASE_SAVED_OBJECT}.created_at`]: {
order: 'desc',
},
},
],
size: 1,
_source: [`${CASE_SAVED_OBJECT}.created_by`],
},
},
},
},
},
});

return (
results?.aggregations?.reporters?.buckets.map(({ key: username, top_docs: topDocs }) => {
const user = topDocs?.hits?.hits?.[0]?._source?.cases?.created_by ?? {};
return {
username,
full_name: user.full_name ?? null,
email: user.email ?? null,
};
}) ?? []
);
} catch (error) {
this.log.error(`Error on GET all reporters: ${error}`);
throw error;
}
}

public async getTags({
unsecuredSavedObjectsClient,
filter,
}: GetTagsArgs): Promise<SavedObjectsFindResponse<ESCaseAttributes>> {
public async getTags({ unsecuredSavedObjectsClient, filter }: GetTagsArgs): Promise<string[]> {
try {
this.log.debug(`Attempting to GET all cases`);

return await unsecuredSavedObjectsClient.find<ESCaseAttributes>({
const results = await unsecuredSavedObjectsClient.find<
ESCaseAttributes,
{ tags: { buckets: Array<{ key: string }> } }
>({
type: CASE_SAVED_OBJECT,
fields: ['tags', OWNER_FIELD],
page: 1,
perPage: MAX_DOCS_PER_PAGE,
perPage: 1,
filter,
aggs: {
tags: {
terms: {
field: `${CASE_SAVED_OBJECT}.attributes.tags`,
size: MAX_DOCS_PER_PAGE,
order: { _key: 'asc' },
},
},
},
});

return results?.aggregations?.tags?.buckets.map(({ key }) => key) ?? [];
} catch (error) {
this.log.error(`Error on GET tags: ${error}`);
throw error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,17 @@ export default ({ getService }: FtrProviderContext): void => {
for (const scenario of [
{
user: globalRead,
expectedReporters: [getUserInfo(secOnly), getUserInfo(obsOnly)],
expectedReporters: [getUserInfo(obsOnly), getUserInfo(secOnly)],
},
{
user: superUser,
expectedReporters: [getUserInfo(secOnly), getUserInfo(obsOnly)],
expectedReporters: [getUserInfo(obsOnly), getUserInfo(secOnly)],
},
{ user: secOnlyRead, expectedReporters: [getUserInfo(secOnly)] },
{ user: obsOnlyRead, expectedReporters: [getUserInfo(obsOnly)] },
{
user: obsSecRead,
expectedReporters: [getUserInfo(secOnly), getUserInfo(obsOnly)],
expectedReporters: [getUserInfo(obsOnly), getUserInfo(secOnly)],
},
]) {
const reporters = await getReporters({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,17 +74,17 @@ export default ({ getService }: FtrProviderContext): void => {
for (const scenario of [
{
user: globalRead,
expectedTags: ['sec', 'obs'],
expectedTags: ['obs', 'sec'],
},
{
user: superUser,
expectedTags: ['sec', 'obs'],
expectedTags: ['obs', 'sec'],
},
{ user: secOnlyRead, expectedTags: ['sec'] },
{ user: obsOnlyRead, expectedTags: ['obs'] },
{
user: obsSecRead,
expectedTags: ['sec', 'obs'],
expectedTags: ['obs', 'sec'],
},
]) {
const tags = await getTags({
Expand Down

0 comments on commit 08f87f0

Please sign in to comment.