@@ -1359,8 +1359,9 @@ const innerUpdateAttribute = (instance, rawInput) => {
1359
1359
}
1360
1360
return input ;
1361
1361
} ;
1362
- const prepareAttributesForUpdate = ( instance , elements , upsert ) => {
1362
+ const prepareAttributesForUpdate = async ( context , user , instance , elements , upsert ) => {
1363
1363
const instanceType = instance . entity_type ;
1364
+ const platformStatuses = await getEntitiesListFromCache ( context , user , ENTITY_TYPE_STATUS ) ;
1364
1365
return elements . map ( ( input ) => {
1365
1366
// Dynamic cases, attributes not defined in the schema
1366
1367
if ( input . key . startsWith ( RULE_PREFIX ) || input . key . startsWith ( REL_INDEX_PREFIX ) ) {
@@ -1371,6 +1372,37 @@ const prepareAttributesForUpdate = (instance, elements, upsert) => {
1371
1372
if ( ! def ) {
1372
1373
throw UnsupportedError ( 'Cant prepare attribute for update' , { type : instance . entity_type , name : input . key } ) ;
1373
1374
}
1375
+ // Specific case for Label
1376
+ if ( input . key === VALUE_FIELD && instanceType === ENTITY_TYPE_LABEL ) {
1377
+ return {
1378
+ key : input . key ,
1379
+ value : input . value . map ( ( v ) => v . toLowerCase ( ) )
1380
+ } ;
1381
+ }
1382
+ // Specific case for name in aliased entities
1383
+ // If name change already inside aliases, name must be kep untouched
1384
+ if ( upsert && input . key === NAME_FIELD && isStixObjectAliased ( instanceType ) ) {
1385
+ const aliasField = resolveAliasesField ( instanceType ) . name ;
1386
+ const normalizeAliases = instance [ aliasField ] ? instance [ aliasField ] . map ( ( e ) => normalizeName ( e ) ) : [ ] ;
1387
+ const name = normalizeName ( input . value . at ( 0 ) ) ;
1388
+ if ( ( normalizeAliases ) . includes ( name ) ) {
1389
+ return null ;
1390
+ }
1391
+ }
1392
+ // Aliases can't have the same name as entity name and an already existing normalized alias
1393
+ if ( input . key === ATTRIBUTE_ALIASES || input . key === ATTRIBUTE_ALIASES_OPENCTI ) {
1394
+ const filteredValues = input . value . filter ( ( e ) => normalizeName ( e ) !== normalizeName ( instance . name ) ) ;
1395
+ const uniqAliases = R . uniqBy ( ( e ) => normalizeName ( e ) , filteredValues ) ;
1396
+ return { key : input . key , value : uniqAliases } ;
1397
+ }
1398
+ // For upsert, workflow cant be reset or setup on un-existing workflow
1399
+ if ( input . key === X_WORKFLOW_ID && upsert ) {
1400
+ const workflowId = R . head ( input . value ) ;
1401
+ const workflowStatus = workflowId ? platformStatuses . find ( ( p ) => p . id === workflowId ) : workflowId ;
1402
+ if ( isEmptyField ( workflowStatus ) ) { // If workflow is not found, remove the input
1403
+ return null ;
1404
+ }
1405
+ }
1374
1406
// Check integer
1375
1407
if ( def . type === 'numeric' ) {
1376
1408
return {
@@ -1409,29 +1441,6 @@ const prepareAttributesForUpdate = (instance, elements, upsert) => {
1409
1441
} ;
1410
1442
}
1411
1443
}
1412
- // Specific case for Label
1413
- if ( input . key === VALUE_FIELD && instanceType === ENTITY_TYPE_LABEL ) {
1414
- return {
1415
- key : input . key ,
1416
- value : input . value . map ( ( v ) => v . toLowerCase ( ) )
1417
- } ;
1418
- }
1419
- // Specific case for name in aliased entities
1420
- // If name change already inside aliases, name must be kep untouched
1421
- if ( upsert && input . key === NAME_FIELD && isStixObjectAliased ( instanceType ) ) {
1422
- const aliasField = resolveAliasesField ( instanceType ) . name ;
1423
- const normalizeAliases = instance [ aliasField ] ? instance [ aliasField ] . map ( ( e ) => normalizeName ( e ) ) : [ ] ;
1424
- const name = normalizeName ( input . value . at ( 0 ) ) ;
1425
- if ( ( normalizeAliases ) . includes ( name ) ) {
1426
- return null ;
1427
- }
1428
- }
1429
- // Aliases can't have the same name as entity name and an already existing normalized alias
1430
- if ( input . key === ATTRIBUTE_ALIASES || input . key === ATTRIBUTE_ALIASES_OPENCTI ) {
1431
- const filteredValues = input . value . filter ( ( e ) => normalizeName ( e ) !== normalizeName ( instance . name ) ) ;
1432
- const uniqAliases = R . uniqBy ( ( e ) => normalizeName ( e ) , filteredValues ) ;
1433
- return { key : input . key , value : uniqAliases } ;
1434
- }
1435
1444
// No need to rework the input
1436
1445
return input ;
1437
1446
} ) . filter ( ( i ) => isNotEmptyField ( i ) ) ;
@@ -1465,7 +1474,7 @@ const updateAttributeRaw = async (context, user, instance, inputs, opts = {}) =>
1465
1474
const elements = Array . isArray ( inputs ) ? inputs : [ inputs ] ;
1466
1475
const instanceType = instance . entity_type ;
1467
1476
// Prepare attributes
1468
- const preparedElements = prepareAttributesForUpdate ( instance , elements , upsert ) ;
1477
+ const preparedElements = await prepareAttributesForUpdate ( context , user , instance , elements , upsert ) ;
1469
1478
// region Check date range
1470
1479
const inputKeys = elements . map ( ( i ) => i . key ) ;
1471
1480
if ( inputKeys . includes ( START_TIME ) || inputKeys . includes ( STOP_TIME ) ) {
@@ -2356,8 +2365,9 @@ const upsertElement = async (context, user, element, type, basePatch, opts = {})
2356
2365
const updatePatch = { ...basePatch } ;
2357
2366
// Handle attributes updates
2358
2367
if ( isNotEmptyField ( basePatch . stix_id ) || isNotEmptyField ( basePatch . x_opencti_stix_ids ) ) {
2368
+ const compareIds = [ element . standard_id , generateStandardId ( type , basePatch ) ] ;
2359
2369
const ids = [ ...( basePatch . x_opencti_stix_ids || [ ] ) ] ;
2360
- if ( isNotEmptyField ( basePatch . stix_id ) && basePatch . stix_id !== element . standard_id ) {
2370
+ if ( isNotEmptyField ( basePatch . stix_id ) && ! compareIds . includes ( basePatch . stix_id ) ) {
2361
2371
ids . push ( basePatch . stix_id ) ;
2362
2372
}
2363
2373
if ( ids . length > 0 ) {
@@ -3081,7 +3091,8 @@ const createEntityRaw = async (context, user, rawInput, type, opts = {}) => {
3081
3091
const standardId = resolvedInput . standard_id || generateStandardId ( type , resolvedInput ) ;
3082
3092
// Check if the entity exists, must be done with SYSTEM USER to really find it.
3083
3093
const existingEntities = [ ] ;
3084
- const existingByIdsPromise = internalFindByIds ( context , SYSTEM_USER , participantIds , { type } ) ;
3094
+ const finderIds = [ ...participantIds , ...( context . previousStandard ? [ context . previousStandard ] : [ ] ) ] ;
3095
+ const existingByIdsPromise = internalFindByIds ( context , SYSTEM_USER , finderIds , { type } ) ;
3085
3096
// Hash are per definition keys.
3086
3097
// When creating a hash, we can check all hashes to update or merge the result
3087
3098
// Generating multiple standard ids could be a solution but to complex to implements
@@ -3151,8 +3162,8 @@ const createEntityRaw = async (context, user, rawInput, type, opts = {}) => {
3151
3162
const concurrentAliases = R . flatten ( R . map ( ( c ) => [ c [ key ] , c . name ] , concurrentEntities ) ) ;
3152
3163
const normedAliases = R . uniq ( concurrentAliases . map ( ( c ) => normalizeName ( c ) ) ) ;
3153
3164
const filteredAliases = R . filter ( ( i ) => ! normedAliases . includes ( normalizeName ( i ) ) , resolvedInput [ key ] || [ ] ) ;
3154
- const inputAliases = { ...resolvedInput , [ key ] : filteredAliases } ;
3155
- return upsertElement ( context , user , existingByStandard , type , inputAliases , { ...opts , locks : participantIds } ) ;
3165
+ const resolvedAliases = { ...resolvedInput , [ key ] : filteredAliases } ;
3166
+ return upsertElement ( context , user , existingByStandard , type , resolvedAliases , { ...opts , locks : participantIds } ) ;
3156
3167
}
3157
3168
if ( resolvedInput . update === true ) {
3158
3169
// The new one is new reference, merge all found entities
@@ -3165,7 +3176,8 @@ const createEntityRaw = async (context, user, rawInput, type, opts = {}) => {
3165
3176
}
3166
3177
if ( resolvedInput . stix_id && ! existingEntities . map ( ( n ) => getInstanceIds ( n ) ) . flat ( ) . includes ( resolvedInput . stix_id ) ) {
3167
3178
const target = R . head ( filteredEntities ) ;
3168
- return upsertElement ( context , user , target , type , { x_opencti_stix_ids : [ ...target . x_opencti_stix_ids , resolvedInput . stix_id ] } , { ...opts , locks : participantIds } ) ;
3179
+ const resolvedStixIds = { ...target , x_opencti_stix_ids : [ ...target . x_opencti_stix_ids , resolvedInput . stix_id ] } ;
3180
+ return upsertElement ( context , user , target , type , resolvedStixIds , { ...opts , locks : participantIds } ) ;
3169
3181
}
3170
3182
// If not we dont know what to do, just throw an exception.
3171
3183
throw UnsupportedError ( 'Cant upsert entity. Too many entities resolved' , { input, entityIds } ) ;
0 commit comments