diff --git a/opencti-platform/opencti-graphql/src/database/engine.js b/opencti-platform/opencti-graphql/src/database/engine.js index 0035d590f2915..8002f7ab81db0 100644 --- a/opencti-platform/opencti-graphql/src/database/engine.js +++ b/opencti-platform/opencti-graphql/src/database/engine.js @@ -3683,7 +3683,7 @@ const copyLiveElementToDraft = async (context, user, element) => { const updatedElement = structuredClone(element); const newId = generateInternalId(); const setDraftData = `ctx._id="${newId}";ctx._source.draft_ids=['${draftContext}'];`; - await elReindexElements(context, user, [element.id], element._index, INDEX_DRAFT, setDraftData); + await elReindexElements(context, user, [element.internal_id], element._index, INDEX_DRAFT, setDraftData); updatedElement._id = newId; updatedElement._index = INDEX_DRAFT; @@ -3698,7 +3698,7 @@ const copyLiveElementToDraft = async (context, user, element) => { ` } }; - await elUpdate(element._index, element.id, addDraftIdScript); + await elUpdate(element._index, element.internal_id, addDraftIdScript); return updatedElement; }; @@ -3913,14 +3913,20 @@ const elUpdateConnectionsOfElement = async (documentId, documentBody) => { throw DatabaseError('Error updating connections', { cause: err, documentId, body: documentBody }); }); }; -export const elUpdateElement = async (instance) => { - const esData = prepareElementForIndexing(instance); +export const elUpdateElement = async (context, user, instance) => { + const draftContext = inDraftContext(context, user); + let instanceToUse = instance; + // We still want to be able to update internal entities in draft, but we don't want to copy them to draft index + if (draftContext && !isInternalObject(instance.entity_type) && !isInternalRelationship(instance.entity_type)) { + instanceToUse = await getElementDraftVersion(context, user, instance); + } + const esData = prepareElementForIndexing(instanceToUse); validateDataBeforeIndexing(esData); - const dataToReplace = R.dissoc('representative', esData); - const replacePromise = elReplace(instance._index, instance.internal_id, { doc: dataToReplace }); + const dataToReplace = R.pipe(R.dissoc('representative'), R.dissoc('_id'))(esData); + const replacePromise = elReplace(instanceToUse._index, instanceToUse._id ?? instanceToUse.internal_id, { doc: dataToReplace }); // If entity with a name, must update connections let connectionPromise = Promise.resolve(); - if (esData.name && isStixObject(instance.entity_type)) { + if (esData.name && isStixObject(instanceToUse.entity_type)) { connectionPromise = elUpdateConnectionsOfElement(instance.internal_id, { name: extractEntityRepresentativeName(esData) }); } return Promise.all([replacePromise, connectionPromise]); diff --git a/opencti-platform/opencti-graphql/src/database/middleware.js b/opencti-platform/opencti-graphql/src/database/middleware.js index 971f6e2e0b7fc..cacfcc63ed992 100644 --- a/opencti-platform/opencti-graphql/src/database/middleware.js +++ b/opencti-platform/opencti-graphql/src/database/middleware.js @@ -889,6 +889,7 @@ const partialInstanceWithInputs = (instance, inputs) => { const inputData = updatedInputsToData(instance, inputs); return { _index: instance._index, + _id: instance._id, internal_id: instance.internal_id, entity_type: instance.entity_type, ...inputData, @@ -1362,7 +1363,7 @@ const mergeEntitiesRaw = async (context, user, targetEntity, sourceEntities, tar // Elastic update with partial instance to prevent data override if (impactedInputs.length > 0) { const updateAsInstance = partialInstanceWithInputs(targetEntity, impactedInputs); - await elUpdateElement(updateAsInstance); + await elUpdateElement(context, user, updateAsInstance); logApp.info(`[OPENCTI] Merging attributes success for ${targetEntity.internal_id}`, { update: updateAsInstance }); } }; @@ -2133,7 +2134,7 @@ export const updateAttributeMetaResolved = async (context, user, initial, inputs // Impacting information if (impactedInputs.length > 0) { const updateAsInstance = partialInstanceWithInputs(updatedInstance, impactedInputs); - await elUpdateElement(updateAsInstance); + await elUpdateElement(context, user, updateAsInstance); } if (relationsToDelete.length > 0) { await elDeleteElements(context, user, relationsToDelete); diff --git a/opencti-platform/opencti-graphql/src/domain/stixCoreObject.js b/opencti-platform/opencti-graphql/src/domain/stixCoreObject.js index a3fc95f934cde..a574d202676a2 100644 --- a/opencti-platform/opencti-graphql/src/domain/stixCoreObject.js +++ b/opencti-platform/opencti-graphql/src/domain/stixCoreObject.js @@ -641,7 +641,7 @@ export const stixCoreObjectImportPush = async (context, user, id, file, args = { // Patch the updated_at to force live stream evolution const eventFile = storeFileConverter(user, up); const files = [...(previous.x_opencti_files ?? []).filter((f) => f.id !== up.id), eventFile]; - await elUpdateElement({ + await elUpdateElement(context, user, { _index: previous._index, internal_id: internalId, entity_type: previous.entity_type, // required for schema validation @@ -715,7 +715,7 @@ export const stixCoreObjectImportDelete = async (context, user, fileId) => { await deleteFile(context, user, fileId); // Patch the updated_at to force live stream evolution const files = (previous.x_opencti_files ?? []).filter((f) => f.id !== fileId); - await elUpdateElement({ + await elUpdateElement(context, user, { _index: previous._index, internal_id: entityId, updated_at: now(),