mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Cases] Version cases
and comment
domain and apis (#161954)
## Summary This PR versions the `cases` and `comment` domain objects and their corresponding APIs. It was not possible to do them separately as I got errors due to circular dependencies. ## Notable Changes - The `Comment` type was renamed to `Attachment` - The `Comments` type was renamed to `Attachments` - The `*CommentRequestRt` type was renamed to `*AttachmentPayload` - The `CommentType` type was renamed to `AttachmentType` - The `AttributesType*` type was renamed to `*AttachmentAttributes` - The `*ResponseTypeUserRt` type was renamed to `*AttachmentRt` - The word `comment` got replaced with the word `attachment` in all types - The `RelatedCaseInfo` type was renamed to `RelatedCase` - The `CasesByAlertId` type was renamed to `GetRelatedCasesByAlertResponse` Depends on: https://github.com/elastic/kibana/pull/161783, https://github.com/elastic/kibana/pull/162059 ### Checklist Delete any items that do not apply to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
da5554f77b
commit
2221ff8b55
388 changed files with 4913 additions and 4494 deletions
|
@ -6,6 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is being used by Cases in
|
||||
* x-pack/plugins/cases/common/types/domain/case/v1.ts.
|
||||
* Introducing a breaking change in this enum will
|
||||
* force cases to create a version of the domain object
|
||||
* which in turn will force cases to create a new version
|
||||
* to most of the Cases APIs.
|
||||
*/
|
||||
export enum CaseStatuses {
|
||||
open = 'open',
|
||||
'in-progress' = 'in-progress',
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* 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 { CaseAssigneesRt } from './assignee';
|
||||
|
||||
describe('Assignee', () => {
|
||||
describe('CaseAssigneesRt', () => {
|
||||
const defaultRequest = [{ uid: '1' }, { uid: '2' }];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseAssigneesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseAssigneesRt.decode([{ ...defaultRequest[0], foo: 'bar' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [defaultRequest[0]],
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from assignees', () => {
|
||||
const query = CaseAssigneesRt.decode([{ uid: '1', foo: 'bar' }, { uid: '2' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [{ uid: '1' }, { uid: '2' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,765 +0,0 @@
|
|||
/*
|
||||
* 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 { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { ConnectorTypes } from '../../types/domain/connector/v1';
|
||||
import {
|
||||
RelatedCaseInfoRt,
|
||||
SettingsRt,
|
||||
CaseSeverity,
|
||||
CaseFullExternalServiceRt,
|
||||
CasesFindRequestRt,
|
||||
CasesByAlertIDRequestRt,
|
||||
CasePatchRequestRt,
|
||||
CasesPatchRequestRt,
|
||||
CasePushRequestParamsRt,
|
||||
ExternalServiceResponseRt,
|
||||
AllReportersFindRequestRt,
|
||||
CasesBulkGetRequestRt,
|
||||
CasesBulkGetResponseRt,
|
||||
CasePostRequestRt,
|
||||
CaseAttributesRt,
|
||||
CasesRt,
|
||||
CasesFindResponseRt,
|
||||
CaseResolveResponseRt,
|
||||
CasesFindRequestSearchFieldsRt,
|
||||
CasesFindRequestSortFieldsRt,
|
||||
} from './case';
|
||||
import { CommentType } from './comment';
|
||||
import { CaseStatuses } from './status';
|
||||
|
||||
const basicCase = {
|
||||
owner: 'cases',
|
||||
closed_at: null,
|
||||
closed_by: null,
|
||||
id: 'basic-case-id',
|
||||
comments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
id: 'basic-comment-id',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
owner: 'cases',
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
version: 'WzQ3LDFc',
|
||||
},
|
||||
],
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
connector: {
|
||||
id: 'none',
|
||||
name: 'My Connector',
|
||||
type: ConnectorTypes.none,
|
||||
fields: null,
|
||||
},
|
||||
description: 'Security banana Issue',
|
||||
severity: CaseSeverity.LOW,
|
||||
duration: null,
|
||||
external_service: null,
|
||||
status: CaseStatuses.open,
|
||||
tags: ['coke', 'pepsi'],
|
||||
title: 'Another horrible breach!!',
|
||||
totalComment: 1,
|
||||
totalAlerts: 0,
|
||||
updated_at: '2020-02-20T15:02:57.995Z',
|
||||
updated_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
version: 'WzQ3LDFd',
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
// damaged_raccoon uid
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
category: null,
|
||||
};
|
||||
|
||||
describe('Case', () => {
|
||||
describe('RelatedCaseInfoRt', () => {
|
||||
const defaultRequest = {
|
||||
id: 'basic-case-id',
|
||||
title: 'basic-case-title',
|
||||
description: 'this is a simple description',
|
||||
status: CaseStatuses.open,
|
||||
createdAt: '2023-01-17T09:46:29.813Z',
|
||||
totals: {
|
||||
alerts: 5,
|
||||
userComments: 2,
|
||||
},
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = RelatedCaseInfoRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = RelatedCaseInfoRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from totals', () => {
|
||||
const query = RelatedCaseInfoRt.decode({
|
||||
...defaultRequest,
|
||||
totals: { ...defaultRequest.totals, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SettingsRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = SettingsRt.decode({ syncAlerts: true });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { syncAlerts: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = SettingsRt.decode({ syncAlerts: false, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { syncAlerts: false },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseFullExternalServiceRt', () => {
|
||||
const defaultRequest = {
|
||||
connector_id: 'servicenow-1',
|
||||
connector_name: 'My SN connector',
|
||||
external_id: 'external_id',
|
||||
external_title: 'external title',
|
||||
external_url: 'basicPush.com',
|
||||
pushed_at: '2023-01-17T09:46:29.813Z',
|
||||
pushed_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseFullExternalServiceRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseFullExternalServiceRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from pushed_by', () => {
|
||||
const query = CaseFullExternalServiceRt.decode({
|
||||
...defaultRequest,
|
||||
pushed_by: { ...defaultRequest.pushed_by, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseAttributesRt', () => {
|
||||
const defaultRequest = {
|
||||
description: 'A description',
|
||||
status: CaseStatuses.open,
|
||||
tags: ['new', 'case'],
|
||||
title: 'My new case',
|
||||
connector: {
|
||||
id: '123',
|
||||
name: 'My connector',
|
||||
type: ConnectorTypes.jira,
|
||||
fields: { issueType: 'Task', priority: 'High', parent: null },
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
owner: 'cases',
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
duration: null,
|
||||
closed_at: null,
|
||||
closed_by: null,
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
external_service: null,
|
||||
updated_at: '2020-02-20T15:02:57.995Z',
|
||||
updated_by: null,
|
||||
category: null,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseAttributesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseAttributesRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from connector', () => {
|
||||
const query = CaseAttributesRt.decode({
|
||||
...defaultRequest,
|
||||
connector: { ...defaultRequest.connector, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from created_by', () => {
|
||||
const query = CaseAttributesRt.decode({
|
||||
...defaultRequest,
|
||||
created_by: { ...defaultRequest.created_by, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePostRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
description: 'A description',
|
||||
tags: ['new', 'case'],
|
||||
title: 'My new case',
|
||||
connector: {
|
||||
id: '123',
|
||||
name: 'My connector',
|
||||
type: ConnectorTypes.jira,
|
||||
fields: { issueType: 'Task', priority: 'High', parent: null },
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
owner: 'cases',
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePostRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePostRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from connector', () => {
|
||||
const query = CasePostRequestRt.decode({
|
||||
...defaultRequest,
|
||||
connector: { ...defaultRequest.connector, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesFindRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
tags: ['new', 'case'],
|
||||
status: CaseStatuses.open,
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: ['damaged_racoon'],
|
||||
reporters: ['damaged_racoon'],
|
||||
defaultSearchOperator: 'AND',
|
||||
from: 'now',
|
||||
page: '1',
|
||||
perPage: '10',
|
||||
search: 'search text',
|
||||
searchFields: ['title', 'description'],
|
||||
to: '1w',
|
||||
sortOrder: 'desc',
|
||||
sortField: 'createdAt',
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesFindRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
const searchFields = Object.keys(CasesFindRequestSearchFieldsRt.keys);
|
||||
|
||||
it.each(searchFields)('succeeds with %s as searchFields', (field) => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, searchFields: field });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, searchFields: field, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
const sortFields = Object.keys(CasesFindRequestSortFieldsRt.keys);
|
||||
|
||||
it.each(sortFields)('succeeds with %s as sortField', (sortField) => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, sortField });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, sortField, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes rootSearchField when passed', () => {
|
||||
expect(
|
||||
PathReporter.report(
|
||||
CasesFindRequestRt.decode({ ...defaultRequest, rootSearchField: ['foobar'] })
|
||||
)
|
||||
).toContain('No errors!');
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it('throws error when invalid searchField passed', () => {
|
||||
expect(
|
||||
PathReporter.report(
|
||||
CasesFindRequestRt.decode({ ...defaultRequest, searchFields: 'foobar' })
|
||||
)
|
||||
).not.toContain('No errors!');
|
||||
});
|
||||
|
||||
it('throws error when invalid sortField passed', () => {
|
||||
expect(
|
||||
PathReporter.report(CasesFindRequestRt.decode({ ...defaultRequest, sortField: 'foobar' }))
|
||||
).not.toContain('No errors!');
|
||||
});
|
||||
|
||||
it('succeeds when valid parameters passed', () => {
|
||||
expect(PathReporter.report(CasesFindRequestRt.decode(defaultRequest))).toContain(
|
||||
'No errors!'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesByAlertIDRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesByAlertIDRequestRt.decode({ owner: 'cases' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { owner: 'cases' },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesByAlertIDRequestRt.decode({ owner: ['cases'], foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { owner: ['cases'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseResolveResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
case: { ...basicCase },
|
||||
outcome: 'exactMatch',
|
||||
alias_target_id: 'sample-target-id',
|
||||
alias_purpose: 'savedObjectConversion',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseResolveResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseResolveResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesFindResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [{ ...basicCase }],
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 20,
|
||||
count_open_cases: 10,
|
||||
count_in_progress_cases: 5,
|
||||
count_closed_cases: 5,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesFindResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesFindResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from cases', () => {
|
||||
const query = CasesFindResponseRt.decode({
|
||||
...defaultRequest,
|
||||
cases: [{ ...basicCase, foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
id: 'basic-case-id',
|
||||
version: 'WzQ3LDFd',
|
||||
description: 'Updated description',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesPatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [
|
||||
{
|
||||
id: 'basic-case-id',
|
||||
version: 'WzQ3LDFd',
|
||||
description: 'Updated description',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesPatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesPatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
...basicCase,
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesRt.decode([{ ...defaultRequest[0], foo: 'bar' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePushRequestParamsRt', () => {
|
||||
const defaultRequest = {
|
||||
case_id: 'basic-case-id',
|
||||
connector_id: 'basic-connector-id',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePushRequestParamsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePushRequestParamsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ExternalServiceResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
title: 'case_title',
|
||||
id: 'basic-case-id',
|
||||
pushedDate: '2020-02-19T23:06:33.798Z',
|
||||
url: 'https://atlassian.com',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'basic-comment-id',
|
||||
pushedDate: '2020-02-19T23:06:33.798Z',
|
||||
externalCommentId: 'external-comment-id',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalServiceResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalServiceResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from comments', () => {
|
||||
const query = ExternalServiceResponseRt.decode({
|
||||
...defaultRequest,
|
||||
comments: [{ ...defaultRequest.comments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AllReportersFindRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
owner: ['cases', 'security-solution'],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AllReportersFindRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AllReportersFindRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesBulkGetRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
ids: ['case-1', 'case-2'],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesBulkGetRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesBulkGetRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesBulkGetResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [basicCase],
|
||||
errors: [
|
||||
{
|
||||
error: 'error',
|
||||
message: 'error-message',
|
||||
status: 403,
|
||||
caseId: 'basic-case-id',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesBulkGetResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from cases', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({
|
||||
...defaultRequest,
|
||||
cases: [{ ...defaultRequest.cases[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, cases: defaultRequest.cases },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from errors', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({
|
||||
...defaultRequest,
|
||||
errors: [{ ...defaultRequest.errors[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* 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 {
|
||||
SingleFileAttachmentMetadataRt,
|
||||
FileAttachmentMetadataRt,
|
||||
BulkDeleteFileAttachmentsRequestRt,
|
||||
} from './files';
|
||||
|
||||
describe('Files', () => {
|
||||
describe('SingleFileAttachmentMetadataRt', () => {
|
||||
const defaultRequest = {
|
||||
created: '2020-02-19T23:06:33.798Z',
|
||||
extension: 'png',
|
||||
mimeType: 'image/png',
|
||||
name: 'my-super-cool-screenshot',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = SingleFileAttachmentMetadataRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = SingleFileAttachmentMetadataRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('FileAttachmentMetadataRt', () => {
|
||||
const defaultRequest = {
|
||||
created: '2020-02-19T23:06:33.798Z',
|
||||
extension: 'png',
|
||||
mimeType: 'image/png',
|
||||
name: 'my-super-cool-screenshot',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = FileAttachmentMetadataRt.decode({ files: [defaultRequest] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
files: [
|
||||
{
|
||||
...defaultRequest,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = FileAttachmentMetadataRt.decode({ files: [{ ...defaultRequest, foo: 'bar' }] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
files: [
|
||||
{
|
||||
...defaultRequest,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('BulkDeleteFileAttachmentsRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkDeleteFileAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkDeleteFileAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'], foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import { MAX_DELETE_FILES } from '../../../constants';
|
||||
import { limitedArraySchema, NonEmptyString } from '../../../schema';
|
||||
|
||||
export const SingleFileAttachmentMetadataRt = rt.strict({
|
||||
name: rt.string,
|
||||
extension: rt.string,
|
||||
mimeType: rt.string,
|
||||
created: rt.string,
|
||||
});
|
||||
|
||||
export const FileAttachmentMetadataRt = rt.strict({
|
||||
files: rt.array(SingleFileAttachmentMetadataRt),
|
||||
});
|
||||
|
||||
export type FileAttachmentMetadata = rt.TypeOf<typeof FileAttachmentMetadataRt>;
|
||||
|
||||
const MIN_DELETE_IDS = 1;
|
||||
|
||||
export const BulkDeleteFileAttachmentsRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({
|
||||
codec: NonEmptyString,
|
||||
min: MIN_DELETE_IDS,
|
||||
max: MAX_DELETE_FILES,
|
||||
fieldName: 'ids',
|
||||
}),
|
||||
});
|
||||
|
||||
export type BulkDeleteFileAttachmentsRequest = rt.TypeOf<typeof BulkDeleteFileAttachmentsRequestRt>;
|
|
@ -1,962 +0,0 @@
|
|||
/*
|
||||
* 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 { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
|
||||
import {
|
||||
CommentAttributesBasicRt,
|
||||
CommentType,
|
||||
ContextTypeUserRt,
|
||||
AlertCommentRequestRt,
|
||||
ActionsCommentRequestRt,
|
||||
ExternalReferenceStorageType,
|
||||
ExternalReferenceRt,
|
||||
PersistableStateAttachmentRt,
|
||||
CommentRequestRt,
|
||||
CommentRt,
|
||||
CommentResponseTypeUserRt,
|
||||
CommentResponseTypeAlertsRt,
|
||||
CommentResponseTypeActionsRt,
|
||||
CommentResponseTypeExternalReferenceRt,
|
||||
CommentResponseTypePersistableStateRt,
|
||||
CommentPatchRequestRt,
|
||||
CommentPatchAttributesRt,
|
||||
CommentsFindResponseRt,
|
||||
FindCommentsQueryParamsRt,
|
||||
BulkCreateCommentRequestRt,
|
||||
BulkGetAttachmentsRequestRt,
|
||||
BulkGetAttachmentsResponseRt,
|
||||
} from '.';
|
||||
import { MAX_COMMENT_LENGTH, MAX_BULK_CREATE_ATTACHMENTS } from '../../../constants';
|
||||
|
||||
describe('Comments', () => {
|
||||
describe('CommentAttributesBasicRt', () => {
|
||||
const defaultRequest = {
|
||||
created_at: '2019-11-25T22:32:30.608Z',
|
||||
created_by: {
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
},
|
||||
owner: 'cases',
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentAttributesBasicRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentAttributesBasicRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ContextTypeUserRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'This is a sample comment',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ContextTypeUserRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ContextTypeUserRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AlertCommentRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: CommentType.alert,
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AlertCommentRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AlertCommentRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from rule', () => {
|
||||
const query = AlertCommentRequestRt.decode({
|
||||
...defaultRequest,
|
||||
rule: { id: 'rule-id-1', name: 'Awesome rule', foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ActionsCommentRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.actions,
|
||||
comment: 'I just isolated the host!',
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ActionsCommentRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ActionsCommentRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from actions', () => {
|
||||
const query = ActionsCommentRequestRt.decode({
|
||||
...defaultRequest,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from targets', () => {
|
||||
const query = ActionsCommentRequestRt.decode({
|
||||
...defaultRequest,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
foo: 'bar',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ExternalReferenceRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: { test_foo: 'foo' },
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalReferenceRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalReferenceRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from externalReferenceStorage', () => {
|
||||
const query = ExternalReferenceRt.decode({
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.elasticSearchDoc,
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from externalReferenceStorage with soType', () => {
|
||||
const query = ExternalReferenceRt.decode({
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.savedObject,
|
||||
soType: 'awesome',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.savedObject,
|
||||
soType: 'awesome',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PersistableStateAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.persistableState,
|
||||
persistableStateAttachmentState: { test_foo: 'foo' },
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = PersistableStateAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = PersistableStateAttachmentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from persistableStateAttachmentState', () => {
|
||||
const query = PersistableStateAttachmentRt.decode({
|
||||
...defaultRequest,
|
||||
persistableStateAttachmentState: { test_foo: 'foo', foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
...defaultRequest,
|
||||
persistableStateAttachmentState: { test_foo: 'foo', foo: 'bar' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
describe('commentType: user', () => {
|
||||
it('throws error when comment is too long', () => {
|
||||
const longComment = 'x'.repeat(MAX_COMMENT_LENGTH + 1);
|
||||
|
||||
expect(
|
||||
PathReporter.report(
|
||||
CommentRequestRt.decode({ ...defaultRequest, comment: longComment })
|
||||
)
|
||||
).toContain('The length of the comment is too long. The maximum length is 30000.');
|
||||
});
|
||||
|
||||
it('throws error when comment is empty', () => {
|
||||
expect(
|
||||
PathReporter.report(CommentRequestRt.decode({ ...defaultRequest, comment: '' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
|
||||
it('throws error when comment string of empty characters', () => {
|
||||
expect(
|
||||
PathReporter.report(CommentRequestRt.decode({ ...defaultRequest, comment: ' ' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('commentType: action', () => {
|
||||
const request = {
|
||||
type: CommentType.actions,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('throws error when comment is too long', () => {
|
||||
const longComment = 'x'.repeat(MAX_COMMENT_LENGTH + 1);
|
||||
|
||||
expect(
|
||||
PathReporter.report(CommentRequestRt.decode({ ...request, comment: longComment }))
|
||||
).toContain('The length of the comment is too long. The maximum length is 30000.');
|
||||
});
|
||||
|
||||
it('throws error when comment is empty', () => {
|
||||
expect(
|
||||
PathReporter.report(CommentRequestRt.decode({ ...request, comment: '' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
|
||||
it('throws error when comment string of empty characters', () => {
|
||||
expect(
|
||||
PathReporter.report(CommentRequestRt.decode({ ...request, comment: ' ' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentResponseTypeUserRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentResponseTypeUserRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentResponseTypeUserRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentResponseTypeAlertsRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: CommentType.alert,
|
||||
id: 'alert-comment-id',
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentResponseTypeAlertsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentResponseTypeAlertsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from created_by', () => {
|
||||
const query = CommentResponseTypeAlertsRt.decode({
|
||||
...defaultRequest,
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentResponseTypeActionsRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.actions,
|
||||
comment: 'I just isolated the host!',
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentResponseTypeActionsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentResponseTypeActionsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentResponseTypeExternalReferenceRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: { test_foo: 'foo' },
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentResponseTypeExternalReferenceRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentResponseTypeExternalReferenceRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentResponseTypePersistableStateRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.persistableState,
|
||||
persistableStateAttachmentState: { test_foo: 'foo' },
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentResponseTypePersistableStateRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentResponseTypePersistableStateRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentPatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: CommentType.alert,
|
||||
id: 'alert-comment-id',
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
version: 'WzQ3LDFc',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentPatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentPatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentPatchAttributesRt', () => {
|
||||
const defaultRequest = {
|
||||
type: CommentType.actions,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentPatchAttributesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentPatchAttributesRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CommentsFindResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
comments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
},
|
||||
],
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 1,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CommentsFindResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CommentsFindResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from comments', () => {
|
||||
const query = CommentsFindResponseRt.decode({
|
||||
...defaultRequest,
|
||||
comments: [{ ...defaultRequest.comments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('FindCommentsQueryParamsRt', () => {
|
||||
const defaultRequest = {
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
sortOrder: 'asc',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = FindCommentsQueryParamsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = FindCommentsQueryParamsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkCreateCommentRequestRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkCreateCommentRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkCreateCommentRequestRt.decode([
|
||||
{ comment: 'Solve this fast!', type: CommentType.user, owner: 'cases', foo: 'bar' },
|
||||
]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it(`throws error when attachments are more than ${MAX_BULK_CREATE_ATTACHMENTS}`, () => {
|
||||
const comment = {
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
const attachments = Array(MAX_BULK_CREATE_ATTACHMENTS + 1).fill(comment);
|
||||
|
||||
expect(PathReporter.report(BulkCreateCommentRequestRt.decode(attachments))).toContain(
|
||||
`The length of the field attachments is too long. Array must be of length <= ${MAX_BULK_CREATE_ATTACHMENTS}.`
|
||||
);
|
||||
});
|
||||
|
||||
it(`no errors when empty array of attachments`, () => {
|
||||
expect(PathReporter.report(BulkCreateCommentRequestRt.decode([]))).toStrictEqual([
|
||||
'No errors!',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkGetAttachmentsRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkGetAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkGetAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'], foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkGetAttachmentsResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
attachments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: CommentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
],
|
||||
errors: [
|
||||
{
|
||||
error: 'error',
|
||||
message: 'not found',
|
||||
status: 404,
|
||||
attachmentId: 'abc',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from attachments', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({
|
||||
...defaultRequest,
|
||||
attachments: [{ ...defaultRequest.attachments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from errors', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({
|
||||
...defaultRequest,
|
||||
errors: [{ ...defaultRequest.errors[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,400 +0,0 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import {
|
||||
MAX_BULK_GET_ATTACHMENTS,
|
||||
MAX_COMMENTS_PER_PAGE,
|
||||
MAX_COMMENT_LENGTH,
|
||||
MAX_BULK_CREATE_ATTACHMENTS,
|
||||
} from '../../../constants';
|
||||
import { limitedArraySchema, paginationSchema, limitedStringSchema } from '../../../schema';
|
||||
import { jsonValueRt } from '../../runtime_types';
|
||||
|
||||
import { UserRt } from '../../user';
|
||||
|
||||
export * from './files';
|
||||
|
||||
export const CommentAttributesBasicRt = rt.strict({
|
||||
created_at: rt.string,
|
||||
created_by: UserRt,
|
||||
owner: rt.string,
|
||||
pushed_at: rt.union([rt.string, rt.null]),
|
||||
pushed_by: rt.union([UserRt, rt.null]),
|
||||
updated_at: rt.union([rt.string, rt.null]),
|
||||
updated_by: rt.union([UserRt, rt.null]),
|
||||
});
|
||||
|
||||
export enum CommentType {
|
||||
user = 'user',
|
||||
alert = 'alert',
|
||||
actions = 'actions',
|
||||
externalReference = 'externalReference',
|
||||
persistableState = 'persistableState',
|
||||
}
|
||||
|
||||
export enum IsolateHostActionType {
|
||||
isolate = 'isolate',
|
||||
unisolate = 'unisolate',
|
||||
}
|
||||
|
||||
export const ContextTypeUserRt = rt.strict({
|
||||
comment: rt.string,
|
||||
type: rt.literal(CommentType.user),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
/**
|
||||
* This defines the structure of how alerts (generated or user attached) are stored in saved objects documents. It also
|
||||
* represents of an alert after it has been transformed. A generated alert will be transformed by the connector so that
|
||||
* it matches this structure. User attached alerts do not need to be transformed.
|
||||
*/
|
||||
export const AlertCommentRequestRt = rt.strict({
|
||||
type: rt.literal(CommentType.alert),
|
||||
alertId: rt.union([rt.array(rt.string), rt.string]),
|
||||
index: rt.union([rt.array(rt.string), rt.string]),
|
||||
rule: rt.strict({
|
||||
id: rt.union([rt.string, rt.null]),
|
||||
name: rt.union([rt.string, rt.null]),
|
||||
}),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
export const ActionsCommentRequestRt = rt.strict({
|
||||
type: rt.literal(CommentType.actions),
|
||||
comment: rt.string,
|
||||
actions: rt.strict({
|
||||
targets: rt.array(
|
||||
rt.strict({
|
||||
hostname: rt.string,
|
||||
endpointId: rt.string,
|
||||
})
|
||||
),
|
||||
type: rt.string,
|
||||
}),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
export enum ExternalReferenceStorageType {
|
||||
savedObject = 'savedObject',
|
||||
elasticSearchDoc = 'elasticSearchDoc',
|
||||
}
|
||||
|
||||
const ExternalReferenceStorageNoSORt = rt.strict({
|
||||
type: rt.literal(ExternalReferenceStorageType.elasticSearchDoc),
|
||||
});
|
||||
|
||||
const ExternalReferenceStorageSORt = rt.strict({
|
||||
type: rt.literal(ExternalReferenceStorageType.savedObject),
|
||||
soType: rt.string,
|
||||
});
|
||||
|
||||
export const ExternalReferenceBaseRt = rt.strict({
|
||||
externalReferenceAttachmentTypeId: rt.string,
|
||||
externalReferenceMetadata: rt.union([rt.null, rt.record(rt.string, jsonValueRt)]),
|
||||
type: rt.literal(CommentType.externalReference),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
export const ExternalReferenceNoSORt = rt.strict({
|
||||
...ExternalReferenceBaseRt.type.props,
|
||||
externalReferenceId: rt.string,
|
||||
externalReferenceStorage: ExternalReferenceStorageNoSORt,
|
||||
});
|
||||
|
||||
export const ExternalReferenceSORt = rt.strict({
|
||||
...ExternalReferenceBaseRt.type.props,
|
||||
externalReferenceId: rt.string,
|
||||
externalReferenceStorage: ExternalReferenceStorageSORt,
|
||||
});
|
||||
|
||||
// externalReferenceId is missing.
|
||||
export const ExternalReferenceSOWithoutRefsRt = rt.strict({
|
||||
...ExternalReferenceBaseRt.type.props,
|
||||
externalReferenceStorage: ExternalReferenceStorageSORt,
|
||||
});
|
||||
|
||||
export const ExternalReferenceRt = rt.union([ExternalReferenceNoSORt, ExternalReferenceSORt]);
|
||||
export const ExternalReferenceWithoutRefsRt = rt.union([
|
||||
ExternalReferenceNoSORt,
|
||||
ExternalReferenceSOWithoutRefsRt,
|
||||
]);
|
||||
|
||||
export const PersistableStateAttachmentRt = rt.strict({
|
||||
type: rt.literal(CommentType.persistableState),
|
||||
owner: rt.string,
|
||||
persistableStateAttachmentTypeId: rt.string,
|
||||
persistableStateAttachmentState: rt.record(rt.string, jsonValueRt),
|
||||
});
|
||||
|
||||
const AttributesTypeUserRt = rt.intersection([ContextTypeUserRt, CommentAttributesBasicRt]);
|
||||
export const AttributesTypeAlertsRt = rt.intersection([
|
||||
AlertCommentRequestRt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
const AttributesTypeActionsRt = rt.intersection([
|
||||
ActionsCommentRequestRt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const AttributesTypeExternalReferenceRt = rt.intersection([
|
||||
ExternalReferenceRt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const AttributesTypeExternalReferenceWithoutRefsRt = rt.intersection([
|
||||
ExternalReferenceWithoutRefsRt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const AttributesTypeExternalReferenceNoSORt = rt.intersection([
|
||||
ExternalReferenceNoSORt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const AttributesTypeExternalReferenceSORt = rt.intersection([
|
||||
ExternalReferenceSORt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const AttributesTypePersistableStateRt = rt.intersection([
|
||||
PersistableStateAttachmentRt,
|
||||
CommentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const CommentAttributesRt = rt.union([
|
||||
AttributesTypeUserRt,
|
||||
AttributesTypeAlertsRt,
|
||||
AttributesTypeActionsRt,
|
||||
AttributesTypeExternalReferenceRt,
|
||||
AttributesTypePersistableStateRt,
|
||||
]);
|
||||
|
||||
const CommentAttributesNoSORt = rt.union([
|
||||
AttributesTypeUserRt,
|
||||
AttributesTypeAlertsRt,
|
||||
AttributesTypeActionsRt,
|
||||
AttributesTypeExternalReferenceNoSORt,
|
||||
AttributesTypePersistableStateRt,
|
||||
]);
|
||||
|
||||
const CommentAttributesWithoutRefsRt = rt.union([
|
||||
AttributesTypeUserRt,
|
||||
AttributesTypeAlertsRt,
|
||||
AttributesTypeActionsRt,
|
||||
AttributesTypeExternalReferenceWithoutRefsRt,
|
||||
AttributesTypePersistableStateRt,
|
||||
]);
|
||||
|
||||
const BasicCommentRequestRt = rt.union([
|
||||
ContextTypeUserRt,
|
||||
AlertCommentRequestRt,
|
||||
ActionsCommentRequestRt,
|
||||
ExternalReferenceNoSORt,
|
||||
PersistableStateAttachmentRt,
|
||||
]);
|
||||
|
||||
export const CommentRequestRt = rt.union([
|
||||
rt.strict({
|
||||
comment: limitedStringSchema({ fieldName: 'comment', min: 1, max: MAX_COMMENT_LENGTH }),
|
||||
type: rt.literal(CommentType.user),
|
||||
owner: rt.string,
|
||||
}),
|
||||
AlertCommentRequestRt,
|
||||
rt.strict({
|
||||
type: rt.literal(CommentType.actions),
|
||||
comment: limitedStringSchema({ fieldName: 'comment', min: 1, max: MAX_COMMENT_LENGTH }),
|
||||
actions: rt.strict({
|
||||
targets: rt.array(
|
||||
rt.strict({
|
||||
hostname: rt.string,
|
||||
endpointId: rt.string,
|
||||
})
|
||||
),
|
||||
type: rt.string,
|
||||
}),
|
||||
owner: rt.string,
|
||||
}),
|
||||
ExternalReferenceNoSORt,
|
||||
ExternalReferenceSORt,
|
||||
PersistableStateAttachmentRt,
|
||||
]);
|
||||
|
||||
export const CommentRequestWithoutRefsRt = rt.union([
|
||||
BasicCommentRequestRt,
|
||||
ExternalReferenceSOWithoutRefsRt,
|
||||
]);
|
||||
|
||||
export const CommentRt = rt.intersection([
|
||||
CommentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentResponseTypeUserRt = rt.intersection([
|
||||
AttributesTypeUserRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentResponseTypeAlertsRt = rt.intersection([
|
||||
AttributesTypeAlertsRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentResponseTypeActionsRt = rt.intersection([
|
||||
AttributesTypeActionsRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentResponseTypeExternalReferenceRt = rt.intersection([
|
||||
AttributesTypeExternalReferenceRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentResponseTypePersistableStateRt = rt.intersection([
|
||||
AttributesTypePersistableStateRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CommentPatchRequestRt = rt.intersection([
|
||||
/**
|
||||
* Partial updates are not allowed.
|
||||
* We want to prevent the user for changing the type without removing invalid fields.
|
||||
*
|
||||
* injectAttachmentSOAttributesFromRefsForPatch is dependent on this assumption.
|
||||
* The consumers of the persistable attachment service should always get the
|
||||
* persistableStateAttachmentState on a patch.
|
||||
*/
|
||||
CommentRequestRt,
|
||||
rt.strict({ id: rt.string, version: rt.string }),
|
||||
]);
|
||||
|
||||
/**
|
||||
* This type is used by the CaseService.
|
||||
* Because the type for the attributes of savedObjectClient update function is Partial<T>
|
||||
* we need to make all of our attributes partial too.
|
||||
* We ensure that partial updates of CommentContext is not going to happen inside the patch comment route.
|
||||
*/
|
||||
export const CommentPatchAttributesRt = rt.intersection([
|
||||
rt.union([
|
||||
rt.exact(rt.partial(ContextTypeUserRt.type.props)),
|
||||
rt.exact(rt.partial(AlertCommentRequestRt.type.props)),
|
||||
rt.exact(rt.partial(ActionsCommentRequestRt.type.props)),
|
||||
rt.exact(rt.partial(ExternalReferenceNoSORt.type.props)),
|
||||
rt.exact(rt.partial(ExternalReferenceSORt.type.props)),
|
||||
rt.exact(rt.partial(PersistableStateAttachmentRt.type.props)),
|
||||
]),
|
||||
rt.exact(rt.partial(CommentAttributesBasicRt.type.props)),
|
||||
]);
|
||||
|
||||
export const CommentsFindResponseRt = rt.strict({
|
||||
comments: rt.array(CommentRt),
|
||||
page: rt.number,
|
||||
per_page: rt.number,
|
||||
total: rt.number,
|
||||
});
|
||||
|
||||
export const CommentsRt = rt.array(CommentRt);
|
||||
|
||||
export const FindCommentsQueryParamsRt = rt.intersection([
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
/**
|
||||
* Order to sort the response
|
||||
*/
|
||||
sortOrder: rt.union([rt.literal('desc'), rt.literal('asc')]),
|
||||
})
|
||||
),
|
||||
paginationSchema({ maxPerPage: MAX_COMMENTS_PER_PAGE }),
|
||||
]);
|
||||
|
||||
export const BulkCreateCommentRequestRt = limitedArraySchema({
|
||||
codec: CommentRequestRt,
|
||||
min: 0,
|
||||
max: MAX_BULK_CREATE_ATTACHMENTS,
|
||||
fieldName: 'attachments',
|
||||
});
|
||||
|
||||
export const BulkGetAttachmentsRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({
|
||||
codec: rt.string,
|
||||
min: 1,
|
||||
max: MAX_BULK_GET_ATTACHMENTS,
|
||||
fieldName: 'ids',
|
||||
}),
|
||||
});
|
||||
|
||||
export const BulkGetAttachmentsResponseRt = rt.strict({
|
||||
attachments: CommentsRt,
|
||||
errors: rt.array(
|
||||
rt.strict({
|
||||
error: rt.string,
|
||||
message: rt.string,
|
||||
status: rt.union([rt.undefined, rt.number]),
|
||||
attachmentId: rt.string,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export type FindCommentsQueryParams = rt.TypeOf<typeof FindCommentsQueryParamsRt>;
|
||||
export type AttributesTypeActions = rt.TypeOf<typeof AttributesTypeActionsRt>;
|
||||
export type AttributesTypeAlerts = rt.TypeOf<typeof AttributesTypeAlertsRt>;
|
||||
export type AttributesTypeUser = rt.TypeOf<typeof AttributesTypeUserRt>;
|
||||
export type AttributesTypeExternalReference = rt.TypeOf<typeof AttributesTypeExternalReferenceRt>;
|
||||
export type AttributesTypeExternalReferenceSO = rt.TypeOf<
|
||||
typeof AttributesTypeExternalReferenceSORt
|
||||
>;
|
||||
export type AttributesTypeExternalReferenceNoSO = rt.TypeOf<
|
||||
typeof AttributesTypeExternalReferenceNoSORt
|
||||
>;
|
||||
export type ExternalReferenceWithoutRefs = rt.TypeOf<typeof ExternalReferenceWithoutRefsRt>;
|
||||
export type AttributesTypePersistableState = rt.TypeOf<typeof AttributesTypePersistableStateRt>;
|
||||
export type CommentAttributes = rt.TypeOf<typeof CommentAttributesRt>;
|
||||
export type CommentAttributesNoSO = rt.TypeOf<typeof CommentAttributesNoSORt>;
|
||||
export type CommentAttributesWithoutRefs = rt.TypeOf<typeof CommentAttributesWithoutRefsRt>;
|
||||
export type CommentRequest = rt.TypeOf<typeof CommentRequestRt>;
|
||||
export type BulkCreateCommentRequest = rt.TypeOf<typeof BulkCreateCommentRequestRt>;
|
||||
export type Comment = rt.TypeOf<typeof CommentRt>;
|
||||
export type CommentResponseUserType = rt.TypeOf<typeof CommentResponseTypeUserRt>;
|
||||
export type CommentResponseAlertsType = rt.TypeOf<typeof CommentResponseTypeAlertsRt>;
|
||||
export type CommentResponseTypePersistableState = rt.TypeOf<
|
||||
typeof CommentResponseTypePersistableStateRt
|
||||
>;
|
||||
export type CommentResponseExternalReferenceType = rt.TypeOf<
|
||||
typeof CommentResponseTypeExternalReferenceRt
|
||||
>;
|
||||
export type CommentResponseActionsType = rt.TypeOf<typeof CommentResponseTypeActionsRt>;
|
||||
export type Comments = rt.TypeOf<typeof CommentsRt>;
|
||||
export type CommentsFindResponse = rt.TypeOf<typeof CommentsFindResponseRt>;
|
||||
export type CommentPatchRequest = rt.TypeOf<typeof CommentPatchRequestRt>;
|
||||
export type CommentPatchAttributes = rt.TypeOf<typeof CommentPatchAttributesRt>;
|
||||
export type CommentRequestUserType = rt.TypeOf<typeof ContextTypeUserRt>;
|
||||
export type CommentRequestAlertType = rt.TypeOf<typeof AlertCommentRequestRt>;
|
||||
export type CommentRequestActionsType = rt.TypeOf<typeof ActionsCommentRequestRt>;
|
||||
export type CommentRequestExternalReferenceType = rt.TypeOf<typeof ExternalReferenceRt>;
|
||||
export type CommentRequestExternalReferenceSOType = rt.TypeOf<typeof ExternalReferenceSORt>;
|
||||
export type CommentRequestExternalReferenceNoSOType = rt.TypeOf<typeof ExternalReferenceNoSORt>;
|
||||
export type CommentRequestPersistableStateType = rt.TypeOf<typeof PersistableStateAttachmentRt>;
|
||||
export type BulkGetAttachmentsResponse = rt.TypeOf<typeof BulkGetAttachmentsResponseRt>;
|
||||
export type BulkGetAttachmentsRequest = rt.TypeOf<typeof BulkGetAttachmentsRequestRt>;
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This field is used for authorization of the entities within the cases plugin. Each entity within Cases will have the owner field
|
||||
* set to a string that represents the plugin that "owns" (i.e. the plugin that originally issued the POST request to
|
||||
* create the entity) the entity.
|
||||
*
|
||||
* The Authorization class constructs a string composed of the operation being performed (createCase, getComment, etc),
|
||||
* and the owner of the entity being acted upon or created. This string is then given to the Security plugin which
|
||||
* checks to see if the user making the request has that particular string stored within it's privileges. If it does,
|
||||
* then the operation succeeds, otherwise the operation fails.
|
||||
*
|
||||
* APIs that create/update an entity require that the owner field be passed in the body of the request.
|
||||
* APIs that search for entities typically require that the owner be passed as a query parameter.
|
||||
* APIs that specify an ID of an entity directly generally don't need to specify the owner field.
|
||||
*
|
||||
* For APIs that create/update an entity, the RBAC implementation checks to see if the user making the request has the
|
||||
* correct privileges for performing that action (a create/update) for the specified owner.
|
||||
* This check is done through the Security plugin's API.
|
||||
*
|
||||
* For APIs that search for entities, the RBAC implementation creates a filter for the saved objects query that limits
|
||||
* the search to only owners that the user has access to. We also check that the objects returned by the saved objects
|
||||
* API have the limited owner scope. If we find one that the user does not have permissions for, we throw a 403 error.
|
||||
* The owner field that is passed in as a query parameter can be used to further limit the results. If a user attempts
|
||||
* to pass an owner that they do not have access to, the owner is ignored.
|
||||
*
|
||||
* For APIs that retrieve/delete entities directly using their ID, the RBAC implementation requests the object first,
|
||||
* and then checks to see if the user making the request has access to that operation and owner. If the user does, the
|
||||
* operation continues, otherwise we throw a 403.
|
||||
*/
|
||||
export const OWNER_FIELD = 'owner';
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
* 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 { CasesStatusRequestRt, CasesStatusResponseRt } from './status';
|
||||
|
||||
describe('status', () => {
|
||||
describe('CasesStatusRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
from: '2022-04-28T15:18:00.000Z',
|
||||
to: '2022-04-28T15:22:00.000Z',
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesStatusRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('has removes foo:bar attributes from request', () => {
|
||||
const query = CasesStatusRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesStatusResponseRt', () => {
|
||||
const defaultResponse = {
|
||||
count_closed_cases: 1,
|
||||
count_in_progress_cases: 2,
|
||||
count_open_cases: 1,
|
||||
};
|
||||
|
||||
it('has expected attributes in response', () => {
|
||||
const query = CasesStatusResponseRt.decode(defaultResponse);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultResponse,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from response', () => {
|
||||
const query = CasesStatusResponseRt.decode({ ...defaultResponse, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultResponse,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* 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 { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { MAX_SUGGESTED_PROFILES } from '../../constants';
|
||||
import { SuggestUserProfilesRequestRt, CaseUserProfileRt } from './user_profiles';
|
||||
|
||||
describe('userProfile', () => {
|
||||
describe('SuggestUserProfilesRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('has only name and owner in request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('missing size parameter works correctly', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
name: 'di maria',
|
||||
owners: ['benfica'],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'di maria',
|
||||
owners: ['benfica'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`does not accept size param bigger than ${MAX_SUGGESTED_PROFILES}`, () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
...defaultRequest,
|
||||
size: MAX_SUGGESTED_PROFILES + 1,
|
||||
});
|
||||
|
||||
expect(PathReporter.report(query)).toContain('The size field cannot be more than 10.');
|
||||
});
|
||||
|
||||
it('does not accept size param lower than 1', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
...defaultRequest,
|
||||
size: 0,
|
||||
});
|
||||
|
||||
expect(PathReporter.report(query)).toContain('The size field cannot be less than 1.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseUserProfileRt', () => {
|
||||
it('has expected attributes in response', () => {
|
||||
const query = CaseUserProfileRt.decode({
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from response', () => {
|
||||
const query = CaseUserProfileRt.decode({
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,9 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './cases';
|
||||
export * from './helpers';
|
||||
export * from './runtime_types';
|
||||
export * from './saved_object';
|
||||
export * from './user';
|
||||
export * from './metrics';
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { BulkCreateCommentRequestRt, CommentType } from './cases';
|
||||
|
||||
import { decodeWithExcessOrThrow } from './runtime_types';
|
||||
|
||||
|
@ -101,15 +100,5 @@ describe('runtime_types', () => {
|
|||
|
||||
expect(decodeWithExcessOrThrow(schemaRt)({ a: 'hi' })).toStrictEqual({ a: 'hi' });
|
||||
});
|
||||
|
||||
describe('BulkCreateCommentRequestRt', () => {
|
||||
it('does not throw an error for BulkCreateCommentRequestRt', () => {
|
||||
expect(() =>
|
||||
decodeWithExcessOrThrow(BulkCreateCommentRequestRt)([
|
||||
{ comment: 'hi', type: CommentType.user, owner: 'owner' },
|
||||
])
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -199,3 +199,33 @@ export const LOCAL_STORAGE_KEYS = {
|
|||
*/
|
||||
|
||||
export const NONE_CONNECTOR_ID: string = 'none';
|
||||
|
||||
/**
|
||||
* This field is used for authorization of the entities within the cases plugin. Each entity within Cases will have the owner field
|
||||
* set to a string that represents the plugin that "owns" (i.e. the plugin that originally issued the POST request to
|
||||
* create the entity) the entity.
|
||||
*
|
||||
* The Authorization class constructs a string composed of the operation being performed (createCase, getComment, etc),
|
||||
* and the owner of the entity being acted upon or created. This string is then given to the Security plugin which
|
||||
* checks to see if the user making the request has that particular string stored within it's privileges. If it does,
|
||||
* then the operation succeeds, otherwise the operation fails.
|
||||
*
|
||||
* APIs that create/update an entity require that the owner field be passed in the body of the request.
|
||||
* APIs that search for entities typically require that the owner be passed as a query parameter.
|
||||
* APIs that specify an ID of an entity directly generally don't need to specify the owner field.
|
||||
*
|
||||
* For APIs that create/update an entity, the RBAC implementation checks to see if the user making the request has the
|
||||
* correct privileges for performing that action (a create/update) for the specified owner.
|
||||
* This check is done through the Security plugin's API.
|
||||
*
|
||||
* For APIs that search for entities, the RBAC implementation creates a filter for the saved objects query that limits
|
||||
* the search to only owners that the user has access to. We also check that the objects returned by the saved objects
|
||||
* API have the limited owner scope. If we find one that the user does not have permissions for, we throw a 403 error.
|
||||
* The owner field that is passed in as a query parameter can be used to further limit the results. If a user attempts
|
||||
* to pass an owner that they do not have access to, the owner is ignored.
|
||||
*
|
||||
* For APIs that retrieve/delete entities directly using their ID, the RBAC implementation requests the object first,
|
||||
* and then checks to see if the user making the request has access to that operation and owner. If the user does, the
|
||||
* operation continues, otherwise we throw a 403.
|
||||
*/
|
||||
export const OWNER_FIELD = 'owner';
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
// For example, constants below could eventually be in a "kbn-cases-constants" instead.
|
||||
// See: https://docs.elastic.dev/kibana-dev-docs/key-concepts/platform-intro#public-plugin-api
|
||||
|
||||
export type { Case, Cases, CasesBulkGetResponse } from './api';
|
||||
export type {
|
||||
CasesBulkGetResponse,
|
||||
CasePostRequest,
|
||||
GetRelatedCasesByAlertResponse,
|
||||
UserActionFindResponse,
|
||||
} from './types/api';
|
||||
export type { Case, Cases, RelatedCase } from './types/domain';
|
||||
export type {
|
||||
CaseUI,
|
||||
CasesUI,
|
||||
|
@ -23,8 +29,11 @@ export type {
|
|||
Ecs,
|
||||
CaseViewRefreshPropInterface,
|
||||
CasesPermissions,
|
||||
CasesStatus,
|
||||
} from './ui/types';
|
||||
|
||||
export { CaseSeverity } from './types/domain';
|
||||
|
||||
export {
|
||||
APP_ID,
|
||||
CASES_URL,
|
||||
|
@ -38,18 +47,14 @@ export {
|
|||
UPDATE_CASES_CAPABILITY,
|
||||
INTERNAL_BULK_GET_CASES_URL,
|
||||
LENS_ATTACHMENT_TYPE,
|
||||
INTERNAL_BULK_CREATE_ATTACHMENTS_URL,
|
||||
SAVED_OBJECT_TYPES,
|
||||
CASE_COMMENT_SAVED_OBJECT,
|
||||
} from './constants';
|
||||
|
||||
export { ConnectorTypes } from './types/domain';
|
||||
|
||||
export {
|
||||
getCasesFromAlertsUrl,
|
||||
throwErrors,
|
||||
CaseStatuses,
|
||||
CaseSeverity,
|
||||
CommentType,
|
||||
ExternalReferenceStorageType,
|
||||
} from './api';
|
||||
export type { AttachmentAttributes } from './types/domain';
|
||||
export { ConnectorTypes, AttachmentType, ExternalReferenceStorageType } from './types/domain';
|
||||
export { getCasesFromAlertsUrl, getCaseFindUserActionsUrl, throwErrors } from './api';
|
||||
export { StatusAll } from './ui/types';
|
||||
export { createUICapabilities } from './utils/capabilities';
|
||||
export { getApiTags } from './utils/api_tags';
|
||||
|
|
|
@ -5,10 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export * from './case';
|
||||
export * from './comment';
|
||||
export * from './status';
|
||||
export * from './constants';
|
||||
export * from './alerts';
|
||||
export * from './user_profiles';
|
||||
export * from './assignee';
|
||||
export * from './v1';
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AlertResponseRt } from './alerts';
|
||||
import { AlertResponseRt } from './v1';
|
||||
|
||||
describe('Alerts', () => {
|
||||
describe('AlertResponseRt', () => {
|
|
@ -5,9 +5,4 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseUserProfileRt } from './user_profiles';
|
||||
|
||||
export const CaseAssigneesRt = rt.array(CaseUserProfileRt);
|
||||
|
||||
export type CaseAssignees = rt.TypeOf<typeof CaseAssigneesRt>;
|
||||
export * from './v1';
|
392
x-pack/plugins/cases/common/types/api/attachment/v1.test.ts
Normal file
392
x-pack/plugins/cases/common/types/api/attachment/v1.test.ts
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
* 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 { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { MAX_BULK_CREATE_ATTACHMENTS, MAX_COMMENT_LENGTH } from '../../../constants';
|
||||
import { AttachmentType } from '../../domain/attachment/v1';
|
||||
import {
|
||||
AttachmentPatchRequestRt,
|
||||
AttachmentRequestRt,
|
||||
AttachmentsFindResponseRt,
|
||||
BulkCreateAttachmentsRequestRt,
|
||||
BulkDeleteFileAttachmentsRequestRt,
|
||||
BulkGetAttachmentsRequestRt,
|
||||
BulkGetAttachmentsResponseRt,
|
||||
FindAttachmentsQueryParamsRt,
|
||||
} from './v1';
|
||||
|
||||
describe('Attachments', () => {
|
||||
describe('BulkDeleteFileAttachmentsRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkDeleteFileAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkDeleteFileAttachmentsRequestRt.decode({
|
||||
ids: ['abc', 'xyz'],
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
describe('commentType: user', () => {
|
||||
it('throws error when comment is too long', () => {
|
||||
const longComment = 'x'.repeat(MAX_COMMENT_LENGTH + 1);
|
||||
|
||||
expect(
|
||||
PathReporter.report(
|
||||
AttachmentRequestRt.decode({ ...defaultRequest, comment: longComment })
|
||||
)
|
||||
).toContain('The length of the comment is too long. The maximum length is 30000.');
|
||||
});
|
||||
|
||||
it('throws error when comment is empty', () => {
|
||||
expect(
|
||||
PathReporter.report(AttachmentRequestRt.decode({ ...defaultRequest, comment: '' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
|
||||
it('throws error when comment string of empty characters', () => {
|
||||
expect(
|
||||
PathReporter.report(AttachmentRequestRt.decode({ ...defaultRequest, comment: ' ' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('commentType: action', () => {
|
||||
const request = {
|
||||
type: AttachmentType.actions,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('throws error when comment is too long', () => {
|
||||
const longComment = 'x'.repeat(MAX_COMMENT_LENGTH + 1);
|
||||
|
||||
expect(
|
||||
PathReporter.report(AttachmentRequestRt.decode({ ...request, comment: longComment }))
|
||||
).toContain('The length of the comment is too long. The maximum length is 30000.');
|
||||
});
|
||||
|
||||
it('throws error when comment is empty', () => {
|
||||
expect(
|
||||
PathReporter.report(AttachmentRequestRt.decode({ ...request, comment: '' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
|
||||
it('throws error when comment string of empty characters', () => {
|
||||
expect(
|
||||
PathReporter.report(AttachmentRequestRt.decode({ ...request, comment: ' ' }))
|
||||
).toContain('The comment field cannot be an empty string.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentPatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: AttachmentType.alert,
|
||||
id: 'alert-comment-id',
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
version: 'WzQ3LDFc',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentPatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentPatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentsFindResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
comments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
},
|
||||
],
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 1,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentsFindResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentsFindResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from comments', () => {
|
||||
const query = AttachmentsFindResponseRt.decode({
|
||||
...defaultRequest,
|
||||
comments: [{ ...defaultRequest.comments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('FindAttachmentsQueryParamsRt', () => {
|
||||
const defaultRequest = {
|
||||
page: 1,
|
||||
perPage: 10,
|
||||
sortOrder: 'asc',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = FindAttachmentsQueryParamsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = FindAttachmentsQueryParamsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkCreateAttachmentsRequestRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkCreateAttachmentsRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkCreateAttachmentsRequestRt.decode([
|
||||
{ comment: 'Solve this fast!', type: AttachmentType.user, owner: 'cases', foo: 'bar' },
|
||||
]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it(`throws error when attachments are more than ${MAX_BULK_CREATE_ATTACHMENTS}`, () => {
|
||||
const comment = {
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
const attachments = Array(MAX_BULK_CREATE_ATTACHMENTS + 1).fill(comment);
|
||||
|
||||
expect(PathReporter.report(BulkCreateAttachmentsRequestRt.decode(attachments))).toContain(
|
||||
`The length of the field attachments is too long. Array must be of length <= ${MAX_BULK_CREATE_ATTACHMENTS}.`
|
||||
);
|
||||
});
|
||||
|
||||
it(`no errors when empty array of attachments`, () => {
|
||||
expect(PathReporter.report(BulkCreateAttachmentsRequestRt.decode([]))).toStrictEqual([
|
||||
'No errors!',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkGetAttachmentsRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkGetAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkGetAttachmentsRequestRt.decode({ ids: ['abc', 'xyz'], foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ids: ['abc', 'xyz'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('BulkGetAttachmentsResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
attachments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
},
|
||||
],
|
||||
errors: [
|
||||
{
|
||||
error: 'error',
|
||||
message: 'not found',
|
||||
status: 404,
|
||||
attachmentId: 'abc',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from attachments', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({
|
||||
...defaultRequest,
|
||||
attachments: [{ ...defaultRequest.attachments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from errors', () => {
|
||||
const query = BulkGetAttachmentsResponseRt.decode({
|
||||
...defaultRequest,
|
||||
errors: [{ ...defaultRequest.errors[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
157
x-pack/plugins/cases/common/types/api/attachment/v1.ts
Normal file
157
x-pack/plugins/cases/common/types/api/attachment/v1.ts
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import {
|
||||
MAX_BULK_CREATE_ATTACHMENTS,
|
||||
MAX_BULK_GET_ATTACHMENTS,
|
||||
MAX_COMMENTS_PER_PAGE,
|
||||
MAX_COMMENT_LENGTH,
|
||||
MAX_DELETE_FILES,
|
||||
} from '../../../constants';
|
||||
import {
|
||||
limitedArraySchema,
|
||||
limitedStringSchema,
|
||||
NonEmptyString,
|
||||
paginationSchema,
|
||||
} from '../../../schema';
|
||||
import {
|
||||
UserCommentAttachmentPayloadRt,
|
||||
AlertAttachmentPayloadRt,
|
||||
ActionsAttachmentPayloadRt,
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
ExternalReferenceSOAttachmentPayloadRt,
|
||||
ExternalReferenceSOWithoutRefsAttachmentPayloadRt,
|
||||
PersistableStateAttachmentPayloadRt,
|
||||
AttachmentType,
|
||||
AttachmentRt,
|
||||
AttachmentsRt,
|
||||
} from '../../domain/attachment/v1';
|
||||
|
||||
/**
|
||||
* Files
|
||||
*/
|
||||
|
||||
const MIN_DELETE_IDS = 1;
|
||||
|
||||
export const BulkDeleteFileAttachmentsRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({
|
||||
codec: NonEmptyString,
|
||||
min: MIN_DELETE_IDS,
|
||||
max: MAX_DELETE_FILES,
|
||||
fieldName: 'ids',
|
||||
}),
|
||||
});
|
||||
|
||||
export type BulkDeleteFileAttachmentsRequest = rt.TypeOf<typeof BulkDeleteFileAttachmentsRequestRt>;
|
||||
|
||||
const BasicAttachmentRequestRt = rt.union([
|
||||
UserCommentAttachmentPayloadRt,
|
||||
AlertAttachmentPayloadRt,
|
||||
ActionsAttachmentPayloadRt,
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
PersistableStateAttachmentPayloadRt,
|
||||
]);
|
||||
|
||||
export const AttachmentRequestRt = rt.union([
|
||||
rt.strict({
|
||||
comment: limitedStringSchema({ fieldName: 'comment', min: 1, max: MAX_COMMENT_LENGTH }),
|
||||
type: rt.literal(AttachmentType.user),
|
||||
owner: rt.string,
|
||||
}),
|
||||
AlertAttachmentPayloadRt,
|
||||
rt.strict({
|
||||
type: rt.literal(AttachmentType.actions),
|
||||
comment: limitedStringSchema({ fieldName: 'comment', min: 1, max: MAX_COMMENT_LENGTH }),
|
||||
actions: rt.strict({
|
||||
targets: rt.array(
|
||||
rt.strict({
|
||||
hostname: rt.string,
|
||||
endpointId: rt.string,
|
||||
})
|
||||
),
|
||||
type: rt.string,
|
||||
}),
|
||||
owner: rt.string,
|
||||
}),
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
ExternalReferenceSOAttachmentPayloadRt,
|
||||
PersistableStateAttachmentPayloadRt,
|
||||
]);
|
||||
|
||||
export const AttachmentRequestWithoutRefsRt = rt.union([
|
||||
BasicAttachmentRequestRt,
|
||||
ExternalReferenceSOWithoutRefsAttachmentPayloadRt,
|
||||
]);
|
||||
|
||||
export const AttachmentPatchRequestRt = rt.intersection([
|
||||
/**
|
||||
* Partial updates are not allowed.
|
||||
* We want to prevent the user for changing the type without removing invalid fields.
|
||||
*
|
||||
* injectAttachmentSOAttributesFromRefsForPatch is dependent on this assumption.
|
||||
* The consumers of the persistable attachment service should always get the
|
||||
* persistableStateAttachmentState on a patch.
|
||||
*/
|
||||
AttachmentRequestRt,
|
||||
rt.strict({ id: rt.string, version: rt.string }),
|
||||
]);
|
||||
|
||||
export const AttachmentsFindResponseRt = rt.strict({
|
||||
comments: rt.array(AttachmentRt),
|
||||
page: rt.number,
|
||||
per_page: rt.number,
|
||||
total: rt.number,
|
||||
});
|
||||
|
||||
export const FindAttachmentsQueryParamsRt = rt.intersection([
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
/**
|
||||
* Order to sort the response
|
||||
*/
|
||||
sortOrder: rt.union([rt.literal('desc'), rt.literal('asc')]),
|
||||
})
|
||||
),
|
||||
paginationSchema({ maxPerPage: MAX_COMMENTS_PER_PAGE }),
|
||||
]);
|
||||
|
||||
export const BulkCreateAttachmentsRequestRt = limitedArraySchema({
|
||||
codec: AttachmentRequestRt,
|
||||
min: 0,
|
||||
max: MAX_BULK_CREATE_ATTACHMENTS,
|
||||
fieldName: 'attachments',
|
||||
});
|
||||
|
||||
export const BulkGetAttachmentsRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({
|
||||
codec: rt.string,
|
||||
min: 1,
|
||||
max: MAX_BULK_GET_ATTACHMENTS,
|
||||
fieldName: 'ids',
|
||||
}),
|
||||
});
|
||||
|
||||
export const BulkGetAttachmentsResponseRt = rt.strict({
|
||||
attachments: AttachmentsRt,
|
||||
errors: rt.array(
|
||||
rt.strict({
|
||||
error: rt.string,
|
||||
message: rt.string,
|
||||
status: rt.union([rt.undefined, rt.number]),
|
||||
attachmentId: rt.string,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
export type FindAttachmentsQueryParams = rt.TypeOf<typeof FindAttachmentsQueryParamsRt>;
|
||||
export type AttachmentsFindResponse = rt.TypeOf<typeof AttachmentsFindResponseRt>;
|
||||
export type AttachmentRequest = rt.TypeOf<typeof AttachmentRequestRt>;
|
||||
export type AttachmentPatchRequest = rt.TypeOf<typeof AttachmentPatchRequestRt>;
|
||||
export type BulkCreateAttachmentsRequest = rt.TypeOf<typeof BulkCreateAttachmentsRequestRt>;
|
||||
export type BulkGetAttachmentsResponse = rt.TypeOf<typeof BulkGetAttachmentsResponseRt>;
|
||||
export type BulkGetAttachmentsRequest = rt.TypeOf<typeof BulkGetAttachmentsRequestRt>;
|
8
x-pack/plugins/cases/common/types/api/case/latest.ts
Normal file
8
x-pack/plugins/cases/common/types/api/case/latest.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
555
x-pack/plugins/cases/common/types/api/case/v1.test.ts
Normal file
555
x-pack/plugins/cases/common/types/api/case/v1.test.ts
Normal file
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* 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 { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { AttachmentType } from '../../domain/attachment/v1';
|
||||
import { CaseSeverity, CaseStatuses } from '../../domain/case/v1';
|
||||
import { ConnectorTypes } from '../../domain/connector/v1';
|
||||
import { CasesStatusRequestRt, CasesStatusResponseRt } from '../stats/v1';
|
||||
import {
|
||||
AllReportersFindRequestRt,
|
||||
CasePatchRequestRt,
|
||||
CasePostRequestRt,
|
||||
CasePushRequestParamsRt,
|
||||
CaseResolveResponseRt,
|
||||
CasesBulkGetRequestRt,
|
||||
CasesBulkGetResponseRt,
|
||||
CasesByAlertIDRequestRt,
|
||||
CasesFindRequestRt,
|
||||
CasesFindRequestSearchFieldsRt,
|
||||
CasesFindRequestSortFieldsRt,
|
||||
CasesFindResponseRt,
|
||||
CasesPatchRequestRt,
|
||||
} from './v1';
|
||||
|
||||
const basicCase = {
|
||||
owner: 'cases',
|
||||
closed_at: null,
|
||||
closed_by: null,
|
||||
id: 'basic-case-id',
|
||||
comments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
id: 'basic-comment-id',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
owner: 'cases',
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
version: 'WzQ3LDFc',
|
||||
},
|
||||
],
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
connector: {
|
||||
id: 'none',
|
||||
name: 'My Connector',
|
||||
type: ConnectorTypes.none,
|
||||
fields: null,
|
||||
},
|
||||
description: 'Security banana Issue',
|
||||
severity: CaseSeverity.LOW,
|
||||
duration: null,
|
||||
external_service: null,
|
||||
status: CaseStatuses.open,
|
||||
tags: ['coke', 'pepsi'],
|
||||
title: 'Another horrible breach!!',
|
||||
totalComment: 1,
|
||||
totalAlerts: 0,
|
||||
updated_at: '2020-02-20T15:02:57.995Z',
|
||||
updated_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
version: 'WzQ3LDFd',
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
// damaged_raccoon uid
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
category: null,
|
||||
};
|
||||
|
||||
describe('Status', () => {
|
||||
describe('CasesStatusRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
from: '2022-04-28T15:18:00.000Z',
|
||||
to: '2022-04-28T15:22:00.000Z',
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesStatusRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('has removes foo:bar attributes from request', () => {
|
||||
const query = CasesStatusRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesStatusResponseRt', () => {
|
||||
const defaultResponse = {
|
||||
count_closed_cases: 1,
|
||||
count_in_progress_cases: 2,
|
||||
count_open_cases: 1,
|
||||
};
|
||||
|
||||
it('has expected attributes in response', () => {
|
||||
const query = CasesStatusResponseRt.decode(defaultResponse);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultResponse,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from response', () => {
|
||||
const query = CasesStatusResponseRt.decode({ ...defaultResponse, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultResponse,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePostRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
description: 'A description',
|
||||
tags: ['new', 'case'],
|
||||
title: 'My new case',
|
||||
connector: {
|
||||
id: '123',
|
||||
name: 'My connector',
|
||||
type: ConnectorTypes.jira,
|
||||
fields: { issueType: 'Task', priority: 'High', parent: null },
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
owner: 'cases',
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePostRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePostRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from connector', () => {
|
||||
const query = CasePostRequestRt.decode({
|
||||
...defaultRequest,
|
||||
connector: { ...defaultRequest.connector, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesFindRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
tags: ['new', 'case'],
|
||||
status: CaseStatuses.open,
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: ['damaged_racoon'],
|
||||
reporters: ['damaged_racoon'],
|
||||
defaultSearchOperator: 'AND',
|
||||
from: 'now',
|
||||
page: '1',
|
||||
perPage: '10',
|
||||
search: 'search text',
|
||||
searchFields: ['title', 'description'],
|
||||
to: '1w',
|
||||
sortOrder: 'desc',
|
||||
sortField: 'createdAt',
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesFindRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
const searchFields = Object.keys(CasesFindRequestSearchFieldsRt.keys);
|
||||
|
||||
it.each(searchFields)('succeeds with %s as searchFields', (field) => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, searchFields: field });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, searchFields: field, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
const sortFields = Object.keys(CasesFindRequestSortFieldsRt.keys);
|
||||
|
||||
it.each(sortFields)('succeeds with %s as sortField', (sortField) => {
|
||||
const query = CasesFindRequestRt.decode({ ...defaultRequest, sortField });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, sortField, page: 1, perPage: 10 },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes rootSearchField when passed', () => {
|
||||
expect(
|
||||
PathReporter.report(
|
||||
CasesFindRequestRt.decode({ ...defaultRequest, rootSearchField: ['foobar'] })
|
||||
)
|
||||
).toContain('No errors!');
|
||||
});
|
||||
|
||||
describe('errors', () => {
|
||||
it('throws error when invalid searchField passed', () => {
|
||||
expect(
|
||||
PathReporter.report(
|
||||
CasesFindRequestRt.decode({ ...defaultRequest, searchFields: 'foobar' })
|
||||
)
|
||||
).not.toContain('No errors!');
|
||||
});
|
||||
|
||||
it('throws error when invalid sortField passed', () => {
|
||||
expect(
|
||||
PathReporter.report(CasesFindRequestRt.decode({ ...defaultRequest, sortField: 'foobar' }))
|
||||
).not.toContain('No errors!');
|
||||
});
|
||||
|
||||
it('succeeds when valid parameters passed', () => {
|
||||
expect(PathReporter.report(CasesFindRequestRt.decode(defaultRequest))).toContain(
|
||||
'No errors!'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesByAlertIDRequestRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesByAlertIDRequestRt.decode({ owner: 'cases' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { owner: 'cases' },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesByAlertIDRequestRt.decode({ owner: ['cases'], foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { owner: ['cases'] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseResolveResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
case: { ...basicCase },
|
||||
outcome: 'exactMatch',
|
||||
alias_target_id: 'sample-target-id',
|
||||
alias_purpose: 'savedObjectConversion',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseResolveResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseResolveResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesFindResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [{ ...basicCase }],
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
total: 20,
|
||||
count_open_cases: 10,
|
||||
count_in_progress_cases: 5,
|
||||
count_closed_cases: 5,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesFindResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesFindResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from cases', () => {
|
||||
const query = CasesFindResponseRt.decode({
|
||||
...defaultRequest,
|
||||
cases: [{ ...basicCase, foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
id: 'basic-case-id',
|
||||
version: 'WzQ3LDFd',
|
||||
description: 'Updated description',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesPatchRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [
|
||||
{
|
||||
id: 'basic-case-id',
|
||||
version: 'WzQ3LDFd',
|
||||
description: 'Updated description',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesPatchRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesPatchRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasePushRequestParamsRt', () => {
|
||||
const defaultRequest = {
|
||||
case_id: 'basic-case-id',
|
||||
connector_id: 'basic-connector-id',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasePushRequestParamsRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasePushRequestParamsRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AllReportersFindRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
owner: ['cases', 'security-solution'],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AllReportersFindRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AllReportersFindRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesBulkGetRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
ids: ['case-1', 'case-2'],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesBulkGetRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesBulkGetRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesBulkGetResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
cases: [basicCase],
|
||||
errors: [
|
||||
{
|
||||
error: 'error',
|
||||
message: 'error-message',
|
||||
status: 403,
|
||||
caseId: 'basic-case-id',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesBulkGetResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from cases', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({
|
||||
...defaultRequest,
|
||||
cases: [{ ...defaultRequest.cases[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { ...defaultRequest, cases: defaultRequest.cases },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from errors', () => {
|
||||
const query = CasesBulkGetResponseRt.decode({
|
||||
...defaultRequest,
|
||||
errors: [{ ...defaultRequest.errors[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,145 +6,41 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
|
||||
import { UserRt } from '../user';
|
||||
import { CommentRt } from './comment';
|
||||
import { CasesStatusResponseRt, CaseStatusRt } from './status';
|
||||
import { CaseAssigneesRt } from './assignee';
|
||||
import {
|
||||
limitedArraySchema,
|
||||
limitedStringSchema,
|
||||
NonEmptyString,
|
||||
paginationSchema,
|
||||
} from '../../schema';
|
||||
import {
|
||||
MAX_DELETE_IDS_LENGTH,
|
||||
MAX_DESCRIPTION_LENGTH,
|
||||
MAX_TITLE_LENGTH,
|
||||
MAX_LENGTH_PER_TAG,
|
||||
MAX_CATEGORY_LENGTH,
|
||||
MAX_TAGS_PER_CASE,
|
||||
MAX_TITLE_LENGTH,
|
||||
MAX_CATEGORY_LENGTH,
|
||||
MAX_ASSIGNEES_FILTER_LENGTH,
|
||||
MAX_CASES_PER_PAGE,
|
||||
MAX_DELETE_IDS_LENGTH,
|
||||
MAX_REPORTERS_FILTER_LENGTH,
|
||||
MAX_TAGS_FILTER_LENGTH,
|
||||
MAX_CASES_TO_UPDATE,
|
||||
MAX_BULK_GET_CASES,
|
||||
MAX_CASES_PER_PAGE,
|
||||
} from '../../constants';
|
||||
import { CaseConnectorRt } from '../../types/domain/connector/v1';
|
||||
|
||||
export const AttachmentTotalsRt = rt.strict({
|
||||
alerts: rt.number,
|
||||
userComments: rt.number,
|
||||
});
|
||||
|
||||
export const RelatedCaseInfoRt = rt.strict({
|
||||
id: rt.string,
|
||||
title: rt.string,
|
||||
description: rt.string,
|
||||
status: CaseStatusRt,
|
||||
createdAt: rt.string,
|
||||
totals: AttachmentTotalsRt,
|
||||
});
|
||||
|
||||
export const CasesByAlertIdRt = rt.array(RelatedCaseInfoRt);
|
||||
|
||||
export const SettingsRt = rt.strict({
|
||||
syncAlerts: rt.boolean,
|
||||
});
|
||||
|
||||
export enum CaseSeverity {
|
||||
LOW = 'low',
|
||||
MEDIUM = 'medium',
|
||||
HIGH = 'high',
|
||||
CRITICAL = 'critical',
|
||||
}
|
||||
|
||||
export const CaseSeverityRt = rt.union([
|
||||
rt.literal(CaseSeverity.LOW),
|
||||
rt.literal(CaseSeverity.MEDIUM),
|
||||
rt.literal(CaseSeverity.HIGH),
|
||||
rt.literal(CaseSeverity.CRITICAL),
|
||||
]);
|
||||
|
||||
const CaseBasicRt = rt.strict({
|
||||
/**
|
||||
* The description of the case
|
||||
*/
|
||||
description: rt.string,
|
||||
/**
|
||||
* The current status of the case (open, closed, in-progress)
|
||||
*/
|
||||
status: CaseStatusRt,
|
||||
/**
|
||||
* The identifying strings for filter a case
|
||||
*/
|
||||
tags: rt.array(rt.string),
|
||||
/**
|
||||
* The title of a case
|
||||
*/
|
||||
title: rt.string,
|
||||
/**
|
||||
* The external system that the case can be synced with
|
||||
*/
|
||||
connector: CaseConnectorRt,
|
||||
/**
|
||||
* The alert sync settings
|
||||
*/
|
||||
settings: SettingsRt,
|
||||
/**
|
||||
* The plugin owner of the case
|
||||
*/
|
||||
owner: rt.string,
|
||||
/**
|
||||
* The severity of the case
|
||||
*/
|
||||
severity: CaseSeverityRt,
|
||||
/**
|
||||
* The users assigned to this case
|
||||
*/
|
||||
assignees: CaseAssigneesRt,
|
||||
/**
|
||||
* The category of the case.
|
||||
*/
|
||||
category: rt.union([rt.string, rt.null]),
|
||||
});
|
||||
} from '../../../constants';
|
||||
import {
|
||||
limitedStringSchema,
|
||||
limitedArraySchema,
|
||||
NonEmptyString,
|
||||
paginationSchema,
|
||||
} from '../../../schema';
|
||||
import {
|
||||
CaseRt,
|
||||
CaseSettingsRt,
|
||||
CaseSeverityRt,
|
||||
CasesRt,
|
||||
CaseStatusRt,
|
||||
RelatedCaseRt,
|
||||
} from '../../domain/case/v1';
|
||||
import { CaseConnectorRt } from '../../domain/connector/v1';
|
||||
import { CaseAssigneesRt, UserRt } from '../../domain/user/v1';
|
||||
import { CasesStatusResponseRt } from '../stats/v1';
|
||||
|
||||
/**
|
||||
* This represents the push to service UserAction. It lacks the connector_id because that is stored in a different field
|
||||
* within the user action object in the API response.
|
||||
* Create case
|
||||
*/
|
||||
export const CaseUserActionExternalServiceRt = rt.strict({
|
||||
connector_name: rt.string,
|
||||
external_id: rt.string,
|
||||
external_title: rt.string,
|
||||
external_url: rt.string,
|
||||
pushed_at: rt.string,
|
||||
pushed_by: UserRt,
|
||||
});
|
||||
|
||||
export const CaseExternalServiceBasicRt = rt.intersection([
|
||||
rt.strict({
|
||||
connector_id: rt.string,
|
||||
}),
|
||||
CaseUserActionExternalServiceRt,
|
||||
]);
|
||||
|
||||
export const CaseFullExternalServiceRt = rt.union([CaseExternalServiceBasicRt, rt.null]);
|
||||
|
||||
export const CaseAttributesRt = rt.intersection([
|
||||
CaseBasicRt,
|
||||
rt.strict({
|
||||
duration: rt.union([rt.number, rt.null]),
|
||||
closed_at: rt.union([rt.string, rt.null]),
|
||||
closed_by: rt.union([UserRt, rt.null]),
|
||||
created_at: rt.string,
|
||||
created_by: UserRt,
|
||||
external_service: CaseFullExternalServiceRt,
|
||||
updated_at: rt.union([rt.string, rt.null]),
|
||||
updated_by: rt.union([UserRt, rt.null]),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CasePostRequestRt = rt.intersection([
|
||||
rt.strict({
|
||||
|
@ -176,7 +72,7 @@ export const CasePostRequestRt = rt.intersection([
|
|||
/**
|
||||
* Sync settings for alerts
|
||||
*/
|
||||
settings: SettingsRt,
|
||||
settings: CaseSettingsRt,
|
||||
/**
|
||||
* The owner here must match the string used when a plugin registers a feature with access to the cases plugin. The user
|
||||
* creating this case must also be granted access to that plugin's feature.
|
||||
|
@ -324,6 +220,20 @@ export const CasesFindRequestRt = rt.intersection([
|
|||
paginationSchema({ maxPerPage: MAX_CASES_PER_PAGE }),
|
||||
]);
|
||||
|
||||
export const CasesFindResponseRt = rt.intersection([
|
||||
rt.strict({
|
||||
cases: rt.array(CaseRt),
|
||||
page: rt.number,
|
||||
per_page: rt.number,
|
||||
total: rt.number,
|
||||
}),
|
||||
CasesStatusResponseRt,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Delete cases
|
||||
*/
|
||||
|
||||
export const CasesDeleteRequestRt = limitedArraySchema({
|
||||
codec: NonEmptyString,
|
||||
min: 1,
|
||||
|
@ -331,30 +241,9 @@ export const CasesDeleteRequestRt = limitedArraySchema({
|
|||
fieldName: 'ids',
|
||||
});
|
||||
|
||||
export const CasesByAlertIDRequestRt = rt.exact(
|
||||
rt.partial({
|
||||
/**
|
||||
* The type of cases to retrieve given an alert ID. If no owner is provided, all cases
|
||||
* that the user has access to will be returned.
|
||||
*/
|
||||
owner: rt.union([rt.array(rt.string), rt.string]),
|
||||
})
|
||||
);
|
||||
|
||||
export const CaseRt = rt.intersection([
|
||||
CaseAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
totalComment: rt.number,
|
||||
totalAlerts: rt.number,
|
||||
version: rt.string,
|
||||
}),
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
comments: rt.array(CommentRt),
|
||||
})
|
||||
),
|
||||
]);
|
||||
/**
|
||||
* Resolve case
|
||||
*/
|
||||
|
||||
export const CaseResolveResponseRt = rt.intersection([
|
||||
rt.strict({
|
||||
|
@ -372,16 +261,28 @@ export const CaseResolveResponseRt = rt.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export const CasesFindResponseRt = rt.intersection([
|
||||
rt.strict({
|
||||
cases: rt.array(CaseRt),
|
||||
page: rt.number,
|
||||
per_page: rt.number,
|
||||
total: rt.number,
|
||||
}),
|
||||
CasesStatusResponseRt,
|
||||
]);
|
||||
/**
|
||||
* Get cases
|
||||
*/
|
||||
export const CasesBulkGetRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({ codec: rt.string, min: 1, max: MAX_BULK_GET_CASES, fieldName: 'ids' }),
|
||||
});
|
||||
|
||||
export const CasesBulkGetResponseRt = rt.strict({
|
||||
cases: CasesRt,
|
||||
errors: rt.array(
|
||||
rt.strict({
|
||||
error: rt.string,
|
||||
message: rt.string,
|
||||
status: rt.union([rt.undefined, rt.number]),
|
||||
caseId: rt.string,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* Update cases
|
||||
*/
|
||||
export const CasePatchRequestRt = rt.intersection([
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
|
@ -417,7 +318,7 @@ export const CasePatchRequestRt = rt.intersection([
|
|||
/**
|
||||
* The alert sync settings
|
||||
*/
|
||||
settings: SettingsRt,
|
||||
settings: CaseSettingsRt,
|
||||
/**
|
||||
* The plugin owner of the case
|
||||
*/
|
||||
|
@ -454,34 +355,18 @@ export const CasesPatchRequestRt = rt.strict({
|
|||
}),
|
||||
});
|
||||
|
||||
export const CasesRt = rt.array(CaseRt);
|
||||
/**
|
||||
* Push case
|
||||
*/
|
||||
|
||||
export const CasePushRequestParamsRt = rt.strict({
|
||||
case_id: rt.string,
|
||||
connector_id: rt.string,
|
||||
});
|
||||
|
||||
export const ExternalServiceResponseRt = rt.intersection([
|
||||
rt.strict({
|
||||
title: rt.string,
|
||||
id: rt.string,
|
||||
pushedDate: rt.string,
|
||||
url: rt.string,
|
||||
}),
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
comments: rt.array(
|
||||
rt.intersection([
|
||||
rt.strict({
|
||||
commentId: rt.string,
|
||||
pushedDate: rt.string,
|
||||
}),
|
||||
rt.exact(rt.partial({ externalCommentId: rt.string })),
|
||||
])
|
||||
),
|
||||
})
|
||||
),
|
||||
]);
|
||||
/**
|
||||
* Taxonomies
|
||||
*/
|
||||
|
||||
export const AllTagsFindRequestRt = rt.exact(
|
||||
rt.partial({
|
||||
|
@ -509,28 +394,24 @@ export const GetTagsResponseRt = rt.array(rt.string);
|
|||
export const GetCategoriesResponseRt = rt.array(rt.string);
|
||||
export const GetReportersResponseRt = rt.array(UserRt);
|
||||
|
||||
export const CasesBulkGetRequestRt = rt.strict({
|
||||
ids: limitedArraySchema({ codec: rt.string, min: 1, max: MAX_BULK_GET_CASES, fieldName: 'ids' }),
|
||||
});
|
||||
/**
|
||||
* Alerts
|
||||
*/
|
||||
|
||||
export const CasesBulkGetResponseRt = rt.strict({
|
||||
cases: CasesRt,
|
||||
errors: rt.array(
|
||||
rt.strict({
|
||||
error: rt.string,
|
||||
message: rt.string,
|
||||
status: rt.union([rt.undefined, rt.number]),
|
||||
caseId: rt.string,
|
||||
})
|
||||
),
|
||||
});
|
||||
export const CasesByAlertIDRequestRt = rt.exact(
|
||||
rt.partial({
|
||||
/**
|
||||
* The type of cases to retrieve given an alert ID. If no owner is provided, all cases
|
||||
* that the user has access to will be returned.
|
||||
*/
|
||||
owner: rt.union([rt.array(rt.string), rt.string]),
|
||||
})
|
||||
);
|
||||
|
||||
export type CaseAttributes = rt.TypeOf<typeof CaseAttributesRt>;
|
||||
export const GetRelatedCasesByAlertResponseRt = rt.array(RelatedCaseRt);
|
||||
|
||||
export type CasePostRequest = rt.TypeOf<typeof CasePostRequestRt>;
|
||||
export type Case = rt.TypeOf<typeof CaseRt>;
|
||||
export type CaseResolveResponse = rt.TypeOf<typeof CaseResolveResponseRt>;
|
||||
export type Cases = rt.TypeOf<typeof CasesRt>;
|
||||
export type CasesDeleteRequest = rt.TypeOf<typeof CasesDeleteRequestRt>;
|
||||
export type CasesByAlertIDRequest = rt.TypeOf<typeof CasesByAlertIDRequestRt>;
|
||||
export type CasesFindRequest = rt.TypeOf<typeof CasesFindRequestRt>;
|
||||
|
@ -538,18 +419,12 @@ export type CasesFindRequestSortFields = rt.TypeOf<typeof CasesFindRequestSortFi
|
|||
export type CasesFindResponse = rt.TypeOf<typeof CasesFindResponseRt>;
|
||||
export type CasePatchRequest = rt.TypeOf<typeof CasePatchRequestRt>;
|
||||
export type CasesPatchRequest = rt.TypeOf<typeof CasesPatchRequestRt>;
|
||||
export type CaseFullExternalService = rt.TypeOf<typeof CaseFullExternalServiceRt>;
|
||||
export type CaseSettings = rt.TypeOf<typeof SettingsRt>;
|
||||
export type ExternalServiceResponse = rt.TypeOf<typeof ExternalServiceResponseRt>;
|
||||
export type CaseExternalServiceBasic = rt.TypeOf<typeof CaseExternalServiceBasicRt>;
|
||||
|
||||
export type AllTagsFindRequest = rt.TypeOf<typeof AllTagsFindRequestRt>;
|
||||
export type GetTagsResponse = rt.TypeOf<typeof GetTagsResponseRt>;
|
||||
export type AllCategoriesFindRequest = rt.TypeOf<typeof AllCategoriesFindRequestRt>;
|
||||
export type GetCategoriesResponse = rt.TypeOf<typeof GetCategoriesResponseRt>;
|
||||
export type AllReportersFindRequest = AllTagsFindRequest;
|
||||
|
||||
export type AttachmentTotals = rt.TypeOf<typeof AttachmentTotalsRt>;
|
||||
export type RelatedCaseInfo = rt.TypeOf<typeof RelatedCaseInfoRt>;
|
||||
export type CasesByAlertId = rt.TypeOf<typeof CasesByAlertIdRt>;
|
||||
|
||||
export type GetReportersResponse = rt.TypeOf<typeof GetReportersResponseRt>;
|
||||
export type CasesBulkGetRequest = rt.TypeOf<typeof CasesBulkGetRequestRt>;
|
||||
export type CasesBulkGetResponse = rt.TypeOf<typeof CasesBulkGetResponseRt>;
|
||||
export type GetRelatedCasesByAlertResponse = rt.TypeOf<typeof GetRelatedCasesByAlertResponseRt>;
|
|
@ -6,28 +6,13 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseExternalServiceBasicRt } from '../../../api';
|
||||
import { ExternalServiceRt } from '../../domain/external_service/v1';
|
||||
import { CaseConnectorRt, ConnectorMappingsRt } from '../../domain/connector/v1';
|
||||
|
||||
const ActionConnectorResultRt = rt.intersection([
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
actionTypeId: rt.string,
|
||||
name: rt.string,
|
||||
isDeprecated: rt.boolean,
|
||||
isPreconfigured: rt.boolean,
|
||||
isSystemAction: rt.boolean,
|
||||
referencedByCount: rt.number,
|
||||
}),
|
||||
rt.exact(rt.partial({ config: rt.record(rt.string, rt.unknown), isMissingSecrets: rt.boolean })),
|
||||
]);
|
||||
|
||||
export const FindActionConnectorResponseRt = rt.array(ActionConnectorResultRt);
|
||||
|
||||
const PushDetailsRt = rt.strict({
|
||||
latestUserActionPushDate: rt.string,
|
||||
oldestUserActionPushDate: rt.string,
|
||||
externalService: CaseExternalServiceBasicRt,
|
||||
externalService: ExternalServiceRt,
|
||||
});
|
||||
|
||||
const CaseConnectorPushInfoRt = rt.intersection([
|
||||
|
@ -52,6 +37,21 @@ export const GetCaseConnectorsResponseRt = rt.record(
|
|||
])
|
||||
);
|
||||
|
||||
const ActionConnectorResultRt = rt.intersection([
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
actionTypeId: rt.string,
|
||||
name: rt.string,
|
||||
isDeprecated: rt.boolean,
|
||||
isPreconfigured: rt.boolean,
|
||||
isSystemAction: rt.boolean,
|
||||
referencedByCount: rt.number,
|
||||
}),
|
||||
rt.exact(rt.partial({ config: rt.record(rt.string, rt.unknown), isMissingSecrets: rt.boolean })),
|
||||
]);
|
||||
|
||||
export const FindActionConnectorResponseRt = rt.array(ActionConnectorResultRt);
|
||||
|
||||
export const ConnectorMappingResponseRt = rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 { ExternalServiceResponseRt } from './v1';
|
||||
|
||||
describe('ExternalServiceResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
title: 'case_title',
|
||||
id: 'basic-case-id',
|
||||
pushedDate: '2020-02-19T23:06:33.798Z',
|
||||
url: 'https://atlassian.com',
|
||||
comments: [
|
||||
{
|
||||
commentId: 'basic-comment-id',
|
||||
pushedDate: '2020-02-19T23:06:33.798Z',
|
||||
externalCommentId: 'external-comment-id',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalServiceResponseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalServiceResponseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from comments', () => {
|
||||
const query = ExternalServiceResponseRt.decode({
|
||||
...defaultRequest,
|
||||
comments: [{ ...defaultRequest.comments[0], foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
32
x-pack/plugins/cases/common/types/api/external_service/v1.ts
Normal file
32
x-pack/plugins/cases/common/types/api/external_service/v1.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
|
||||
export const ExternalServiceResponseRt = rt.intersection([
|
||||
rt.strict({
|
||||
title: rt.string,
|
||||
id: rt.string,
|
||||
pushedDate: rt.string,
|
||||
url: rt.string,
|
||||
}),
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
comments: rt.array(
|
||||
rt.intersection([
|
||||
rt.strict({
|
||||
commentId: rt.string,
|
||||
pushedDate: rt.string,
|
||||
}),
|
||||
rt.exact(rt.partial({ externalCommentId: rt.string })),
|
||||
])
|
||||
),
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
||||
export type ExternalServiceResponse = rt.TypeOf<typeof ExternalServiceResponseRt>;
|
|
@ -8,9 +8,21 @@
|
|||
// Latest
|
||||
export * from './configure/latest';
|
||||
export * from './user_action/latest';
|
||||
export * from './alert/latest';
|
||||
export * from './case/latest';
|
||||
export * from './external_service/latest';
|
||||
export * from './stats/latest';
|
||||
export * from './user/latest';
|
||||
export * from './connector/latest';
|
||||
export * from './attachment/latest';
|
||||
|
||||
// V1
|
||||
export * as configureApiV1 from './configure/v1';
|
||||
export * as userActionApiV1 from './user_action/v1';
|
||||
export * as alertApiV1 from './alert/v1';
|
||||
export * as statsApiV1 from './stats/v1';
|
||||
export * as caseApiV1 from './case/v1';
|
||||
export * as externalServiceApiV1 from './external_service/v1';
|
||||
export * as userApiV1 from './user/v1';
|
||||
export * as connectorApiV1 from './connector/v1';
|
||||
export * as attachmentApiV1 from './attachment/v1';
|
||||
|
|
8
x-pack/plugins/cases/common/types/api/stats/latest.ts
Normal file
8
x-pack/plugins/cases/common/types/api/stats/latest.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
|
@ -6,17 +6,6 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseStatuses } from '@kbn/cases-components/src/status/types';
|
||||
|
||||
export { CaseStatuses };
|
||||
|
||||
export const CaseStatusRt = rt.union([
|
||||
rt.literal(CaseStatuses.open),
|
||||
rt.literal(CaseStatuses['in-progress']),
|
||||
rt.literal(CaseStatuses.closed),
|
||||
]);
|
||||
|
||||
export const caseStatuses = Object.values(CaseStatuses);
|
||||
|
||||
export const CasesStatusResponseRt = rt.strict({
|
||||
count_open_cases: rt.number,
|
8
x-pack/plugins/cases/common/types/api/user/latest.ts
Normal file
8
x-pack/plugins/cases/common/types/api/user/latest.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
|
@ -5,137 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { set } from 'lodash';
|
||||
import { UserRt, UserWithProfileInfoRt, UsersRt, GetCaseUsersResponseRt } from './user';
|
||||
import { MAX_SUGGESTED_PROFILES } from '../../../constants';
|
||||
import { PathReporter } from 'io-ts/lib/PathReporter';
|
||||
import { GetCaseUsersResponseRt, SuggestUserProfilesRequestRt } from './v1';
|
||||
|
||||
describe('User', () => {
|
||||
describe('UserRt', () => {
|
||||
const defaultRequest = {
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
profile_uid: 'profile-uid-1',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserWithProfileInfoRt', () => {
|
||||
const defaultRequest = {
|
||||
uid: '1',
|
||||
avatar: {
|
||||
initials: 'SU',
|
||||
color: 'red',
|
||||
imageUrl: 'https://google.com/image1',
|
||||
},
|
||||
user: {
|
||||
username: 'user',
|
||||
email: 'some.user@google.com',
|
||||
full_name: 'Some Super User',
|
||||
},
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserWithProfileInfoRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it.each(['initials', 'color', 'imageUrl'])('does not returns an error if %s is null', (key) => {
|
||||
const reqWithNullImage = set(defaultRequest, `avatar.${key}`, null);
|
||||
const query = UserWithProfileInfoRt.decode(reqWithNullImage);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: reqWithNullImage,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserWithProfileInfoRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from avatar', () => {
|
||||
const query = UserWithProfileInfoRt.decode({
|
||||
...defaultRequest,
|
||||
avatar: { ...defaultRequest.avatar, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UsersRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
email: 'reporter_no_uid@elastic.co',
|
||||
full_name: 'Reporter No UID',
|
||||
username: 'reporter_no_uid',
|
||||
profile_uid: 'reporter-uid',
|
||||
},
|
||||
{
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UsersRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UsersRt.decode([
|
||||
{
|
||||
...defaultRequest[0],
|
||||
foo: 'bar',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [defaultRequest[0]],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GetCaseUsersResponseRt', () => {
|
||||
const defaultRequest = {
|
||||
assignees: [
|
||||
|
@ -271,4 +145,89 @@ describe('User', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserProfile', () => {
|
||||
describe('SuggestUserProfilesRequestRt', () => {
|
||||
const defaultRequest = {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('has only name and owner in request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('missing size parameter works correctly', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
name: 'di maria',
|
||||
owners: ['benfica'],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'di maria',
|
||||
owners: ['benfica'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
name: 'damaged_raccoon',
|
||||
owners: ['cases'],
|
||||
size: 5,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it(`does not accept size param bigger than ${MAX_SUGGESTED_PROFILES}`, () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
...defaultRequest,
|
||||
size: MAX_SUGGESTED_PROFILES + 1,
|
||||
});
|
||||
|
||||
expect(PathReporter.report(query)).toContain('The size field cannot be more than 10.');
|
||||
});
|
||||
|
||||
it('does not accept size param lower than 1', () => {
|
||||
const query = SuggestUserProfilesRequestRt.decode({
|
||||
...defaultRequest,
|
||||
size: 0,
|
||||
});
|
||||
|
||||
expect(PathReporter.report(query)).toContain('The size field cannot be less than 1.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,9 +6,22 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { MAX_SUGGESTED_PROFILES } from '../../constants';
|
||||
import { limitedNumberSchema } from '../../schema';
|
||||
import { MAX_SUGGESTED_PROFILES } from '../../../constants';
|
||||
import { limitedNumberSchema } from '../../../schema';
|
||||
import { UserWithProfileInfoRt } from '../../domain/user/v1';
|
||||
|
||||
export const GetCaseUsersResponseRt = rt.strict({
|
||||
assignees: rt.array(UserWithProfileInfoRt),
|
||||
unassignedUsers: rt.array(UserWithProfileInfoRt),
|
||||
participants: rt.array(UserWithProfileInfoRt),
|
||||
reporter: UserWithProfileInfoRt,
|
||||
});
|
||||
|
||||
export type GetCaseUsersResponse = rt.TypeOf<typeof GetCaseUsersResponseRt>;
|
||||
|
||||
/**
|
||||
* User Profiles
|
||||
*/
|
||||
export const SuggestUserProfilesRequestRt = rt.intersection([
|
||||
rt.strict({
|
||||
name: rt.string,
|
||||
|
@ -22,9 +35,3 @@ export const SuggestUserProfilesRequestRt = rt.intersection([
|
|||
]);
|
||||
|
||||
export type SuggestUserProfilesRequest = rt.TypeOf<typeof SuggestUserProfilesRequestRt>;
|
||||
|
||||
export const CaseUserProfileRt = rt.strict({
|
||||
uid: rt.string,
|
||||
});
|
||||
|
||||
export type CaseUserProfile = rt.TypeOf<typeof CaseUserProfileRt>;
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CommentType } from '../../../api';
|
||||
import { AttachmentType } from '../../domain/attachment/v1';
|
||||
import { UserActionTypes } from '../../domain/user_action/action/v1';
|
||||
import {
|
||||
CaseUserActionStatsResponseRt,
|
||||
|
@ -59,7 +59,7 @@ describe('User actions APIs', () => {
|
|||
payload: {
|
||||
comment: {
|
||||
comment: 'this is a sample comment',
|
||||
type: CommentType.user,
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
680
x-pack/plugins/cases/common/types/domain/attachment/v1.test.ts
Normal file
680
x-pack/plugins/cases/common/types/domain/attachment/v1.test.ts
Normal file
|
@ -0,0 +1,680 @@
|
|||
/*
|
||||
* 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 {
|
||||
AttachmentAttributesBasicRt,
|
||||
FileAttachmentMetadataRt,
|
||||
SingleFileAttachmentMetadataRt,
|
||||
AttachmentType,
|
||||
UserCommentAttachmentPayloadRt,
|
||||
AlertAttachmentPayloadRt,
|
||||
ActionsAttachmentPayloadRt,
|
||||
ExternalReferenceStorageType,
|
||||
ExternalReferenceAttachmentPayloadRt,
|
||||
PersistableStateAttachmentPayloadRt,
|
||||
AttachmentRt,
|
||||
UserCommentAttachmentRt,
|
||||
AlertAttachmentRt,
|
||||
ActionsAttachmentRt,
|
||||
ExternalReferenceAttachmentRt,
|
||||
PersistableStateAttachmentRt,
|
||||
AttachmentPatchAttributesRt,
|
||||
} from './v1';
|
||||
|
||||
describe('Attachments', () => {
|
||||
describe('Files', () => {
|
||||
describe('SingleFileAttachmentMetadataRt', () => {
|
||||
const defaultRequest = {
|
||||
created: '2020-02-19T23:06:33.798Z',
|
||||
extension: 'png',
|
||||
mimeType: 'image/png',
|
||||
name: 'my-super-cool-screenshot',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = SingleFileAttachmentMetadataRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = SingleFileAttachmentMetadataRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('FileAttachmentMetadataRt', () => {
|
||||
const defaultRequest = {
|
||||
created: '2020-02-19T23:06:33.798Z',
|
||||
extension: 'png',
|
||||
mimeType: 'image/png',
|
||||
name: 'my-super-cool-screenshot',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = FileAttachmentMetadataRt.decode({ files: [defaultRequest] });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
files: [
|
||||
{
|
||||
...defaultRequest,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = FileAttachmentMetadataRt.decode({
|
||||
files: [{ ...defaultRequest, foo: 'bar' }],
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
files: [
|
||||
{
|
||||
...defaultRequest,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentAttributesBasicRt', () => {
|
||||
const defaultRequest = {
|
||||
created_at: '2019-11-25T22:32:30.608Z',
|
||||
created_by: {
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
},
|
||||
owner: 'cases',
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentAttributesBasicRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentAttributesBasicRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserCommentAttachmentPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'This is a sample comment',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserCommentAttachmentPayloadRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserCommentAttachmentPayloadRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AlertAttachmentPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: AttachmentType.alert,
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AlertAttachmentPayloadRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AlertAttachmentPayloadRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from rule', () => {
|
||||
const query = AlertAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
rule: { id: 'rule-id-1', name: 'Awesome rule', foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ActionsAttachmentPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.actions,
|
||||
comment: 'I just isolated the host!',
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ActionsAttachmentPayloadRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ActionsAttachmentPayloadRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from actions', () => {
|
||||
const query = ActionsAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from targets', () => {
|
||||
const query = ActionsAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
foo: 'bar',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ExternalReferenceAttachmentPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: { test_foo: 'foo' },
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalReferenceAttachmentPayloadRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalReferenceAttachmentPayloadRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from externalReferenceStorage', () => {
|
||||
const query = ExternalReferenceAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.elasticSearchDoc,
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from externalReferenceStorage with soType', () => {
|
||||
const query = ExternalReferenceAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.savedObject,
|
||||
soType: 'awesome',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
...defaultRequest,
|
||||
externalReferenceStorage: {
|
||||
type: ExternalReferenceStorageType.savedObject,
|
||||
soType: 'awesome',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PersistableStateAttachmentPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.persistableState,
|
||||
persistableStateAttachmentState: { test_foo: 'foo' },
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = PersistableStateAttachmentPayloadRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = PersistableStateAttachmentPayloadRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from persistableStateAttachmentState', () => {
|
||||
const query = PersistableStateAttachmentPayloadRt.decode({
|
||||
...defaultRequest,
|
||||
persistableStateAttachmentState: { test_foo: 'foo', foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
...defaultRequest,
|
||||
persistableStateAttachmentState: { test_foo: 'foo', foo: 'bar' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserCommentAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserCommentAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserCommentAttachmentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AlertAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
alertId: 'alert-id-1',
|
||||
index: 'alert-index-1',
|
||||
type: AttachmentType.alert,
|
||||
id: 'alert-comment-id',
|
||||
owner: 'cases',
|
||||
rule: {
|
||||
id: 'rule-id-1',
|
||||
name: 'Awesome rule',
|
||||
},
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AlertAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AlertAttachmentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from created_by', () => {
|
||||
const query = AlertAttachmentRt.decode({
|
||||
...defaultRequest,
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ActionsAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.actions,
|
||||
comment: 'I just isolated the host!',
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ActionsAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ActionsAttachmentRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ExternalReferenceAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.externalReference,
|
||||
externalReferenceId: 'my-id',
|
||||
externalReferenceStorage: { type: ExternalReferenceStorageType.elasticSearchDoc },
|
||||
externalReferenceAttachmentTypeId: '.test',
|
||||
externalReferenceMetadata: { test_foo: 'foo' },
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalReferenceAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalReferenceAttachmentRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('PersistableStateAttachmentRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.persistableState,
|
||||
persistableStateAttachmentState: { test_foo: 'foo' },
|
||||
persistableStateAttachmentTypeId: '.test',
|
||||
owner: 'cases',
|
||||
id: 'basic-comment-id',
|
||||
version: 'WzQ3LDFc',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = PersistableStateAttachmentRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = PersistableStateAttachmentRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AttachmentPatchAttributesRt', () => {
|
||||
const defaultRequest = {
|
||||
type: AttachmentType.actions,
|
||||
actions: {
|
||||
targets: [
|
||||
{
|
||||
hostname: 'host1',
|
||||
endpointId: '001',
|
||||
},
|
||||
],
|
||||
type: 'isolate',
|
||||
},
|
||||
owner: 'cases',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = AttachmentPatchAttributesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = AttachmentPatchAttributesRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
348
x-pack/plugins/cases/common/types/domain/attachment/v1.ts
Normal file
348
x-pack/plugins/cases/common/types/domain/attachment/v1.ts
Normal file
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import { jsonValueRt } from '../../../api';
|
||||
import { UserRt } from '../user/v1';
|
||||
|
||||
/**
|
||||
* Files
|
||||
*/
|
||||
export const SingleFileAttachmentMetadataRt = rt.strict({
|
||||
name: rt.string,
|
||||
extension: rt.string,
|
||||
mimeType: rt.string,
|
||||
created: rt.string,
|
||||
});
|
||||
|
||||
export const FileAttachmentMetadataRt = rt.strict({
|
||||
files: rt.array(SingleFileAttachmentMetadataRt),
|
||||
});
|
||||
|
||||
export type FileAttachmentMetadata = rt.TypeOf<typeof FileAttachmentMetadataRt>;
|
||||
|
||||
export const AttachmentAttributesBasicRt = rt.strict({
|
||||
created_at: rt.string,
|
||||
created_by: UserRt,
|
||||
owner: rt.string,
|
||||
pushed_at: rt.union([rt.string, rt.null]),
|
||||
pushed_by: rt.union([UserRt, rt.null]),
|
||||
updated_at: rt.union([rt.string, rt.null]),
|
||||
updated_by: rt.union([UserRt, rt.null]),
|
||||
});
|
||||
|
||||
/**
|
||||
* User comment
|
||||
*/
|
||||
|
||||
export enum AttachmentType {
|
||||
user = 'user',
|
||||
alert = 'alert',
|
||||
actions = 'actions',
|
||||
externalReference = 'externalReference',
|
||||
persistableState = 'persistableState',
|
||||
}
|
||||
|
||||
export const UserCommentAttachmentPayloadRt = rt.strict({
|
||||
comment: rt.string,
|
||||
type: rt.literal(AttachmentType.user),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
const UserCommentAttachmentAttributesRt = rt.intersection([
|
||||
UserCommentAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const UserCommentAttachmentRt = rt.intersection([
|
||||
UserCommentAttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type UserCommentAttachmentPayload = rt.TypeOf<typeof UserCommentAttachmentPayloadRt>;
|
||||
export type UserCommentAttachmentAttributes = rt.TypeOf<typeof UserCommentAttachmentAttributesRt>;
|
||||
export type UserCommentAttachment = rt.TypeOf<typeof UserCommentAttachmentRt>;
|
||||
|
||||
/**
|
||||
* Alerts
|
||||
*/
|
||||
|
||||
export const AlertAttachmentPayloadRt = rt.strict({
|
||||
type: rt.literal(AttachmentType.alert),
|
||||
alertId: rt.union([rt.array(rt.string), rt.string]),
|
||||
index: rt.union([rt.array(rt.string), rt.string]),
|
||||
rule: rt.strict({
|
||||
id: rt.union([rt.string, rt.null]),
|
||||
name: rt.union([rt.string, rt.null]),
|
||||
}),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
export const AlertAttachmentAttributesRt = rt.intersection([
|
||||
AlertAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const AlertAttachmentRt = rt.intersection([
|
||||
AlertAttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type AlertAttachmentPayload = rt.TypeOf<typeof AlertAttachmentPayloadRt>;
|
||||
export type AlertAttachmentAttributes = rt.TypeOf<typeof AlertAttachmentAttributesRt>;
|
||||
export type AlertAttachment = rt.TypeOf<typeof AlertAttachmentRt>;
|
||||
|
||||
/**
|
||||
* Actions
|
||||
*/
|
||||
|
||||
export enum IsolateHostActionType {
|
||||
isolate = 'isolate',
|
||||
unisolate = 'unisolate',
|
||||
}
|
||||
|
||||
export const ActionsAttachmentPayloadRt = rt.strict({
|
||||
type: rt.literal(AttachmentType.actions),
|
||||
comment: rt.string,
|
||||
actions: rt.strict({
|
||||
targets: rt.array(
|
||||
rt.strict({
|
||||
hostname: rt.string,
|
||||
endpointId: rt.string,
|
||||
})
|
||||
),
|
||||
type: rt.string,
|
||||
}),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
const ActionsAttachmentAttributesRt = rt.intersection([
|
||||
ActionsAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const ActionsAttachmentRt = rt.intersection([
|
||||
ActionsAttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type ActionsAttachmentPayload = rt.TypeOf<typeof ActionsAttachmentPayloadRt>;
|
||||
export type ActionsAttachmentAttributes = rt.TypeOf<typeof ActionsAttachmentAttributesRt>;
|
||||
export type ActionsAttachment = rt.TypeOf<typeof ActionsAttachmentRt>;
|
||||
|
||||
/**
|
||||
* External reference
|
||||
*/
|
||||
|
||||
export enum ExternalReferenceStorageType {
|
||||
savedObject = 'savedObject',
|
||||
elasticSearchDoc = 'elasticSearchDoc',
|
||||
}
|
||||
|
||||
const ExternalReferenceStorageNoSORt = rt.strict({
|
||||
type: rt.literal(ExternalReferenceStorageType.elasticSearchDoc),
|
||||
});
|
||||
|
||||
const ExternalReferenceStorageSORt = rt.strict({
|
||||
type: rt.literal(ExternalReferenceStorageType.savedObject),
|
||||
soType: rt.string,
|
||||
});
|
||||
|
||||
const ExternalReferenceBaseAttachmentPayloadRt = rt.strict({
|
||||
externalReferenceAttachmentTypeId: rt.string,
|
||||
externalReferenceMetadata: rt.union([rt.null, rt.record(rt.string, jsonValueRt)]),
|
||||
type: rt.literal(AttachmentType.externalReference),
|
||||
owner: rt.string,
|
||||
});
|
||||
|
||||
export const ExternalReferenceNoSOAttachmentPayloadRt = rt.strict({
|
||||
...ExternalReferenceBaseAttachmentPayloadRt.type.props,
|
||||
externalReferenceId: rt.string,
|
||||
externalReferenceStorage: ExternalReferenceStorageNoSORt,
|
||||
});
|
||||
|
||||
export const ExternalReferenceSOAttachmentPayloadRt = rt.strict({
|
||||
...ExternalReferenceBaseAttachmentPayloadRt.type.props,
|
||||
externalReferenceId: rt.string,
|
||||
externalReferenceStorage: ExternalReferenceStorageSORt,
|
||||
});
|
||||
|
||||
// externalReferenceId is missing.
|
||||
export const ExternalReferenceSOWithoutRefsAttachmentPayloadRt = rt.strict({
|
||||
...ExternalReferenceBaseAttachmentPayloadRt.type.props,
|
||||
externalReferenceStorage: ExternalReferenceStorageSORt,
|
||||
});
|
||||
|
||||
export const ExternalReferenceAttachmentPayloadRt = rt.union([
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
ExternalReferenceSOAttachmentPayloadRt,
|
||||
]);
|
||||
|
||||
export const ExternalReferenceWithoutRefsAttachmentPayloadRt = rt.union([
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
ExternalReferenceSOWithoutRefsAttachmentPayloadRt,
|
||||
]);
|
||||
|
||||
const ExternalReferenceAttachmentAttributesRt = rt.intersection([
|
||||
ExternalReferenceAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const ExternalReferenceWithoutRefsAttachmentAttributesRt = rt.intersection([
|
||||
ExternalReferenceWithoutRefsAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const ExternalReferenceNoSOAttachmentAttributesRt = rt.intersection([
|
||||
ExternalReferenceNoSOAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
const ExternalReferenceSOAttachmentAttributesRt = rt.intersection([
|
||||
ExternalReferenceSOAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const ExternalReferenceAttachmentRt = rt.intersection([
|
||||
ExternalReferenceAttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type ExternalReferenceAttachmentPayload = rt.TypeOf<
|
||||
typeof ExternalReferenceAttachmentPayloadRt
|
||||
>;
|
||||
|
||||
export type ExternalReferenceSOAttachmentPayload = rt.TypeOf<
|
||||
typeof ExternalReferenceSOAttachmentPayloadRt
|
||||
>;
|
||||
export type ExternalReferenceNoSOAttachmentPayload = rt.TypeOf<
|
||||
typeof ExternalReferenceNoSOAttachmentPayloadRt
|
||||
>;
|
||||
|
||||
export type ExternalReferenceAttachmentAttributes = rt.TypeOf<
|
||||
typeof ExternalReferenceAttachmentAttributesRt
|
||||
>;
|
||||
|
||||
export type ExternalReferenceSOAttachmentAttributes = rt.TypeOf<
|
||||
typeof ExternalReferenceSOAttachmentAttributesRt
|
||||
>;
|
||||
|
||||
export type ExternalReferenceNoSOAttachmentAttributes = rt.TypeOf<
|
||||
typeof ExternalReferenceNoSOAttachmentAttributesRt
|
||||
>;
|
||||
|
||||
export type ExternalReferenceWithoutRefsAttachmentPayload = rt.TypeOf<
|
||||
typeof ExternalReferenceWithoutRefsAttachmentPayloadRt
|
||||
>;
|
||||
export type ExternalReferenceAttachment = rt.TypeOf<typeof ExternalReferenceAttachmentRt>;
|
||||
|
||||
/**
|
||||
* Persistable state
|
||||
*/
|
||||
|
||||
export const PersistableStateAttachmentPayloadRt = rt.strict({
|
||||
type: rt.literal(AttachmentType.persistableState),
|
||||
owner: rt.string,
|
||||
persistableStateAttachmentTypeId: rt.string,
|
||||
persistableStateAttachmentState: rt.record(rt.string, jsonValueRt),
|
||||
});
|
||||
|
||||
const PersistableStateAttachmentAttributesRt = rt.intersection([
|
||||
PersistableStateAttachmentPayloadRt,
|
||||
AttachmentAttributesBasicRt,
|
||||
]);
|
||||
|
||||
export const PersistableStateAttachmentRt = rt.intersection([
|
||||
PersistableStateAttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export type PersistableStateAttachmentPayload = rt.TypeOf<
|
||||
typeof PersistableStateAttachmentPayloadRt
|
||||
>;
|
||||
export type PersistableStateAttachment = rt.TypeOf<typeof PersistableStateAttachmentRt>;
|
||||
export type PersistableStateAttachmentAttributes = rt.TypeOf<
|
||||
typeof PersistableStateAttachmentAttributesRt
|
||||
>;
|
||||
|
||||
/**
|
||||
* Common
|
||||
*/
|
||||
|
||||
export const AttachmentAttributesRt = rt.union([
|
||||
UserCommentAttachmentAttributesRt,
|
||||
AlertAttachmentAttributesRt,
|
||||
ActionsAttachmentAttributesRt,
|
||||
ExternalReferenceAttachmentAttributesRt,
|
||||
PersistableStateAttachmentAttributesRt,
|
||||
]);
|
||||
|
||||
const AttachmentAttributesNoSORt = rt.union([
|
||||
UserCommentAttachmentAttributesRt,
|
||||
AlertAttachmentAttributesRt,
|
||||
ActionsAttachmentAttributesRt,
|
||||
ExternalReferenceNoSOAttachmentAttributesRt,
|
||||
PersistableStateAttachmentAttributesRt,
|
||||
]);
|
||||
|
||||
const AttachmentAttributesWithoutRefsRt = rt.union([
|
||||
UserCommentAttachmentAttributesRt,
|
||||
AlertAttachmentAttributesRt,
|
||||
ActionsAttachmentAttributesRt,
|
||||
ExternalReferenceWithoutRefsAttachmentAttributesRt,
|
||||
PersistableStateAttachmentAttributesRt,
|
||||
]);
|
||||
|
||||
export const AttachmentRt = rt.intersection([
|
||||
AttachmentAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
version: rt.string,
|
||||
}),
|
||||
]);
|
||||
|
||||
export const AttachmentsRt = rt.array(AttachmentRt);
|
||||
|
||||
/**
|
||||
* This type is used by the CaseService.
|
||||
* Because the type for the attributes of savedObjectClient update function is Partial<T>
|
||||
* we need to make all of our attributes partial too.
|
||||
* We ensure that partial updates of CommentContext is not going to happen inside the patch comment route.
|
||||
*/
|
||||
export const AttachmentPatchAttributesRt = rt.intersection([
|
||||
rt.union([
|
||||
rt.exact(rt.partial(UserCommentAttachmentPayloadRt.type.props)),
|
||||
rt.exact(rt.partial(AlertAttachmentPayloadRt.type.props)),
|
||||
rt.exact(rt.partial(ActionsAttachmentPayloadRt.type.props)),
|
||||
rt.exact(rt.partial(ExternalReferenceNoSOAttachmentPayloadRt.type.props)),
|
||||
rt.exact(rt.partial(ExternalReferenceSOAttachmentPayloadRt.type.props)),
|
||||
rt.exact(rt.partial(PersistableStateAttachmentPayloadRt.type.props)),
|
||||
]),
|
||||
rt.exact(rt.partial(AttachmentAttributesBasicRt.type.props)),
|
||||
]);
|
||||
|
||||
export type AttachmentAttributes = rt.TypeOf<typeof AttachmentAttributesRt>;
|
||||
export type AttachmentAttributesNoSO = rt.TypeOf<typeof AttachmentAttributesNoSORt>;
|
||||
export type AttachmentAttributesWithoutRefs = rt.TypeOf<typeof AttachmentAttributesWithoutRefsRt>;
|
||||
export type AttachmentPatchAttributes = rt.TypeOf<typeof AttachmentPatchAttributesRt>;
|
||||
export type Attachment = rt.TypeOf<typeof AttachmentRt>;
|
||||
export type Attachments = rt.TypeOf<typeof AttachmentsRt>;
|
8
x-pack/plugins/cases/common/types/domain/case/latest.ts
Normal file
8
x-pack/plugins/cases/common/types/domain/case/latest.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
242
x-pack/plugins/cases/common/types/domain/case/v1.test.ts
Normal file
242
x-pack/plugins/cases/common/types/domain/case/v1.test.ts
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* 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 { AttachmentType } from '../attachment/v1';
|
||||
import { ConnectorTypes } from '../connector/v1';
|
||||
import {
|
||||
CaseAttributesRt,
|
||||
CaseSettingsRt,
|
||||
CaseSeverity,
|
||||
CasesRt,
|
||||
CaseStatuses,
|
||||
RelatedCaseRt,
|
||||
} from './v1';
|
||||
|
||||
const basicCase = {
|
||||
owner: 'cases',
|
||||
closed_at: null,
|
||||
closed_by: null,
|
||||
id: 'basic-case-id',
|
||||
comments: [
|
||||
{
|
||||
comment: 'Solve this fast!',
|
||||
type: AttachmentType.user,
|
||||
id: 'basic-comment-id',
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
owner: 'cases',
|
||||
pushed_at: null,
|
||||
pushed_by: null,
|
||||
updated_at: null,
|
||||
updated_by: null,
|
||||
version: 'WzQ3LDFc',
|
||||
},
|
||||
],
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
connector: {
|
||||
id: 'none',
|
||||
name: 'My Connector',
|
||||
type: ConnectorTypes.none,
|
||||
fields: null,
|
||||
},
|
||||
description: 'Security banana Issue',
|
||||
severity: CaseSeverity.LOW,
|
||||
duration: null,
|
||||
external_service: null,
|
||||
status: CaseStatuses.open,
|
||||
tags: ['coke', 'pepsi'],
|
||||
title: 'Another horrible breach!!',
|
||||
totalComment: 1,
|
||||
totalAlerts: 0,
|
||||
updated_at: '2020-02-20T15:02:57.995Z',
|
||||
updated_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
version: 'WzQ3LDFd',
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
// damaged_raccoon uid
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
category: null,
|
||||
};
|
||||
|
||||
describe('RelatedCaseRt', () => {
|
||||
const defaultRequest = {
|
||||
id: 'basic-case-id',
|
||||
title: 'basic-case-title',
|
||||
description: 'this is a simple description',
|
||||
status: CaseStatuses.open,
|
||||
createdAt: '2023-01-17T09:46:29.813Z',
|
||||
totals: {
|
||||
alerts: 5,
|
||||
userComments: 2,
|
||||
},
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = RelatedCaseRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = RelatedCaseRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from totals', () => {
|
||||
const query = RelatedCaseRt.decode({
|
||||
...defaultRequest,
|
||||
totals: { ...defaultRequest.totals, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('SettingsRt', () => {
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseSettingsRt.decode({ syncAlerts: true });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { syncAlerts: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseSettingsRt.decode({ syncAlerts: false, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: { syncAlerts: false },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CaseAttributesRt', () => {
|
||||
const defaultRequest = {
|
||||
description: 'A description',
|
||||
status: CaseStatuses.open,
|
||||
tags: ['new', 'case'],
|
||||
title: 'My new case',
|
||||
connector: {
|
||||
id: '123',
|
||||
name: 'My connector',
|
||||
type: ConnectorTypes.jira,
|
||||
fields: { issueType: 'Task', priority: 'High', parent: null },
|
||||
},
|
||||
settings: {
|
||||
syncAlerts: true,
|
||||
},
|
||||
owner: 'cases',
|
||||
severity: CaseSeverity.LOW,
|
||||
assignees: [{ uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0' }],
|
||||
duration: null,
|
||||
closed_at: null,
|
||||
closed_by: null,
|
||||
created_at: '2020-02-19T23:06:33.798Z',
|
||||
created_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
external_service: null,
|
||||
updated_at: '2020-02-20T15:02:57.995Z',
|
||||
updated_by: null,
|
||||
category: null,
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseAttributesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseAttributesRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from connector', () => {
|
||||
const query = CaseAttributesRt.decode({
|
||||
...defaultRequest,
|
||||
connector: { ...defaultRequest.connector, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from created_by', () => {
|
||||
const query = CaseAttributesRt.decode({
|
||||
...defaultRequest,
|
||||
created_by: { ...defaultRequest.created_by, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('CasesRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
...basicCase,
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CasesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CasesRt.decode([{ ...defaultRequest[0], foo: 'bar' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
147
x-pack/plugins/cases/common/types/domain/case/v1.ts
Normal file
147
x-pack/plugins/cases/common/types/domain/case/v1.ts
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import { CaseStatuses } from '@kbn/cases-components/src/status/types';
|
||||
import { ExternalServiceRt } from '../external_service/v1';
|
||||
import { CaseAssigneesRt, UserRt } from '../user/v1';
|
||||
import { CaseConnectorRt } from '../connector/v1';
|
||||
import { AttachmentRt } from '../attachment/v1';
|
||||
|
||||
export { CaseStatuses };
|
||||
|
||||
/**
|
||||
* Status
|
||||
*/
|
||||
export const CaseStatusRt = rt.union([
|
||||
rt.literal(CaseStatuses.open),
|
||||
rt.literal(CaseStatuses['in-progress']),
|
||||
rt.literal(CaseStatuses.closed),
|
||||
]);
|
||||
|
||||
export const caseStatuses = Object.values(CaseStatuses);
|
||||
|
||||
/**
|
||||
* Severity
|
||||
*/
|
||||
|
||||
export enum CaseSeverity {
|
||||
LOW = 'low',
|
||||
MEDIUM = 'medium',
|
||||
HIGH = 'high',
|
||||
CRITICAL = 'critical',
|
||||
}
|
||||
|
||||
export const CaseSeverityRt = rt.union([
|
||||
rt.literal(CaseSeverity.LOW),
|
||||
rt.literal(CaseSeverity.MEDIUM),
|
||||
rt.literal(CaseSeverity.HIGH),
|
||||
rt.literal(CaseSeverity.CRITICAL),
|
||||
]);
|
||||
|
||||
/**
|
||||
* Case
|
||||
*/
|
||||
|
||||
export const CaseSettingsRt = rt.strict({
|
||||
syncAlerts: rt.boolean,
|
||||
});
|
||||
|
||||
const CaseBasicRt = rt.strict({
|
||||
/**
|
||||
* The description of the case
|
||||
*/
|
||||
description: rt.string,
|
||||
/**
|
||||
* The current status of the case (open, closed, in-progress)
|
||||
*/
|
||||
status: CaseStatusRt,
|
||||
/**
|
||||
* The identifying strings for filter a case
|
||||
*/
|
||||
tags: rt.array(rt.string),
|
||||
/**
|
||||
* The title of a case
|
||||
*/
|
||||
title: rt.string,
|
||||
/**
|
||||
* The external system that the case can be synced with
|
||||
*/
|
||||
connector: CaseConnectorRt,
|
||||
/**
|
||||
* The alert sync settings
|
||||
*/
|
||||
settings: CaseSettingsRt,
|
||||
/**
|
||||
* The plugin owner of the case
|
||||
*/
|
||||
owner: rt.string,
|
||||
/**
|
||||
* The severity of the case
|
||||
*/
|
||||
severity: CaseSeverityRt,
|
||||
/**
|
||||
* The users assigned to this case
|
||||
*/
|
||||
assignees: CaseAssigneesRt,
|
||||
/**
|
||||
* The category of the case.
|
||||
*/
|
||||
category: rt.union([rt.string, rt.null]),
|
||||
});
|
||||
|
||||
export const CaseAttributesRt = rt.intersection([
|
||||
CaseBasicRt,
|
||||
rt.strict({
|
||||
duration: rt.union([rt.number, rt.null]),
|
||||
closed_at: rt.union([rt.string, rt.null]),
|
||||
closed_by: rt.union([UserRt, rt.null]),
|
||||
created_at: rt.string,
|
||||
created_by: UserRt,
|
||||
external_service: rt.union([ExternalServiceRt, rt.null]),
|
||||
updated_at: rt.union([rt.string, rt.null]),
|
||||
updated_by: rt.union([UserRt, rt.null]),
|
||||
}),
|
||||
]);
|
||||
|
||||
export const CaseRt = rt.intersection([
|
||||
CaseAttributesRt,
|
||||
rt.strict({
|
||||
id: rt.string,
|
||||
totalComment: rt.number,
|
||||
totalAlerts: rt.number,
|
||||
version: rt.string,
|
||||
}),
|
||||
rt.exact(
|
||||
rt.partial({
|
||||
comments: rt.array(AttachmentRt),
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
||||
export const CasesRt = rt.array(CaseRt);
|
||||
|
||||
export const AttachmentTotalsRt = rt.strict({
|
||||
alerts: rt.number,
|
||||
userComments: rt.number,
|
||||
});
|
||||
|
||||
export const RelatedCaseRt = rt.strict({
|
||||
id: rt.string,
|
||||
title: rt.string,
|
||||
description: rt.string,
|
||||
status: CaseStatusRt,
|
||||
createdAt: rt.string,
|
||||
totals: AttachmentTotalsRt,
|
||||
});
|
||||
|
||||
export type Case = rt.TypeOf<typeof CaseRt>;
|
||||
export type Cases = rt.TypeOf<typeof CasesRt>;
|
||||
export type CaseAttributes = rt.TypeOf<typeof CaseAttributesRt>;
|
||||
export type CaseSettings = rt.TypeOf<typeof CaseSettingsRt>;
|
||||
export type RelatedCase = rt.TypeOf<typeof RelatedCaseRt>;
|
||||
export type AttachmentTotals = rt.TypeOf<typeof AttachmentTotalsRt>;
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { UserRt } from '../../../api';
|
||||
import { CaseConnectorRt, ConnectorMappingsRt } from '../connector/v1';
|
||||
import { UserRt } from '../user/v1';
|
||||
|
||||
const ClosureTypeRt = rt.union([rt.literal('close-by-user'), rt.literal('close-by-pushing')]);
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 { ExternalServiceRt } from './v1';
|
||||
|
||||
describe('ExternalServiceRt', () => {
|
||||
const defaultRequest = {
|
||||
connector_id: 'servicenow-1',
|
||||
connector_name: 'My SN connector',
|
||||
external_id: 'external_id',
|
||||
external_title: 'external title',
|
||||
external_url: 'basicPush.com',
|
||||
pushed_at: '2023-01-17T09:46:29.813Z',
|
||||
pushed_by: {
|
||||
full_name: 'Leslie Knope',
|
||||
username: 'lknope',
|
||||
email: 'leslie.knope@elastic.co',
|
||||
},
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = ExternalServiceRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = ExternalServiceRt.decode({ ...defaultRequest, foo: 'bar' });
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from pushed_by', () => {
|
||||
const query = ExternalServiceRt.decode({
|
||||
...defaultRequest,
|
||||
pushed_by: { ...defaultRequest.pushed_by, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 * as rt from 'io-ts';
|
||||
import { UserRt } from '../user/v1';
|
||||
|
||||
/**
|
||||
* This represents the push to service UserAction. It lacks the connector_id because that is stored in a different field
|
||||
* within the user action object in the API response.
|
||||
*/
|
||||
export const ExternalServiceBasicRt = rt.strict({
|
||||
connector_name: rt.string,
|
||||
external_id: rt.string,
|
||||
external_title: rt.string,
|
||||
external_url: rt.string,
|
||||
pushed_at: rt.string,
|
||||
pushed_by: UserRt,
|
||||
});
|
||||
|
||||
export const ExternalServiceRt = rt.intersection([
|
||||
rt.strict({
|
||||
connector_id: rt.string,
|
||||
}),
|
||||
ExternalServiceBasicRt,
|
||||
]);
|
||||
|
||||
export type ExternalService = rt.TypeOf<typeof ExternalServiceRt>;
|
|
@ -8,9 +8,17 @@
|
|||
// Latest
|
||||
export * from './configure/latest';
|
||||
export * from './user_action/latest';
|
||||
export * from './external_service/latest';
|
||||
export * from './case/latest';
|
||||
export * from './user/latest';
|
||||
export * from './connector/latest';
|
||||
export * from './attachment/latest';
|
||||
|
||||
// V1
|
||||
export * as configureDomainV1 from './configure/v1';
|
||||
export * as userActionDomainV1 from './user_action/v1';
|
||||
export * as externalServiceDomainV1 from './external_service/v1';
|
||||
export * as caseDomainV1 from './case/v1';
|
||||
export * as userDomainV1 from './user/v1';
|
||||
export * as connectorDomainV1 from './connector/v1';
|
||||
export * as attachmentDomainV1 from './attachment/v1';
|
||||
|
|
8
x-pack/plugins/cases/common/types/domain/user/latest.ts
Normal file
8
x-pack/plugins/cases/common/types/domain/user/latest.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from './v1';
|
202
x-pack/plugins/cases/common/types/domain/user/v1.test.ts
Normal file
202
x-pack/plugins/cases/common/types/domain/user/v1.test.ts
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* 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 { set } from 'lodash';
|
||||
import { UserRt, UserWithProfileInfoRt, UsersRt, CaseUserProfileRt, CaseAssigneesRt } from './v1';
|
||||
|
||||
describe('User', () => {
|
||||
describe('UserRt', () => {
|
||||
const defaultRequest = {
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
profile_uid: 'profile-uid-1',
|
||||
};
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserWithProfileInfoRt', () => {
|
||||
const defaultRequest = {
|
||||
uid: '1',
|
||||
avatar: {
|
||||
initials: 'SU',
|
||||
color: 'red',
|
||||
imageUrl: 'https://google.com/image1',
|
||||
},
|
||||
user: {
|
||||
username: 'user',
|
||||
email: 'some.user@google.com',
|
||||
full_name: 'Some Super User',
|
||||
},
|
||||
};
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UserWithProfileInfoRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it.each(['initials', 'color', 'imageUrl'])('does not returns an error if %s is null', (key) => {
|
||||
const reqWithNullImage = set(defaultRequest, `avatar.${key}`, null);
|
||||
const query = UserWithProfileInfoRt.decode(reqWithNullImage);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: reqWithNullImage,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UserWithProfileInfoRt.decode({
|
||||
...defaultRequest,
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from avatar', () => {
|
||||
const query = UserWithProfileInfoRt.decode({
|
||||
...defaultRequest,
|
||||
avatar: { ...defaultRequest.avatar, foo: 'bar' },
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UsersRt', () => {
|
||||
const defaultRequest = [
|
||||
{
|
||||
email: 'reporter_no_uid@elastic.co',
|
||||
full_name: 'Reporter No UID',
|
||||
username: 'reporter_no_uid',
|
||||
profile_uid: 'reporter-uid',
|
||||
},
|
||||
{
|
||||
full_name: 'elastic',
|
||||
email: 'testemail@elastic.co',
|
||||
username: 'elastic',
|
||||
},
|
||||
];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = UsersRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = UsersRt.decode([
|
||||
{
|
||||
...defaultRequest[0],
|
||||
foo: 'bar',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [defaultRequest[0]],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserProfile', () => {
|
||||
describe('CaseUserProfileRt', () => {
|
||||
it('has expected attributes in response', () => {
|
||||
const query = CaseUserProfileRt.decode({
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from response', () => {
|
||||
const query = CaseUserProfileRt.decode({
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
foo: 'bar',
|
||||
});
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: {
|
||||
uid: 'u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Assignee', () => {
|
||||
describe('CaseAssigneesRt', () => {
|
||||
const defaultRequest = [{ uid: '1' }, { uid: '2' }];
|
||||
|
||||
it('has expected attributes in request', () => {
|
||||
const query = CaseAssigneesRt.decode(defaultRequest);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: defaultRequest,
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from request', () => {
|
||||
const query = CaseAssigneesRt.decode([{ ...defaultRequest[0], foo: 'bar' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [defaultRequest[0]],
|
||||
});
|
||||
});
|
||||
|
||||
it('removes foo:bar attributes from assignees', () => {
|
||||
const query = CaseAssigneesRt.decode([{ uid: '1', foo: 'bar' }, { uid: '2' }]);
|
||||
|
||||
expect(query).toStrictEqual({
|
||||
_tag: 'Right',
|
||||
right: [{ uid: '1' }, { uid: '2' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -41,11 +41,14 @@ export const UsersRt = rt.array(UserRt);
|
|||
export type User = rt.TypeOf<typeof UserRt>;
|
||||
export type UserWithProfileInfo = rt.TypeOf<typeof UserWithProfileInfoRt>;
|
||||
|
||||
export const GetCaseUsersResponseRt = rt.strict({
|
||||
assignees: rt.array(UserWithProfileInfoRt),
|
||||
unassignedUsers: rt.array(UserWithProfileInfoRt),
|
||||
participants: rt.array(UserWithProfileInfoRt),
|
||||
reporter: UserWithProfileInfoRt,
|
||||
export const CaseUserProfileRt = rt.strict({
|
||||
uid: rt.string,
|
||||
});
|
||||
|
||||
export type GetCaseUsersResponse = rt.TypeOf<typeof GetCaseUsersResponseRt>;
|
||||
export type CaseUserProfile = rt.TypeOf<typeof CaseUserProfileRt>;
|
||||
|
||||
/**
|
||||
* Assignees
|
||||
*/
|
||||
export const CaseAssigneesRt = rt.array(CaseUserProfileRt);
|
||||
export type CaseAssignees = rt.TypeOf<typeof CaseAssigneesRt>;
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseAssigneesRt } from '../../../../api';
|
||||
import { CaseAssigneesRt } from '../../user/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const AssigneesUserActionPayloadRt = rt.strict({ assignees: CaseAssigneesRt });
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CommentType } from '../../../../api';
|
||||
import { AttachmentType } from '../../attachment/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
import { CommentUserActionPayloadRt, CommentUserActionRt } from './v1';
|
||||
|
||||
describe('Comment', () => {
|
||||
describe('Attachment', () => {
|
||||
describe('CommentUserActionPayloadRt', () => {
|
||||
const defaultRequest = {
|
||||
comment: {
|
||||
comment: 'this is a sample comment',
|
||||
type: CommentType.user,
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ describe('Comment', () => {
|
|||
payload: {
|
||||
comment: {
|
||||
comment: 'this is a sample comment',
|
||||
type: CommentType.user,
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CommentRequestRt, CommentRequestWithoutRefsRt } from '../../../../api';
|
||||
import { AttachmentRequestRt, AttachmentRequestWithoutRefsRt } from '../../../api/attachment/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const CommentUserActionPayloadRt = rt.strict({ comment: CommentRequestRt });
|
||||
export const CommentUserActionPayloadRt = rt.strict({ comment: AttachmentRequestRt });
|
||||
export const CommentUserActionPayloadWithoutIdsRt = rt.strict({
|
||||
comment: CommentRequestWithoutRefsRt,
|
||||
comment: AttachmentRequestWithoutRefsRt,
|
||||
});
|
||||
|
||||
export const CommentUserActionRt = rt.strict({
|
||||
|
|
|
@ -6,15 +6,15 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseExternalServiceBasicRt, CaseUserActionExternalServiceRt } from '../../../../api';
|
||||
import { ExternalServiceBasicRt, ExternalServiceRt } from '../../external_service/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const PushedUserActionPayloadWithoutConnectorIdRt = rt.strict({
|
||||
externalService: CaseUserActionExternalServiceRt,
|
||||
externalService: ExternalServiceBasicRt,
|
||||
});
|
||||
|
||||
export const PushedUserActionPayloadRt = rt.strict({
|
||||
externalService: CaseExternalServiceBasicRt,
|
||||
externalService: ExternalServiceRt,
|
||||
});
|
||||
|
||||
export const PushedUserActionWithoutConnectorIdRt = rt.strict({
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { SettingsRt } from '../../../../api';
|
||||
import { CaseSettingsRt } from '../../case/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const SettingsUserActionPayloadRt = rt.strict({ settings: SettingsRt });
|
||||
export const SettingsUserActionPayloadRt = rt.strict({ settings: CaseSettingsRt });
|
||||
|
||||
export const SettingsUserActionRt = rt.strict({
|
||||
type: rt.literal(UserActionTypes.settings),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CaseSeverity } from '../../../../api';
|
||||
import { CaseSeverity } from '../../case/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
import { SeverityUserActionPayloadRt, SeverityUserActionRt } from './v1';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseSeverityRt } from '../../../../api';
|
||||
import { CaseSeverityRt } from '../../case/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const SeverityUserActionPayloadRt = rt.strict({ severity: CaseSeverityRt });
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { CaseStatusRt } from '../../../../api';
|
||||
import { CaseStatusRt } from '../../case/v1';
|
||||
import { UserActionTypes } from '../action/v1';
|
||||
|
||||
export const StatusUserActionPayloadRt = rt.strict({ status: CaseStatusRt });
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CommentType } from '../../../api';
|
||||
import { AttachmentType } from '../attachment/v1';
|
||||
import { UserActionTypes } from './action/v1';
|
||||
import { UserActionsRt } from './v1';
|
||||
|
||||
|
@ -17,7 +17,7 @@ describe('User actions', () => {
|
|||
payload: {
|
||||
comment: {
|
||||
comment: 'this is a sample comment',
|
||||
type: CommentType.user,
|
||||
type: AttachmentType.user,
|
||||
owner: 'cases',
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as rt from 'io-ts';
|
||||
import { UserRt } from '../../../api';
|
||||
import { UserRt } from '../user/v1';
|
||||
import { UserActionActionsRt } from './action/v1';
|
||||
import { AssigneesUserActionRt } from './assignees/v1';
|
||||
import { CategoryUserActionRt } from './category/v1';
|
||||
|
|
|
@ -12,28 +12,28 @@ import type {
|
|||
READ_CASES_CAPABILITY,
|
||||
UPDATE_CASES_CAPABILITY,
|
||||
} from '..';
|
||||
import type {
|
||||
CasePatchRequest,
|
||||
CaseStatuses,
|
||||
User,
|
||||
SingleCaseMetricsResponse,
|
||||
Comment,
|
||||
Case as CaseSnakeCase,
|
||||
CommentResponseAlertsType,
|
||||
CasesFindResponse,
|
||||
CasesStatusResponse,
|
||||
CasesMetricsResponse,
|
||||
CaseSeverity,
|
||||
CommentResponseExternalReferenceType,
|
||||
CommentResponseTypePersistableState,
|
||||
GetCaseUsersResponse,
|
||||
} from '../api';
|
||||
import type { SingleCaseMetricsResponse, CasesMetricsResponse } from '../api';
|
||||
import type { PUSH_CASES_CAPABILITY } from '../constants';
|
||||
import type { SnakeToCamelCase } from '../types';
|
||||
import type { ActionConnector, UserAction } from '../types/domain';
|
||||
import type {
|
||||
CaseSeverity,
|
||||
CaseStatuses,
|
||||
UserAction,
|
||||
Case as CaseSnakeCase,
|
||||
User,
|
||||
ActionConnector,
|
||||
AlertAttachment,
|
||||
Attachment,
|
||||
ExternalReferenceAttachment,
|
||||
PersistableStateAttachment,
|
||||
} from '../types/domain';
|
||||
import type {
|
||||
CasePatchRequest,
|
||||
CasesFindResponse,
|
||||
CasesStatusResponse,
|
||||
CaseUserActionStatsResponse,
|
||||
GetCaseConnectorsResponse,
|
||||
GetCaseUsersResponse,
|
||||
UserActionFindRequestTypes,
|
||||
UserActionFindResponse,
|
||||
} from '../types/api';
|
||||
|
@ -84,16 +84,18 @@ export type CaseViewRefreshPropInterface = null | {
|
|||
refreshCase: () => Promise<void>;
|
||||
};
|
||||
|
||||
export type CommentUI = SnakeToCamelCase<Comment>;
|
||||
export type AlertComment = SnakeToCamelCase<CommentResponseAlertsType>;
|
||||
export type ExternalReferenceComment = SnakeToCamelCase<CommentResponseExternalReferenceType>;
|
||||
export type PersistableComment = SnakeToCamelCase<CommentResponseTypePersistableState>;
|
||||
export type AttachmentUI = SnakeToCamelCase<Attachment>;
|
||||
export type AlertAttachmentUI = SnakeToCamelCase<AlertAttachment>;
|
||||
export type ExternalReferenceAttachmentUI = SnakeToCamelCase<ExternalReferenceAttachment>;
|
||||
export type PersistableStateAttachmentUI = SnakeToCamelCase<PersistableStateAttachment>;
|
||||
export type UserActionUI = SnakeToCamelCase<UserAction>;
|
||||
export type FindCaseUserActions = Omit<SnakeToCamelCase<UserActionFindResponse>, 'userActions'> & {
|
||||
userActions: UserActionUI[];
|
||||
};
|
||||
export type CaseUserActionsStats = SnakeToCamelCase<CaseUserActionStatsResponse>;
|
||||
export type CaseUI = Omit<SnakeToCamelCase<CaseSnakeCase>, 'comments'> & { comments: CommentUI[] };
|
||||
export type CaseUI = Omit<SnakeToCamelCase<CaseSnakeCase>, 'comments'> & {
|
||||
comments: AttachmentUI[];
|
||||
};
|
||||
export type CasesUI = CaseUI[];
|
||||
export type CasesFindResponseUI = Omit<SnakeToCamelCase<CasesFindResponse>, 'cases'> & {
|
||||
cases: CasesUI;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CommentAttributes } from '../api';
|
||||
import { CommentType } from '../api';
|
||||
import type { AttachmentAttributes } from '../types/domain';
|
||||
import { AttachmentType } from '../types/domain';
|
||||
import {
|
||||
isCommentRequestTypeExternalReference,
|
||||
isCommentRequestTypePersistableState,
|
||||
|
@ -15,11 +15,11 @@ import {
|
|||
describe('attachments utils', () => {
|
||||
describe('isCommentRequestTypeExternalReference', () => {
|
||||
const externalReferenceAttachment = {
|
||||
type: CommentType.externalReference as const,
|
||||
} as CommentAttributes;
|
||||
type: AttachmentType.externalReference as const,
|
||||
} as AttachmentAttributes;
|
||||
|
||||
const commentTypeWithoutAlert = Object.values(CommentType).filter(
|
||||
(type) => type !== CommentType.externalReference
|
||||
const commentTypeWithoutAlert = Object.values(AttachmentType).filter(
|
||||
(type) => type !== AttachmentType.externalReference
|
||||
);
|
||||
|
||||
it('returns false for type: externalReference', () => {
|
||||
|
@ -29,7 +29,7 @@ describe('attachments utils', () => {
|
|||
it.each(commentTypeWithoutAlert)('returns false for type: %s', (type) => {
|
||||
const attachment = {
|
||||
type,
|
||||
} as CommentAttributes;
|
||||
} as AttachmentAttributes;
|
||||
|
||||
expect(isCommentRequestTypeExternalReference(attachment)).toBe(false);
|
||||
});
|
||||
|
@ -37,11 +37,11 @@ describe('attachments utils', () => {
|
|||
|
||||
describe('isCommentRequestTypePersistableState', () => {
|
||||
const persistableStateAttachment = {
|
||||
type: CommentType.persistableState as const,
|
||||
} as CommentAttributes;
|
||||
type: AttachmentType.persistableState as const,
|
||||
} as AttachmentAttributes;
|
||||
|
||||
const commentTypeWithoutAlert = Object.values(CommentType).filter(
|
||||
(type) => type !== CommentType.persistableState
|
||||
const commentTypeWithoutAlert = Object.values(AttachmentType).filter(
|
||||
(type) => type !== AttachmentType.persistableState
|
||||
);
|
||||
|
||||
it('returns false for type: persistableState', () => {
|
||||
|
@ -51,7 +51,7 @@ describe('attachments utils', () => {
|
|||
it.each(commentTypeWithoutAlert)('returns false for type: %s', (type) => {
|
||||
const attachment = {
|
||||
type,
|
||||
} as CommentAttributes;
|
||||
} as AttachmentAttributes;
|
||||
|
||||
expect(isCommentRequestTypePersistableState(attachment)).toBe(false);
|
||||
});
|
||||
|
|
|
@ -5,27 +5,27 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { AttachmentRequest } from '../types/api';
|
||||
import type {
|
||||
CommentRequest,
|
||||
CommentRequestExternalReferenceType,
|
||||
CommentRequestPersistableStateType,
|
||||
} from '../api';
|
||||
import { CommentType } from '../api';
|
||||
ExternalReferenceAttachmentPayload,
|
||||
PersistableStateAttachmentPayload,
|
||||
} from '../types/domain';
|
||||
import { AttachmentType } from '../types/domain';
|
||||
|
||||
/**
|
||||
* A type narrowing function for external reference attachments.
|
||||
*/
|
||||
export const isCommentRequestTypeExternalReference = (
|
||||
context: CommentRequest
|
||||
): context is CommentRequestExternalReferenceType => {
|
||||
return context.type === CommentType.externalReference;
|
||||
context: AttachmentRequest
|
||||
): context is ExternalReferenceAttachmentPayload => {
|
||||
return context.type === AttachmentType.externalReference;
|
||||
};
|
||||
|
||||
/**
|
||||
* A type narrowing function for persistable state attachments.
|
||||
*/
|
||||
export const isCommentRequestTypePersistableState = (
|
||||
context: Partial<CommentRequest>
|
||||
): context is CommentRequestPersistableStateType => {
|
||||
return context.type === CommentType.persistableState;
|
||||
context: Partial<AttachmentRequest>
|
||||
): context is PersistableStateAttachmentPayload => {
|
||||
return context.type === AttachmentType.persistableState;
|
||||
};
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CaseAssignees } from '../api';
|
||||
import { MAX_ASSIGNEES_PER_CASE } from '../constants';
|
||||
import type { CaseAssignees } from '../types/domain';
|
||||
|
||||
export const areTotalAssigneesInvalid = (assignees?: CaseAssignees): boolean => {
|
||||
if (assignees == null) {
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CasesFindRequest, CasesMetricsRequest } from '../../../common/api';
|
||||
import type { CasesMetricsRequest } from '../../../common/api';
|
||||
import type { HTTPService } from '..';
|
||||
import { casesMetrics, casesStatus } from '../../containers/mock';
|
||||
import type { CasesMetrics, CasesStatus } from '../../containers/types';
|
||||
import type { CasesFindRequest } from '../../../common/types/api';
|
||||
|
||||
export const getCasesStatus = async ({
|
||||
http,
|
||||
|
|
|
@ -9,20 +9,20 @@ import { fold } from 'fp-ts/lib/Either';
|
|||
import { identity } from 'fp-ts/lib/function';
|
||||
import { pipe } from 'fp-ts/lib/pipeable';
|
||||
|
||||
import { createToasterPlainError } from '../containers/utils';
|
||||
import { throwErrors } from '../../common';
|
||||
import type {
|
||||
CasesFindResponse,
|
||||
CasesStatusResponse,
|
||||
CasesMetricsResponse,
|
||||
CasesBulkGetResponse,
|
||||
} from '../../common/api';
|
||||
} from '../../common/types/api';
|
||||
import {
|
||||
CasesBulkGetResponseRt,
|
||||
CasesFindResponseRt,
|
||||
CasesStatusResponseRt,
|
||||
CasesMetricsResponseRt,
|
||||
} from '../../common/api';
|
||||
CasesBulkGetResponseRt,
|
||||
} from '../../common/types/api';
|
||||
import { createToasterPlainError } from '../containers/utils';
|
||||
import { throwErrors } from '../../common';
|
||||
import type { CasesMetricsResponse } from '../../common/api';
|
||||
import { CasesMetricsResponseRt } from '../../common/api';
|
||||
|
||||
export const decodeCasesFindResponse = (respCases?: CasesFindResponse) =>
|
||||
pipe(CasesFindResponseRt.decode(respCases), fold(throwErrors(createToasterPlainError), identity));
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
*/
|
||||
|
||||
import type { HttpStart } from '@kbn/core/public';
|
||||
import type {
|
||||
CasesFindRequest,
|
||||
CasesFindResponse,
|
||||
CasesStatusRequest,
|
||||
CasesStatusResponse,
|
||||
CasesBulkGetRequest,
|
||||
CasesBulkGetResponse,
|
||||
} from '../../common/types/api';
|
||||
import type { CasesStatus, CasesMetrics, CasesFindResponseUI } from '../../common/ui';
|
||||
import {
|
||||
CASE_FIND_URL,
|
||||
|
@ -13,16 +21,7 @@ import {
|
|||
CASE_STATUS_URL,
|
||||
INTERNAL_BULK_GET_CASES_URL,
|
||||
} from '../../common/constants';
|
||||
import type {
|
||||
CasesBulkGetRequest,
|
||||
CasesBulkGetResponse,
|
||||
CasesFindRequest,
|
||||
CasesFindResponse,
|
||||
CasesMetricsRequest,
|
||||
CasesMetricsResponse,
|
||||
CasesStatusRequest,
|
||||
CasesStatusResponse,
|
||||
} from '../../common/api';
|
||||
import type { CasesMetricsRequest, CasesMetricsResponse } from '../../common/api';
|
||||
import { convertAllCasesToCamel, convertToCamelCase } from './utils';
|
||||
import {
|
||||
decodeCasesBulkGetResponse,
|
||||
|
|
|
@ -7,25 +7,22 @@
|
|||
|
||||
import { set } from '@kbn/safer-lodash-set';
|
||||
import { isArray, camelCase, isObject, omit, get } from 'lodash';
|
||||
import type { UserActions } from '../../common/types/domain';
|
||||
import type {
|
||||
AttachmentRequest,
|
||||
CaseResolveResponse,
|
||||
CasesFindResponse,
|
||||
} from '../../common/types/api';
|
||||
import type { Attachment, Case, Cases, UserActions } from '../../common/types/domain';
|
||||
import {
|
||||
isCommentRequestTypeExternalReference,
|
||||
isCommentRequestTypePersistableState,
|
||||
} from '../../common/utils/attachments';
|
||||
import type {
|
||||
CasesFindResponse,
|
||||
Case,
|
||||
CommentRequest,
|
||||
Comment,
|
||||
CaseResolveResponse,
|
||||
Cases,
|
||||
} from '../../common/api';
|
||||
import { isCommentUserAction } from '../../common/utils/user_actions';
|
||||
import type {
|
||||
CasesFindResponseUI,
|
||||
CasesUI,
|
||||
CaseUI,
|
||||
CommentUI,
|
||||
AttachmentUI,
|
||||
ResolvedCase,
|
||||
} from '../containers/types';
|
||||
|
||||
|
@ -71,11 +68,11 @@ export const convertCaseResolveToCamelCase = (res: CaseResolveResponse): Resolve
|
|||
};
|
||||
};
|
||||
|
||||
export const convertAttachmentsToCamelCase = (attachments: Comment[]): CommentUI[] => {
|
||||
export const convertAttachmentsToCamelCase = (attachments: Attachment[]): AttachmentUI[] => {
|
||||
return attachments.map((attachment) => convertAttachmentToCamelCase(attachment));
|
||||
};
|
||||
|
||||
export const convertAttachmentToCamelCase = (attachment: CommentRequest): CommentUI => {
|
||||
export const convertAttachmentToCamelCase = (attachment: AttachmentRequest): AttachmentUI => {
|
||||
if (isCommentRequestTypeExternalReference(attachment)) {
|
||||
return convertAttachmentToCamelExceptProperty(attachment, 'externalReferenceMetadata');
|
||||
}
|
||||
|
@ -84,7 +81,7 @@ export const convertAttachmentToCamelCase = (attachment: CommentRequest): Commen
|
|||
return convertAttachmentToCamelExceptProperty(attachment, 'persistableStateAttachmentState');
|
||||
}
|
||||
|
||||
return convertToCamelCase<CommentRequest, CommentUI>(attachment);
|
||||
return convertToCamelCase<AttachmentRequest, AttachmentUI>(attachment);
|
||||
};
|
||||
|
||||
export const convertUserActionsToCamelCase = (userActions: UserActions) => {
|
||||
|
@ -106,9 +103,9 @@ export const convertUserActionsToCamelCase = (userActions: UserActions) => {
|
|||
};
|
||||
|
||||
const convertAttachmentToCamelExceptProperty = (
|
||||
attachment: CommentRequest,
|
||||
attachment: AttachmentRequest,
|
||||
key: string
|
||||
): CommentUI => {
|
||||
): AttachmentUI => {
|
||||
const intactValue = get(attachment, key);
|
||||
const attachmentWithoutIntactValue = omit(attachment, key);
|
||||
const camelCaseAttachmentWithoutIntactValue = convertToCamelCase(attachmentWithoutIntactValue);
|
||||
|
@ -116,7 +113,7 @@ const convertAttachmentToCamelExceptProperty = (
|
|||
return {
|
||||
...camelCaseAttachmentWithoutIntactValue,
|
||||
[key]: intactValue,
|
||||
} as CommentUI;
|
||||
} as AttachmentUI;
|
||||
};
|
||||
|
||||
export const convertAllCasesToCamel = (snakeCases: CasesFindResponse): CasesFindResponseUI => ({
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import type { HttpStart } from '@kbn/core/public';
|
||||
import type {
|
||||
CasesByAlertId,
|
||||
CasesByAlertIDRequest,
|
||||
GetRelatedCasesByAlertResponse,
|
||||
CasesFindRequest,
|
||||
CasesStatusRequest,
|
||||
CasesMetricsRequest,
|
||||
} from '../../../common/api';
|
||||
} from '../../../common/types/api';
|
||||
import type { CasesMetricsRequest } from '../../../common/api';
|
||||
import { getCasesFromAlertsUrl } from '../../../common/api';
|
||||
import { bulkGetCases, getCases, getCasesMetrics, getCasesStatus } from '../../api';
|
||||
import type { CasesFindResponseUI, CasesStatus, CasesMetrics } from '../../../common/ui';
|
||||
|
@ -23,8 +23,8 @@ export const createClientAPI = ({ http }: { http: HttpStart }): CasesUiStart['ap
|
|||
getRelatedCases: async (
|
||||
alertId: string,
|
||||
query: CasesByAlertIDRequest
|
||||
): Promise<CasesByAlertId> =>
|
||||
http.get<CasesByAlertId>(getCasesFromAlertsUrl(alertId), { query }),
|
||||
): Promise<GetRelatedCasesByAlertResponse> =>
|
||||
http.get<GetRelatedCasesByAlertResponse>(getCasesFromAlertsUrl(alertId), { query }),
|
||||
cases: {
|
||||
find: (query: CasesFindRequest, signal?: AbortSignal): Promise<CasesFindResponseUI> =>
|
||||
getCases({ http, query, signal }),
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import type React from 'react';
|
||||
import type { EuiCommentProps, IconType, EuiButtonProps } from '@elastic/eui';
|
||||
import type {
|
||||
CommentRequestExternalReferenceType,
|
||||
CommentRequestPersistableStateType,
|
||||
} from '../../../common/api';
|
||||
ExternalReferenceAttachmentPayload,
|
||||
PersistableStateAttachmentPayload,
|
||||
} from '../../../common/types/domain';
|
||||
import type { CaseUI } from '../../containers/types';
|
||||
|
||||
export enum AttachmentActionType {
|
||||
|
@ -53,13 +53,13 @@ export interface CommonAttachmentViewProps {
|
|||
}
|
||||
|
||||
export interface ExternalReferenceAttachmentViewProps extends CommonAttachmentViewProps {
|
||||
externalReferenceId: CommentRequestExternalReferenceType['externalReferenceId'];
|
||||
externalReferenceMetadata: CommentRequestExternalReferenceType['externalReferenceMetadata'];
|
||||
externalReferenceId: ExternalReferenceAttachmentPayload['externalReferenceId'];
|
||||
externalReferenceMetadata: ExternalReferenceAttachmentPayload['externalReferenceMetadata'];
|
||||
}
|
||||
|
||||
export interface PersistableStateAttachmentViewProps extends CommonAttachmentViewProps {
|
||||
persistableStateAttachmentTypeId: CommentRequestPersistableStateType['persistableStateAttachmentTypeId'];
|
||||
persistableStateAttachmentState: CommentRequestPersistableStateType['persistableStateAttachmentState'];
|
||||
persistableStateAttachmentTypeId: PersistableStateAttachmentPayload['persistableStateAttachmentTypeId'];
|
||||
persistableStateAttachmentState: PersistableStateAttachmentPayload['persistableStateAttachmentState'];
|
||||
}
|
||||
|
||||
export interface AttachmentType<Props> {
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { CommentRequestAlertType } from '../../../common/api';
|
||||
import type { AlertAttachmentPayload } from '../../../common/types/domain';
|
||||
import type { Ecs } from '../../../common';
|
||||
import { CommentType } from '../../../common';
|
||||
import { AttachmentType } from '../../../common/types/domain';
|
||||
import { getRuleIdFromEvent } from './get_rule_id_from_event';
|
||||
import type { CaseAttachmentsWithoutOwner } from '../../types';
|
||||
|
||||
|
@ -21,7 +21,7 @@ interface EventNonEcsData {
|
|||
value?: Maybe<string[]>;
|
||||
}
|
||||
|
||||
type CommentRequestAlertTypeWithoutOwner = Omit<CommentRequestAlertType, 'owner'>;
|
||||
type CommentRequestAlertTypeWithoutOwner = Omit<AlertAttachmentPayload, 'owner'>;
|
||||
|
||||
export type GroupAlertsByRule = (items: Event[]) => CaseAttachmentsWithoutOwner;
|
||||
|
||||
|
@ -33,7 +33,7 @@ export const groupAlertsByRule: GroupAlertsByRule = (items) => {
|
|||
acc[rule.id] = {
|
||||
alertId: [],
|
||||
index: [],
|
||||
type: CommentType.alert as const,
|
||||
type: AttachmentType.alert as const,
|
||||
rule,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import type { Transaction } from '@elastic/apm-rum';
|
||||
import { useCallback } from 'react';
|
||||
import { CommentType } from '../../../common';
|
||||
import { AttachmentType } from '../../../common/types/domain';
|
||||
import type { CaseAttachmentsWithoutOwner } from '../../types';
|
||||
import { useStartTransaction } from './use_start_transaction';
|
||||
|
||||
|
@ -77,7 +77,7 @@ export const useAddAttachmentToExistingCaseTransaction = () => {
|
|||
|
||||
const getAlertCount = (attachments: CaseAttachmentsWithoutOwner) => {
|
||||
return attachments.reduce((total, attachment) => {
|
||||
if (attachment.type !== CommentType.alert) {
|
||||
if (attachment.type !== AttachmentType.alert) {
|
||||
return total;
|
||||
}
|
||||
if (!Array.isArray(attachment.alertId)) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import styled from 'styled-components';
|
|||
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
|
||||
import { isValidOwner } from '../../common/utils/owner';
|
||||
import type { CaseUI } from '../../common';
|
||||
import { CommentType } from '../../common';
|
||||
import { AttachmentType } from '../../common/types/domain';
|
||||
import { useKibana, useToasts } from './lib/kibana';
|
||||
import { generateCaseViewPath } from './navigation';
|
||||
import type { CaseAttachmentsWithoutOwner, ServerError } from '../types';
|
||||
|
@ -43,7 +43,7 @@ const EuiTextStyled = styled(EuiText)`
|
|||
function getAlertsCount(attachments: CaseAttachmentsWithoutOwner): number {
|
||||
let alertsCount = 0;
|
||||
for (const attachment of attachments) {
|
||||
if (attachment.type === CommentType.alert) {
|
||||
if (attachment.type === AttachmentType.alert) {
|
||||
// alertId might be an array
|
||||
if (Array.isArray(attachment.alertId) && attachment.alertId.length > 1) {
|
||||
alertsCount += attachment.alertId.length;
|
||||
|
@ -91,7 +91,7 @@ function getToastContent({
|
|||
}
|
||||
if (attachments !== undefined) {
|
||||
for (const attachment of attachments) {
|
||||
if (attachment.type === CommentType.alert && theCase.settings.syncAlerts) {
|
||||
if (attachment.type === AttachmentType.alert && theCase.settings.syncAlerts) {
|
||||
return CASE_ALERT_SUCCESS_SYNC_TEXT;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { CaseSeverity } from '../../../../common/api';
|
||||
import { CaseSeverity } from '../../../../common/types/domain';
|
||||
import { severities } from '../../severity/config';
|
||||
|
||||
const SET_SEVERITY = ({
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useSeverityAction } from './use_severity_action';
|
|||
|
||||
import * as api from '../../../containers/api';
|
||||
import { basicCase } from '../../../containers/mock';
|
||||
import { CaseSeverity } from '../../../../common/api';
|
||||
import { CaseSeverity } from '../../../../common/types/domain';
|
||||
|
||||
jest.mock('../../../containers/api');
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import { useCallback } from 'react';
|
||||
import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui';
|
||||
import { CaseSeverity } from '../../../../common/api';
|
||||
import { CaseSeverity } from '../../../../common/types/domain';
|
||||
import { useUpdateCases } from '../../../containers/use_bulk_update_case';
|
||||
import type { CasesUI } from '../../../../common';
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useStatusAction } from './use_status_action';
|
|||
|
||||
import * as api from '../../../containers/api';
|
||||
import { basicCase } from '../../../containers/mock';
|
||||
import { CaseStatuses } from '../../../../common';
|
||||
import { CaseStatuses } from '../../../../common/types/domain';
|
||||
|
||||
jest.mock('../../../containers/api');
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useCallback } from 'react';
|
|||
import type { EuiContextMenuPanelItemDescriptor } from '@elastic/eui';
|
||||
import { useUpdateCases } from '../../../containers/use_bulk_update_case';
|
||||
import type { CasesUI } from '../../../../common';
|
||||
import { CaseStatuses } from '../../../../common';
|
||||
import { CaseStatuses } from '../../../../common/types/domain';
|
||||
|
||||
import * as i18n from './translations';
|
||||
import type { UseActionProps } from '../types';
|
||||
|
|
|
@ -12,7 +12,7 @@ import { noop } from 'lodash/fp';
|
|||
|
||||
import { noCreateCasesPermissions, TestProviders, createAppMockRenderer } from '../../common/mock';
|
||||
|
||||
import { CommentType } from '../../../common/api';
|
||||
import { AttachmentType } from '../../../common/types/domain';
|
||||
import { SECURITY_SOLUTION_OWNER, MAX_COMMENT_LENGTH } from '../../../common/constants';
|
||||
import { useCreateAttachments } from '../../containers/use_create_attachments';
|
||||
import type { AddCommentProps, AddCommentRefObject } from '.';
|
||||
|
@ -46,7 +46,7 @@ const defaultResponse = {
|
|||
|
||||
const sampleData: CaseAttachmentWithoutOwner = {
|
||||
comment: 'what a cool comment',
|
||||
type: CommentType.user as const,
|
||||
type: AttachmentType.user as const,
|
||||
};
|
||||
const appId = 'testAppId';
|
||||
const draftKey = `cases.${appId}.${addCommentProps.caseId}.${addCommentProps.id}.markdownEditor`;
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
UseField,
|
||||
useFormData,
|
||||
} from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||
import { CommentType } from '../../../common/api';
|
||||
import { AttachmentType } from '../../../common/types/domain';
|
||||
import { useCreateAttachments } from '../../containers/use_create_attachments';
|
||||
import type { CaseUI } from '../../containers/types';
|
||||
import type { EuiMarkdownEditorRef } from '../markdown_editor';
|
||||
|
@ -119,7 +119,7 @@ export const AddComment = React.memo(
|
|||
{
|
||||
caseId,
|
||||
caseOwner: owner[0],
|
||||
attachments: [{ ...data, type: CommentType.user }],
|
||||
attachments: [{ ...data, type: AttachmentType.user }],
|
||||
},
|
||||
{
|
||||
onSuccess: (theCase) => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import type { FormSchema } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||
import { FIELD_TYPES } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
|
||||
import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers';
|
||||
import type { CommentRequestUserType } from '../../../common/api';
|
||||
import type { UserCommentAttachmentPayload } from '../../../common/types/domain';
|
||||
import { MAX_COMMENT_LENGTH } from '../../../common/constants';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
@ -16,7 +16,7 @@ import * as i18n from './translations';
|
|||
const { emptyField, maxLengthField } = fieldValidators;
|
||||
|
||||
export interface AddCommentFormSchema {
|
||||
comment: CommentRequestUserType['comment'];
|
||||
comment: UserCommentAttachmentPayload['comment'];
|
||||
}
|
||||
|
||||
export const schema: FormSchema<AddCommentFormSchema> = {
|
||||
|
|
|
@ -23,7 +23,7 @@ import {
|
|||
import { useGetCasesMockState, connectorsMock } from '../../containers/mock';
|
||||
|
||||
import { SortFieldCase, StatusAll } from '../../../common/ui/types';
|
||||
import { CaseSeverity, CaseStatuses } from '../../../common/api';
|
||||
import { CaseSeverity, CaseStatuses } from '../../../common/types/domain';
|
||||
import { SECURITY_SOLUTION_OWNER } from '../../../common/constants';
|
||||
import { getEmptyTagValue } from '../empty_value';
|
||||
import { useKibana } from '../../common/lib/kibana';
|
||||
|
|
|
@ -21,7 +21,7 @@ import type { CasesOwners } from '../../client/helpers/can_use_cases';
|
|||
import type { EuiBasicTableOnChange, Solution } from './types';
|
||||
|
||||
import { SortFieldCase, StatusAll } from '../../../common/ui/types';
|
||||
import { CaseStatuses, caseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses, caseStatuses } from '../../../common/types/domain';
|
||||
import { OWNER_INFO } from '../../../common/constants';
|
||||
import { useAvailableCasesOwners } from '../app/use_available_owners';
|
||||
import { useCasesColumns } from './use_cases_columns';
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import styled, { css } from 'styled-components';
|
||||
import prettyMilliseconds from 'pretty-ms';
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { useGetCasesStatus } from '../../containers/use_get_cases_status';
|
||||
import { StatusStats } from '../status/status_stats';
|
||||
import { useGetCasesMetrics } from '../../containers/use_get_cases_metrics';
|
||||
|
|
|
@ -11,7 +11,8 @@ import userEvent from '@testing-library/user-event';
|
|||
import React from 'react';
|
||||
import AllCasesSelectorModal from '.';
|
||||
import type { CaseUI } from '../../../../common';
|
||||
import { CaseStatuses, StatusAll } from '../../../../common';
|
||||
import { StatusAll } from '../../../../common';
|
||||
import { CaseStatuses } from '../../../../common/types/domain';
|
||||
import type { AppMockRenderer } from '../../../common/mock';
|
||||
import { allCasesPermissions, createAppMockRenderer } from '../../../common/mock';
|
||||
import { useCasesToast } from '../../../common/use_cases_toast';
|
||||
|
|
|
@ -6,10 +6,11 @@
|
|||
*/
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { CaseStatuses, StatusAll } from '../../../../common';
|
||||
import { CaseStatuses } from '../../../../common/types/domain';
|
||||
import type { AllCasesSelectorModalProps } from '.';
|
||||
import { useCasesToast } from '../../../common/use_cases_toast';
|
||||
import type { CaseUI } from '../../../containers/types';
|
||||
import { StatusAll } from '../../../containers/types';
|
||||
import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer';
|
||||
import { useCasesContext } from '../../cases_context/use_cases_context';
|
||||
import { useCasesAddToNewCaseFlyout } from '../../create/flyout/use_cases_add_to_new_case_flyout';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CaseSeverity } from '../../../common/api';
|
||||
import { CaseSeverity } from '../../../common/types/domain';
|
||||
import React from 'react';
|
||||
import type { AppMockRenderer } from '../../common/mock';
|
||||
import { createAppMockRenderer } from '../../common/mock';
|
||||
|
|
|
@ -10,7 +10,7 @@ import { mount } from 'enzyme';
|
|||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
import { StatusAll } from '../../../common/ui/types';
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { StatusFilter } from './status_filter';
|
||||
|
||||
const stats = {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl';
|
|||
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
|
||||
import { waitForComponentToUpdate } from '../../common/test_utils';
|
||||
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import {
|
||||
OWNER_INFO,
|
||||
SECURITY_SOLUTION_OWNER,
|
||||
|
|
|
@ -13,7 +13,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiFieldSearch, EuiFilterGroup, EuiButton }
|
|||
import type { CaseStatusWithAllStatus, CaseSeverityWithAll } from '../../../common/ui/types';
|
||||
import { MAX_TAGS_FILTER_LENGTH, MAX_CATEGORY_FILTER_LENGTH } from '../../../common/constants';
|
||||
import { StatusAll } from '../../../common/ui/types';
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import type { FilterOptions } from '../../containers/types';
|
||||
import { FilterPopover } from '../filter_popover';
|
||||
import { SolutionFilter } from './solution_filter';
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
} from './use_all_cases_state';
|
||||
import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from '../../containers/use_get_cases';
|
||||
import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../containers/constants';
|
||||
import { CaseStatuses } from '../../../common';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { SortFieldCase } from '../../containers/types';
|
||||
import { stringifyToURL } from '../utils';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import { connectors } from '../configure_cases/__mock__';
|
|||
import type { AppMockRenderer } from '../../common/mock';
|
||||
import { createAppMockRenderer, readCasesPermissions, TestProviders } from '../../common/mock';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { CaseStatuses } from '../../../common';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { userProfilesMap } from '../../containers/user_profiles/api.mock';
|
||||
|
||||
describe('useCasesColumns ', () => {
|
||||
|
|
|
@ -27,8 +27,8 @@ import type { UserProfileWithAvatar } from '@kbn/user-profile-components';
|
|||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
|
||||
import type { ActionConnector } from '../../../common/types/domain';
|
||||
import { CaseSeverity, CaseStatuses } from '../../../common/types/domain';
|
||||
import type { CaseUI } from '../../../common/ui/types';
|
||||
import { CaseStatuses, CaseSeverity } from '../../../common/api';
|
||||
import { OWNER_INFO } from '../../../common/constants';
|
||||
import { getEmptyTagValue } from '../empty_value';
|
||||
import { FormattedRelativePreferenceDate } from '../formatted_date';
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { basicCase } from '../../containers/mock';
|
||||
import { getStatusDate, getStatusTitle } from './helpers';
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import type { CaseUI } from '../../containers/types';
|
||||
import { statuses } from '../status';
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
EuiIconTip,
|
||||
} from '@elastic/eui';
|
||||
import type { CaseUI } from '../../../common/ui/types';
|
||||
import type { CaseStatuses } from '../../../common/api';
|
||||
import type { CaseStatuses } from '../../../common/types/domain';
|
||||
import * as i18n from '../case_view/translations';
|
||||
import { Actions } from './actions';
|
||||
import { StatusContextMenu } from './status_context_menu';
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import { CaseStatuses } from '../../../common/api';
|
||||
import { CaseStatuses } from '../../../common/types/domain';
|
||||
import { StatusContextMenu } from './status_context_menu';
|
||||
|
||||
describe('SyncAlertsSwitch', () => {
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
import React, { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { EuiPopover, EuiContextMenuPanel, EuiContextMenuItem } from '@elastic/eui';
|
||||
import { Status } from '@kbn/cases-components/src/status/status';
|
||||
import type { CaseStatuses } from '../../../common/api';
|
||||
import { caseStatuses } from '../../../common/api';
|
||||
import type { CaseStatuses } from '../../../common/types/domain';
|
||||
import { caseStatuses } from '../../../common/types/domain';
|
||||
import { StatusPopoverButton } from '../status';
|
||||
import { CHANGE_STATUS } from '../all_cases/translations';
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ import {
|
|||
} from '@elastic/eui';
|
||||
|
||||
import type { UserProfileWithAvatar } from '@kbn/user-profile-components';
|
||||
import type { CaseAssignees } from '../../../../common/types/domain';
|
||||
import type { CasesPermissions } from '../../../../common';
|
||||
import { useAssignees } from '../../../containers/user_profiles/use_assignees';
|
||||
import type { CaseAssignees } from '../../../../common/api/cases/assignee';
|
||||
import * as i18n from '../translations';
|
||||
import { SidebarTitle } from './sidebar_title';
|
||||
import { RemovableUser } from '../../user_profiles/removable_user';
|
||||
|
|
|
@ -16,9 +16,9 @@ import { useGetCaseConnectors } from '../../../containers/use_get_case_connector
|
|||
import { useCasesFeatures } from '../../../common/use_cases_features';
|
||||
import { useGetCurrentUserProfile } from '../../../containers/user_profiles/use_get_current_user_profile';
|
||||
import { useGetSupportedActionConnectors } from '../../../containers/configure/use_get_supported_action_connectors';
|
||||
import type { CaseSeverity } from '../../../../common/api';
|
||||
import type { CaseSeverity, CaseStatuses } from '../../../../common/types/domain';
|
||||
import type { CaseUsers, UseFetchAlertData } from '../../../../common/ui/types';
|
||||
import type { CaseUI, CaseStatuses } from '../../../../common';
|
||||
import type { CaseUI } from '../../../../common';
|
||||
import { EditConnector } from '../../edit_connector';
|
||||
import type { CasesNavigation } from '../../links';
|
||||
import { StatusActionButton } from '../../status/button';
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { CommentType } from '../../../../common/api';
|
||||
import type { CommentUI } from '../../../containers/types';
|
||||
import { AttachmentType } from '../../../../common/types/domain';
|
||||
import type { AttachmentUI } from '../../../containers/types';
|
||||
|
||||
export const getManualAlertIds = (comments: CommentUI[]): string[] => {
|
||||
const dedupeAlerts = comments.reduce((alertIds, comment: CommentUI) => {
|
||||
if (comment.type === CommentType.alert) {
|
||||
export const getManualAlertIds = (comments: AttachmentUI[]): string[] => {
|
||||
const dedupeAlerts = comments.reduce((alertIds, comment: AttachmentUI) => {
|
||||
if (comment.type === AttachmentType.alert) {
|
||||
const ids = Array.isArray(comment.alertId) ? comment.alertId : [comment.alertId];
|
||||
ids.forEach((id) => alertIds.add(id));
|
||||
return alertIds;
|
||||
|
@ -20,25 +20,28 @@ export const getManualAlertIds = (comments: CommentUI[]): string[] => {
|
|||
return Array.from(dedupeAlerts);
|
||||
};
|
||||
|
||||
export const getRegistrationContextFromAlerts = (comments: CommentUI[]): string[] => {
|
||||
const dedupeRegistrationContext = comments.reduce((registrationContexts, comment: CommentUI) => {
|
||||
if (comment.type === CommentType.alert) {
|
||||
const indices = Array.isArray(comment.index) ? comment.index : [comment.index];
|
||||
indices.forEach((index) => {
|
||||
// That's legacy code, we created some index alias so everything should work as expected
|
||||
if (index.startsWith('.siem-signals')) {
|
||||
registrationContexts.add('security');
|
||||
} else {
|
||||
const registrationContext = getRegistrationContextFromIndex(index);
|
||||
if (registrationContext) {
|
||||
registrationContexts.add(registrationContext);
|
||||
export const getRegistrationContextFromAlerts = (comments: AttachmentUI[]): string[] => {
|
||||
const dedupeRegistrationContext = comments.reduce(
|
||||
(registrationContexts, comment: AttachmentUI) => {
|
||||
if (comment.type === AttachmentType.alert) {
|
||||
const indices = Array.isArray(comment.index) ? comment.index : [comment.index];
|
||||
indices.forEach((index) => {
|
||||
// That's legacy code, we created some index alias so everything should work as expected
|
||||
if (index.startsWith('.siem-signals')) {
|
||||
registrationContexts.add('security');
|
||||
} else {
|
||||
const registrationContext = getRegistrationContextFromIndex(index);
|
||||
if (registrationContext) {
|
||||
registrationContexts.add(registrationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return registrationContexts;
|
||||
}
|
||||
return registrationContexts;
|
||||
}
|
||||
return registrationContexts;
|
||||
}, new Set<string>());
|
||||
},
|
||||
new Set<string>()
|
||||
);
|
||||
return Array.from(dedupeRegistrationContext);
|
||||
};
|
||||
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
|
||||
import type { CaseConnector } from '../../../common/types/domain';
|
||||
import type { CaseAttributes } from '../../../common/api/cases/case';
|
||||
import type { CaseStatuses } from '../../../common/api/cases/status';
|
||||
import type { CaseStatuses, CaseAttributes, CaseConnector } from '../../../common/types/domain';
|
||||
import type { CaseUI, UpdateByKey, UpdateKey } from '../../containers/types';
|
||||
import { useUpdateCase } from '../../containers/use_update_case';
|
||||
import { getTypedPayload } from '../../containers/utils';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue