"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.AttachmentService = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _esQuery = require("@kbn/es-query"); var _domain = require("../../../common/types/domain"); var _api = require("../../../common/api"); var _constants = require("../../../common/constants"); var _utils = require("../../client/utils"); var _utils2 = require("../../common/utils"); var _so_references = require("../so_references"); var _get = require("./operations/get"); var _attachments = require("../../common/types/attachments"); /* * 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. */ class AttachmentService { constructor(context) { (0, _defineProperty2.default)(this, "_getter", void 0); this.context = context; this._getter = new _get.AttachmentGetter(context); } get getter() { return this._getter; } async countAlertsAttachedToCase(params) { try { var _res$alerts; this.context.log.debug(`Attempting to count alerts for case id ${params.caseId}`); const res = await this.executeCaseAggregations({ ...params, attachmentType: _domain.AttachmentType.alert, aggregations: this.buildAlertsAggs() }); return res === null || res === void 0 ? void 0 : (_res$alerts = res.alerts) === null || _res$alerts === void 0 ? void 0 : _res$alerts.value; } catch (error) { this.context.log.error(`Error while counting alerts for case id ${params.caseId}: ${error}`); throw error; } } buildAlertsAggs() { return { alerts: { cardinality: { field: `${_constants.CASE_COMMENT_SAVED_OBJECT}.attributes.alertId` } } }; } /** * Executes the aggregations against a type of attachment attached to a case. */ async executeCaseAggregations({ caseId, filter, aggregations, attachmentType }) { try { this.context.log.debug(`Attempting to aggregate for case id ${caseId}`); const attachmentFilter = (0, _utils.buildFilter)({ filters: attachmentType, field: 'type', operator: 'or', type: _constants.CASE_COMMENT_SAVED_OBJECT }); const combinedFilter = (0, _utils.combineFilters)([attachmentFilter, filter]); const response = await this.context.unsecuredSavedObjectsClient.find({ type: _constants.CASE_COMMENT_SAVED_OBJECT, hasReference: { type: _constants.CASE_SAVED_OBJECT, id: caseId }, page: 1, perPage: 1, sortField: _utils2.defaultSortField, aggs: aggregations, filter: combinedFilter }); return response.aggregations; } catch (error) { this.context.log.error(`Error while executing aggregation for case id ${caseId}: ${error}`); throw error; } } /** * Counts the persistableState and externalReference attachments that are not .files */ async countPersistableStateAndExternalReferenceAttachments({ caseId }) { try { this.context.log.debug(`Attempting to count persistableState and externalReference attachments for case id ${caseId}`); const typeFilter = (0, _utils.buildFilter)({ filters: [_domain.AttachmentType.persistableState, _domain.AttachmentType.externalReference], field: 'type', operator: 'or', type: _constants.CASE_COMMENT_SAVED_OBJECT }); const excludeFilesFilter = (0, _esQuery.fromKueryExpression)(`not ${_constants.CASE_COMMENT_SAVED_OBJECT}.attributes.externalReferenceAttachmentTypeId: ${_constants.FILE_ATTACHMENT_TYPE}`); const combinedFilter = (0, _utils.combineFilters)([typeFilter, excludeFilesFilter]); const response = await this.context.unsecuredSavedObjectsClient.find({ type: _constants.CASE_COMMENT_SAVED_OBJECT, hasReference: { type: _constants.CASE_SAVED_OBJECT, id: caseId }, page: 1, perPage: 1, sortField: _utils2.defaultSortField, filter: combinedFilter }); return response.total; } catch (error) { this.context.log.error(`Error while attempting to count persistableState and externalReference attachments for case id ${caseId}: ${error}`); throw error; } } /** * Executes the aggregations against the actions attached to a case. */ async executeCaseActionsAggregations(params) { try { this.context.log.debug(`Attempting to count actions for case id ${params.caseId}`); return await this.executeCaseAggregations({ ...params, attachmentType: _domain.AttachmentType.actions }); } catch (error) { this.context.log.error(`Error while counting actions for case id ${params.caseId}: ${error}`); throw error; } } async bulkDelete({ attachmentIds, refresh }) { try { if (attachmentIds.length <= 0) { return; } this.context.log.debug(`Attempting to DELETE attachments ${attachmentIds}`); await this.context.unsecuredSavedObjectsClient.bulkDelete(attachmentIds.map(id => ({ id, type: _constants.CASE_COMMENT_SAVED_OBJECT })), { refresh }); } catch (error) { this.context.log.error(`Error on DELETE attachments ${attachmentIds}: ${error}`); throw error; } } async create({ attributes, references, id, refresh }) { try { this.context.log.debug(`Attempting to POST a new comment`); const decodedAttributes = (0, _api.decodeOrThrow)(_domain.AttachmentAttributesRt)(attributes); const { attributes: extractedAttributes, references: extractedReferences } = (0, _so_references.extractAttachmentSORefsFromAttributes)(decodedAttributes, references, this.context.persistableStateAttachmentTypeRegistry); const attachment = await this.context.unsecuredSavedObjectsClient.create(_constants.CASE_COMMENT_SAVED_OBJECT, extractedAttributes, { references: extractedReferences, id, refresh }); const transformedAttachment = (0, _so_references.injectAttachmentSOAttributesFromRefs)(attachment, this.context.persistableStateAttachmentTypeRegistry); const validatedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentTransformedAttributesRt)(transformedAttachment.attributes); return Object.assign(transformedAttachment, { attributes: validatedAttributes }); } catch (error) { this.context.log.error(`Error on POST a new comment: ${error}`); throw error; } } async bulkCreate({ attachments, refresh }) { try { this.context.log.debug(`Attempting to bulk create attachments`); const res = await this.context.unsecuredSavedObjectsClient.bulkCreate(attachments.map(attachment => { const decodedAttributes = (0, _api.decodeOrThrow)(_domain.AttachmentAttributesRt)(attachment.attributes); const { attributes: extractedAttributes, references: extractedReferences } = (0, _so_references.extractAttachmentSORefsFromAttributes)(decodedAttributes, attachment.references, this.context.persistableStateAttachmentTypeRegistry); return { type: _constants.CASE_COMMENT_SAVED_OBJECT, ...attachment, attributes: extractedAttributes, references: extractedReferences }; }), { refresh }); return this.transformAndDecodeBulkCreateResponse(res); } catch (error) { this.context.log.error(`Error on bulk create attachments: ${error}`); throw error; } } transformAndDecodeBulkCreateResponse(res) { const validatedAttachments = []; for (const so of res.saved_objects) { if ((0, _utils2.isSOError)(so)) { validatedAttachments.push(so); } else { const transformedAttachment = (0, _so_references.injectAttachmentSOAttributesFromRefs)(so, this.context.persistableStateAttachmentTypeRegistry); const validatedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentTransformedAttributesRt)(transformedAttachment.attributes); validatedAttachments.push(Object.assign(so, { attributes: validatedAttributes })); } } return Object.assign(res, { saved_objects: validatedAttachments }); } async update({ attachmentId, updatedAttributes, options }) { try { var _options$references; this.context.log.debug(`Attempting to UPDATE comment ${attachmentId}`); const decodedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentPartialAttributesRt)(updatedAttributes); const { attributes: extractedAttributes, references: extractedReferences, didDeleteOperation } = (0, _so_references.extractAttachmentSORefsFromAttributes)(decodedAttributes, (_options$references = options === null || options === void 0 ? void 0 : options.references) !== null && _options$references !== void 0 ? _options$references : [], this.context.persistableStateAttachmentTypeRegistry); const shouldUpdateRefs = extractedReferences.length > 0 || didDeleteOperation; const res = await this.context.unsecuredSavedObjectsClient.update(_constants.CASE_COMMENT_SAVED_OBJECT, attachmentId, extractedAttributes, { ...options, /** * If options?.references are undefined and there is no field to move to the refs * then the extractedReferences will be an empty array. If we pass the empty array * on the update then all previously refs will be removed. The check below is needed * to prevent this. */ references: shouldUpdateRefs ? extractedReferences : undefined }); const transformedAttachment = (0, _so_references.injectAttachmentSOAttributesFromRefsForPatch)(updatedAttributes, res, this.context.persistableStateAttachmentTypeRegistry); const validatedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentPartialAttributesRt)(transformedAttachment.attributes); return Object.assign(transformedAttachment, { attributes: validatedAttributes }); } catch (error) { this.context.log.error(`Error on UPDATE comment ${attachmentId}: ${error}`); throw error; } } async bulkUpdate({ comments, refresh }) { try { this.context.log.debug(`Attempting to UPDATE comments ${comments.map(c => c.attachmentId).join(', ')}`); const res = await this.context.unsecuredSavedObjectsClient.bulkUpdate(comments.map(c => { var _c$options$references, _c$options; const decodedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentPartialAttributesRt)(c.updatedAttributes); const { attributes: extractedAttributes, references: extractedReferences, didDeleteOperation } = (0, _so_references.extractAttachmentSORefsFromAttributes)(decodedAttributes, (_c$options$references = (_c$options = c.options) === null || _c$options === void 0 ? void 0 : _c$options.references) !== null && _c$options$references !== void 0 ? _c$options$references : [], this.context.persistableStateAttachmentTypeRegistry); const shouldUpdateRefs = extractedReferences.length > 0 || didDeleteOperation; return { ...c.options, type: _constants.CASE_COMMENT_SAVED_OBJECT, id: c.attachmentId, attributes: extractedAttributes, /* If c.options?.references are undefined and there is no field to move to the refs * then the extractedAttributes will be an empty array. If we pass the empty array * on the update then all previously refs will be removed. The check below is needed * to prevent this. */ references: shouldUpdateRefs ? extractedReferences : undefined }; }), { refresh }); return this.transformAndDecodeBulkUpdateResponse(res, comments); } catch (error) { this.context.log.error(`Error on UPDATE comments ${comments.map(c => c.attachmentId).join(', ')}: ${error}`); throw error; } } transformAndDecodeBulkUpdateResponse(res, comments) { const validatedAttachments = []; for (let i = 0; i < res.saved_objects.length; i++) { const attachment = res.saved_objects[i]; if ((0, _utils2.isSOError)(attachment)) { // Forcing the type here even though it is an error. The client is responsible for // determining what to do with the errors // TODO: we should fix the return type of this function so that it can return errors validatedAttachments.push(attachment); } else { const transformedAttachment = (0, _so_references.injectAttachmentSOAttributesFromRefsForPatch)(comments[i].updatedAttributes, attachment, this.context.persistableStateAttachmentTypeRegistry); const validatedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentPartialAttributesRt)(transformedAttachment.attributes); validatedAttachments.push(Object.assign(transformedAttachment, { attributes: validatedAttributes })); } } return Object.assign(res, { saved_objects: validatedAttachments }); } async find({ options }) { try { this.context.log.debug(`Attempting to find comments`); const res = await this.context.unsecuredSavedObjectsClient.find({ sortField: _utils2.defaultSortField, ...options, type: _constants.CASE_COMMENT_SAVED_OBJECT }); const validatedAttachments = []; for (const so of res.saved_objects) { const transformedAttachment = (0, _so_references.injectAttachmentSOAttributesFromRefs)(so, this.context.persistableStateAttachmentTypeRegistry // casting here because injectAttachmentSOAttributesFromRefs returns a SavedObject but we need a SavedObjectsFindResult // which has the score in it. The score is returned but the type is not correct ); const validatedAttributes = (0, _api.decodeOrThrow)(_attachments.AttachmentTransformedAttributesRt)(transformedAttachment.attributes); validatedAttachments.push(Object.assign(transformedAttachment, { attributes: validatedAttributes })); } return Object.assign(res, { saved_objects: validatedAttachments }); } catch (error) { this.context.log.error(`Error on find comments: ${error}`); throw error; } } } exports.AttachmentService = AttachmentService;