new: [WiP] edit refactor

pull/9432/head
iglocska 2023-11-20 14:13:15 +01:00
parent d744e6f3d5
commit d015f9cae7
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
6 changed files with 386 additions and 98 deletions

View File

@ -2794,7 +2794,14 @@ class EventsController extends AppController
$this->request->data = array('Event' => $this->request->data);
}
$fast_update = $this->request->param('named.fast_update');
$result = $this->Event->_edit($this->request->data, $this->Auth->user(), $id, null, null, false, $fast_update);
if (!empty($this->request->data['Event']['fast_update'])) {
$fast_update = (bool)$this->request->data['Event']['fast_update'];
}
if ($fast_update) {
$this->Event->fast_update = true;
$this->Event->Attribute->fast_update = true;
}
$result = $this->Event->_edit($this->request->data, $this->Auth->user(), $id, null, null, false);
if ($result === true) {
// REST users want to see the newly created event
$metadata = $this->request->param('named.metadata');

View File

@ -83,6 +83,8 @@ class Attribute extends AppModel
/** @var array */
private $old;
private $updateLookupTable = [];
public function __construct($id = false, $table = null, $ds = null)
{
parent::__construct($id, $table, $ds);
@ -327,6 +329,8 @@ class Attribute extends AppModel
'sha512' => 128,
);
public $fast_update = false;
public function afterFind($results, $primary = false)
{
foreach ($results as &$v) {
@ -347,7 +351,7 @@ class Attribute extends AppModel
if (empty($attribute['uuid'])) {
$attribute['uuid'] = CakeText::uuid();
}
if (!empty($attribute['id'])) {
if (!$this->fast_update && !empty($attribute['id'])) {
$this->old = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Attribute.id' => $attribute['id']),
@ -439,37 +443,41 @@ class Attribute extends AppModel
$this->AttributeTag->attachTagToAttribute($this->id, $attribute['event_id'], $tagId);
}
}
// update correlation...
if (isset($attribute['deleted']) && $attribute['deleted']) {
$this->Correlation->beforeSaveCorrelation($attribute);
$this->Correlation->advancedCorrelationsUpdate($attribute);
if (isset($attribute['event_id'])) {
$this->__alterAttributeCount($attribute['event_id'], false);
}
} else {
/*
* Only recorrelate if:
* - We are dealing with a new attribute OR
* - The existing attribute's previous state is known AND
* value, type, disable correlation or distribution have changed
* This will avoid recorrelations when it's not really needed, such as adding a tag
*/
if (!$created) {
if (
empty($this->old) ||
$attribute['value'] != $this->old['Attribute']['value'] ||
$attribute['disable_correlation'] != $this->old['Attribute']['disable_correlation'] ||
$attribute['type'] != $this->old['Attribute']['type'] ||
$attribute['distribution'] != $this->old['Attribute']['distribution'] ||
$attribute['sharing_group_id'] != $this->old['Attribute']['sharing_group_id']
) {
$this->Correlation->beforeSaveCorrelation($attribute);
// Let's store all the uuid -> ID lookups so we can extract the IDs after a SaveMany() easily
$this->updateLookupTable[$attribute['uuid']] = $attribute['id'];
if (!$this->fast_update) {
// update correlation...
if (isset($attribute['deleted']) && $attribute['deleted']) {
$this->Correlation->beforeSaveCorrelation($attribute);
$this->Correlation->advancedCorrelationsUpdate($attribute);
if (isset($attribute['event_id'])) {
$this->__alterAttributeCount($attribute['event_id'], false);
}
} else {
/*
* Only recorrelate if:
* - We are dealing with a new attribute OR
* - The existing attribute's previous state is known AND
* value, type, disable correlation or distribution have changed
* This will avoid recorrelations when it's not really needed, such as adding a tag
*/
if (!$created) {
if (
empty($this->old) ||
$attribute['value'] != $this->old['Attribute']['value'] ||
$attribute['disable_correlation'] != $this->old['Attribute']['disable_correlation'] ||
$attribute['type'] != $this->old['Attribute']['type'] ||
$attribute['distribution'] != $this->old['Attribute']['distribution'] ||
$attribute['sharing_group_id'] != $this->old['Attribute']['sharing_group_id']
) {
$this->Correlation->beforeSaveCorrelation($attribute);
$this->Correlation->afterSaveCorrelation($attribute, false, $passedEvent);
$this->Correlation->advancedCorrelationsUpdate($attribute);
}
} else {
$this->Correlation->afterSaveCorrelation($attribute, false, $passedEvent);
$this->Correlation->advancedCorrelationsUpdate($attribute);
}
} else {
$this->Correlation->afterSaveCorrelation($attribute, false, $passedEvent);
$this->Correlation->advancedCorrelationsUpdate($attribute);
}
}
$result = true;
@ -484,47 +492,49 @@ class Attribute extends AppModel
$result = $this->saveAttachment($attribute);
}
}
$pubToZmq = $this->pubToZmq('attribute');
$kafkaTopic = $this->kafkaTopic('attribute');
$isTriggerCallable = $this->isTriggerCallable('attribute-after-save');
if ($pubToZmq || $kafkaTopic || $isTriggerCallable) {
$attributeForPublish = $this->fetchAttribute($this->id);
if (!empty($attributeForPublish)) {
$user = array(
'org_id' => -1,
'Role' => array(
'perm_site_admin' => 1
)
);
$attributeForPublish['Attribute']['Sighting'] = $this->Sighting->attachToEvent($attributeForPublish, $user, $attributeForPublish);
$action = $created ? 'add' : 'edit';
if (!empty($attribute['deleted'])) {
$action = 'soft-delete';
}
if ($pubToZmq) {
if (Configure::read('Plugin.ZeroMQ_include_attachments') && $this->typeIsAttachment($attributeForPublish['Attribute']['type'])) {
$attributeForPublish['Attribute']['data'] = $this->base64EncodeAttachment($attributeForPublish['Attribute']);
if (!$this->fast_update) {
$pubToZmq = $this->pubToZmq('attribute');
$kafkaTopic = $this->kafkaTopic('attribute');
$isTriggerCallable = $this->isTriggerCallable('attribute-after-save');
if ($pubToZmq || $kafkaTopic || $isTriggerCallable) {
$attributeForPublish = $this->fetchAttribute($this->id);
if (!empty($attributeForPublish)) {
$user = array(
'org_id' => -1,
'Role' => array(
'perm_site_admin' => 1
)
);
$attributeForPublish['Attribute']['Sighting'] = $this->Sighting->attachToEvent($attributeForPublish, $user, $attributeForPublish);
$action = $created ? 'add' : 'edit';
if (!empty($attribute['deleted'])) {
$action = 'soft-delete';
}
$pubSubTool = $this->getPubSubTool();
$pubSubTool->attribute_save($attributeForPublish, $action);
unset($attributeForPublish['Attribute']['data']);
}
if ($kafkaTopic) {
if (Configure::read('Plugin.Kafka_include_attachments') && $this->typeIsAttachment($attributeForPublish['Attribute']['type'])) {
$attributeForPublish['Attribute']['data'] = $this->base64EncodeAttachment($attributeForPublish['Attribute']);
if ($pubToZmq) {
if (Configure::read('Plugin.ZeroMQ_include_attachments') && $this->typeIsAttachment($attributeForPublish['Attribute']['type'])) {
$attributeForPublish['Attribute']['data'] = $this->base64EncodeAttachment($attributeForPublish['Attribute']);
}
$pubSubTool = $this->getPubSubTool();
$pubSubTool->attribute_save($attributeForPublish, $action);
unset($attributeForPublish['Attribute']['data']);
}
if ($kafkaTopic) {
if (Configure::read('Plugin.Kafka_include_attachments') && $this->typeIsAttachment($attributeForPublish['Attribute']['type'])) {
$attributeForPublish['Attribute']['data'] = $this->base64EncodeAttachment($attributeForPublish['Attribute']);
}
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $attributeForPublish, $action);
}
if ($isTriggerCallable) {
$workflowErrors = [];
$logging = [
'model' => 'Attribute',
'action' => $action,
'id' => $attributeForPublish['Attribute']['id'],
];
$triggerData = $attributeForPublish;
$this->executeTrigger('attribute-after-save', $triggerData, $workflowErrors, $logging);
}
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $attributeForPublish, $action);
}
if ($isTriggerCallable) {
$workflowErrors = [];
$logging = [
'model' => 'Attribute',
'action' => $action,
'id' => $attributeForPublish['Attribute']['id'],
];
$triggerData = $attributeForPublish;
$this->executeTrigger('attribute-after-save', $triggerData, $workflowErrors, $logging);
}
}
}
@ -623,11 +633,13 @@ class Attribute extends AppModel
// make some changes to the inserted value
$attribute['value'] = AttributeValidationTool::modifyBeforeValidation($type, $attribute['value']);
// Run user defined regexp to attribute value
$result = $this->runRegexp($type, $attribute['value']);
if ($result === false) {
$this->invalidate('value', 'This value is blocked by a regular expression in the import filters.');
} else {
$attribute['value'] = $result;
if (!$this->fast_update) {
$result = $this->runRegexp($type, $attribute['value']);
if ($result === false) {
$this->invalidate('value', 'This value is blocked by a regular expression in the import filters.');
} else {
$attribute['value'] = $result;
}
}
if (empty($attribute['comment'])) {
@ -676,7 +688,6 @@ class Attribute extends AppModel
$attribute['disable_correlation'] = true;
}
}
// return true, otherwise the object cannot be saved
return true;
}
@ -729,6 +740,13 @@ class Attribute extends AppModel
*/
public function valueIsUnique($fields)
{
// This is somewhat dangerous, fast_update assumes that you are just updating an existing attribute's
// non uniqueness modifying fields (first/last seen, comment, tags, timestamp, etc)
// By ignoring this warning, you are introducing potential duplicates.
if ($this->fast_update) {
return true;
}
if (!empty($this->data['Attribute']['deleted'])) {
return true;
}
@ -2555,8 +2573,11 @@ class Attribute extends AppModel
return $attribute;
}
public function editAttribute($attribute, array $event, $user, $objectId, $log = false, $force = false, &$nothingToChange = false, $server = null, $fast_update = false)
public function editAttribute($attribute, array $event, $user, $objectId, $log = false, $force = false, &$nothingToChange = false, $server = null)
{
if ($this->fast_update) {
$this->Behaviors->unload('SysLogLogable.SysLogLogable');
}
$eventId = $event['Event']['id'];
$attribute['event_id'] = $eventId;
$attribute['object_id'] = $objectId;
@ -2632,13 +2653,16 @@ class Attribute extends AppModel
$saveOptions = [
'fieldList' => $fieldList,
'parentEvent' => $event
'parentEvent' => $event,
'atomic' => false
];
if ($fast_update) {
$saveOptions['callbacks'] = false;
}
// This is somewhat dangerous, fast_update assumes that you are just updating an existing attribute's
// non uniqueness modifying fields (first/last seen, comment, tags, timestamp, etc)
// By ignoring this warning, you are introducing potential duplicates.
if ($this->fast_update) {
$saveOptions['skipAuditLog'] = true;
}
if (!$this->save(['Attribute' => $attribute], $saveOptions)) {
$this->logDropped($user, $attribute, 'edit');
return $this->validationErrors;
@ -2677,6 +2701,197 @@ class Attribute extends AppModel
return true;
}
public function editAttribute2($attribute, array $event, $user, $objectId, $log = false, $force = false, &$nothingToChange = false, $server = null)
{
if ($this->fast_update) {
$this->Behaviors->unload('SysLogLogable.SysLogLogable');
}
$eventId = $event['Event']['id'];
$attribute['event_id'] = $eventId;
$attribute['object_id'] = $objectId;
if (isset($attribute['encrypt'])) {
$attribute = $this->onDemandEncrypt($attribute);
}
unset($attribute['id']);
if (isset($attribute['uuid'])) {
$existingAttribute = $this->find('first', array(
'conditions' => array('Attribute.uuid' => $attribute['uuid']),
'recursive' => -1,
));
if (!empty($existingAttribute)) {
if ($existingAttribute['Attribute']['event_id'] != $eventId || $existingAttribute['Attribute']['object_id'] != $objectId) {
$change = 'An attribute was blocked from being saved due to a duplicate UUID. The uuid in question is: ' . $attribute['uuid'] . '. This can also be due to the same attribute (or an attribute with the same UUID) existing in a different event / object)';
$this->loadLog()->createLogEntry($user, 'edit', 'Attribute', 0, 'Duplicate UUID found in attribute', $change);
return true;
}
// If a field is not set in the request, just reuse the old value
$recoverFields = array('value', 'to_ids', 'distribution', 'category', 'type', 'comment', 'sharing_group_id', 'object_id', 'object_relation', 'first_seen', 'last_seen');
foreach ($recoverFields as $rF) {
if (!isset($attribute[$rF])) {
$attribute[$rF] = $existingAttribute['Attribute'][$rF];
}
}
$attribute['id'] = $existingAttribute['Attribute']['id'];
// Check if the attribute's timestamp is bigger than the one that already exists.
// If yes, it means that it's newer, so insert it. If no, it means that it's the same attribute or older - don't insert it, insert the old attribute.
// Alternatively, we could unset this attribute from the request, but that could lead with issues if we decide that we want to start deleting attributes that don't exist in a pushed event.
if (isset($attribute['timestamp'])) {
if (!$force && $attribute['timestamp'] <= $existingAttribute['Attribute']['timestamp']) {
$nothingToChange = true;
return true;
}
} else {
$attribute['timestamp'] = time();
}
} else {
$this->create();
}
} else {
$this->create();
}
$attribute['event_id'] = $eventId;
if (isset($attribute['distribution']) && $attribute['distribution'] == 4) {
if (!empty($attribute['SharingGroup'])) {
$attribute['sharing_group_id'] = $this->SharingGroup->captureSG($attribute['SharingGroup'], $user);
} elseif (!empty($attribute['sharing_group_id'])) {
if (!$this->SharingGroup->checkIfAuthorised($user, $attribute['sharing_group_id'])) {
unset($attribute['sharing_group_id']);
}
}
if (empty($attribute['sharing_group_id'])) {
$attribute_short = (isset($attribute['category']) ? $attribute['category'] : 'N/A') . '/' . (isset($attribute['type']) ? $attribute['type'] : 'N/A') . ' ' . (isset($attribute['value']) ? $attribute['value'] : 'N/A');
$this->loadLog()->createLogEntry($user, 'edit', 'Attribute', 0,
'Attribute dropped due to invalid sharing group for Event ' . $eventId . ' failed: ' . $attribute_short,
'Validation errors: ' . json_encode($this->validationErrors) . ' Full Attribute: ' . json_encode($attribute)
);
return 'Invalid sharing group choice.';
}
} else if (!isset($attribute['distribution'])) {
$attribute['distribution'] = $this->defaultDistribution();
}
// This is somewhat dangerous, fast_update assumes that you are just updating an existing attribute's
// non uniqueness modifying fields (first/last seen, comment, tags, timestamp, etc)
// By ignoring this warning, you are introducing potential duplicates.
if ($this->fast_update) {
$saveOptions['skipAuditLog'] = true;
}
return $attribute;
}
public function editAttributeBulk($attributes, $event, $user)
{
$fieldList = self::EDITABLE_FIELDS;
$addableFieldList = array('event_id', 'type', 'uuid', 'object_id', 'object_relation');
$fieldList = array_merge($fieldList, $addableFieldList);
$saveOptions = [
'fieldList' => $fieldList,
'parentEvent' => $event,
'atomic' => true,
'validate' => true
];
$this->saveMany($attributes, $saveOptions);
if (!empty($this->validationErrors)) {
foreach ($this->validationErrors as $key => $validationError) {
$this->logDropped($user, $attributes[$key], 'edit', $validationError);
}
}
return true;
}
public function editAttributePostProcessing($attributes, $event, $user)
{
$eventId = $event['Event']['id'];
$tagActions = [];
foreach ($attributes as $attribute) {
$attributeId = $this->updateLookupTable[$attribute['uuid']];
if (!empty($attribute['Sighting'])) {
$this->Sighting->captureSightings($attribute['Sighting'], $this->id, $eventId, $user);
}
if ($user['Role']['perm_tagger']) {
/*
We should unwrap the line below and remove the server option in the future once we have tag soft-delete
A solution to still keep the behavior for previous instance could be to not soft-delete the Tag if the remote instance
has a version below x
*/
if (isset($server) && isset($server['Server']['remove_missing_tags']) && $server['Server']['remove_missing_tags']) {
$existingTags = $this->AttributeTag->find('all', [
'recursive' => -1,
'conditions' => ['attribute_id' => $attribute['id']]
]);
$this->AttributeTag->pruneOutdatedAttributeTagsFromSync(isset($attribute['Tag']) ? $attribute['Tag'] : array(), $existingTags['AttributeTag']);
}
$tag_id_store = [];
if (isset($attribute['Tag'])) {
foreach ($attribute['Tag'] as $tag) {
if (empty($tag_id_store[$tag['name']])) {
$tag_id = $this->AttributeTag->Tag->captureTag($tag, $user);
if ($tag_id) {
$tag_id_store[$tag['name']] = $tag_id;
}
} else {
$tag_id = $tag_id_store[$tag['name']];
}
if ($tag_id) {
$tag['id'] = $tag_id;
// fix the IDs here
$tag_result = $this->AttributeTag->handleAttributeTag($attributeId, $attribute['event_id'], $tag, true);
if (isset($tag_result['attach'])) {
$tagActions['attach'][$attributeId . '-' . $tag_id] = $tag_result['attach'];
} else if(isset($tag_result['detach'])) {
$tagActions['detach'][] = $tag_result['detach'];
}
} else {
// If we couldn't attach the tag it is most likely because we couldn't create it - which could have many reasons
// However, if a tag couldn't be added, it could also be that the user is a tagger but not a tag editor
// In which case if no matching tag is found, no tag ID is returned. Logging these is pointless as it is the correct behaviour.
if ($user['Role']['perm_tag_editor']) {
$this->loadLog()->createLogEntry($user, 'edit', 'Attribute', $attributeId, 'Failed create or attach Tag ' . $tag['name'] . ' to the attribute.');
}
}
}
}
}
}
if (!empty($tagActions['attach'])) {
foreach ($tagActions['attach'] as $k => $attach) {
$existingAssociation = $this->AttributeTag->find('first', [
'conditions' => [
'tag_id' => $attach['tag_id'],
'attribute_id' => $attach['attribute_id']
],
'recursive' => -1
]);
if (!empty($existingAssociation)) {
$attach['id'] = $existingAssociation['AttributeTag']['id'];
if ($attach['local'] == $existingAssociation['AttributeTag']['local'] && $attach['relationship_type'] == $existingAssociation['AttributeTag']['relationship_type']) {
unset($tagActions['attach'][$k]);
}
}
}
if (!empty($tagActions['attach'])) {
$this->AttributeTag->saveMany($tagActions['attach']);
}
}
if (!empty($tagActions['detach'])) {
$conditions = [];
foreach ($tagActions['detach'] as $detach) {
$conditions[] = [
'AND' => [
'attribute_id' => $detach['attribute_id'],
'tag_id' => $detach['tag_id']
]
];
}
if (!empty($conditions)) {
$this->AttributeTag->deleteAll($conditions, false);
}
}
return true;
}
/**
* @param int $id Attribute ID
* @param array $user
@ -3209,14 +3424,17 @@ class Attribute extends AppModel
* @param string $action
* @throws JsonException
*/
public function logDropped(array $user, array $attribute, $action = 'add')
public function logDropped(array $user, array $attribute, $action = 'add', $validationError = false)
{
$attribute_short = (isset($attribute['category']) ? $attribute['category'] : 'N/A') . '/' . (isset($attribute['type']) ? $attribute['type'] : 'N/A') . ' ' . (isset($attribute['value']) ? $attribute['value'] : 'N/A');
if ($validationError === false) {
$validationError = $this->validationErrors;
}
$eventId = $attribute['event_id'];
$modelId = $action === 'add' ? 0 : $this->id;
$this->loadLog()->createLogEntry($user, $action, 'Attribute', $modelId,
"Attribute dropped due to validation for Event $eventId failed: $attribute_short",
'Validation errors: ' . JsonTool::encode($this->validationErrors) . ' Full Attribute: ' . JsonTool::encode($attribute)
'Validation errors: ' . JsonTool::encode($validationError) . ' Full Attribute: ' . JsonTool::encode($attribute)
);
}

View File

@ -117,14 +117,36 @@ class AttributeTag extends AppModel
}
}
public function handleAttributeTag($attribute_id, $event_id, array $tag)
public function handleAttributeTag($attribute_id, $event_id, array $tag, $mock = false)
{
if (empty($tag['deleted'])) {
$local = isset($tag['local']) ? $tag['local'] : false;
$relationship_type = isset($tag['relationship_type']) ? $tag['relationship_type'] : false;
$this->attachTagToAttribute($attribute_id, $event_id, $tag['id'], $local, $relationship_type);
if ($mock) {
return [
'attach' => [
'attribute_id' => $attribute_id,
'event_id' => $event_id,
'tag_id' => $tag['id'],
'local' => $local,
'relationship_type' => $relationship_type
]
];
} else {
$this->attachTagToAttribute($attribute_id, $event_id, $tag['id'], $local, $relationship_type);
}
} else {
$this->detachTagFromAttribute($attribute_id, $event_id, $tag['id'], null);
if ($mock) {
return [
'detach' => [
'attribute_id' => $attribute_id,
'event_id' => $event_id,
'tag_id' => $tag['id']
]
];
} else {
$this->detachTagFromAttribute($attribute_id, $event_id, $tag['id'], null);
}
}
}

View File

@ -373,6 +373,8 @@ class Event extends AppModel
/** @var array|null */
private $eventBlockRule;
public $fast_update = false;
public function beforeDelete($cascade = true)
{
// blocklist the event UUID if the feature is enabled
@ -3983,7 +3985,6 @@ class Event extends AppModel
$data = $this->cleanupEventArrayFromXML($data);
unset($this->Attribute->validate['event_id']);
unset($this->Attribute->validate['value']['unique']); // otherwise gives bugs because event_id is not set
// reposition to get the event.id with given uuid
if (isset($data['Event']['uuid'])) {
$conditions = ['Event.uuid' => $data['Event']['uuid']];
@ -3993,7 +3994,6 @@ class Event extends AppModel
throw new InvalidArgumentException("No event UUID or ID provided.");
}
$existingEvent = $this->find('first', ['conditions' => $conditions, 'recursive' => -1]);
if ($passAlong) {
$this->Server = ClassRegistry::init('Server');
$server = $this->Server->find('first', array(
@ -4109,19 +4109,32 @@ class Event extends AppModel
'Event'
);
}
if (isset($data['Event']['Attribute'])) {
$data['Event']['Attribute'] = array_values($data['Event']['Attribute']);
foreach ($data['Event']['Attribute'] as $attribute) {
$nothingToChange = false;
$result = $this->Attribute->editAttribute($attribute, $saveResult, $user, 0, false, $force, $nothingToChange, $server, $fast_update);
if ($result !== true) {
$validationErrors['Attribute'][] = $result;
$attributes = [];
if (true) {
foreach ($data['Event']['Attribute'] as $k => $attribute) {
$nothingToChange = false;
$attributes[] = $this->Attribute->editAttribute2($attribute, $saveResult, $user, 0, false, $force, $nothingToChange, $server);
if (!$nothingToChange) {
$changed = true;
}
}
if (!$nothingToChange) {
$changed = true;
$result = $this->Attribute->editAttributeBulk($attributes, $saveResult, $user);
$result = $this->Attribute->editAttributePostProcessing($attributes, $saveResult, $user);
} else {
foreach ($data['Event']['Attribute'] as $k => $attribute) {
$nothingToChange = false;
$result = $this->Attribute->editAttribute($attribute, $saveResult, $user, 0, false, $force, $nothingToChange, $server);
if ($result !== true) {
$validationErrors['Attribute'][] = $result;
}
if (!$nothingToChange) {
$changed = true;
}
}
}
}
if (isset($data['Event']['Object'])) {
$data['Event']['Object'] = array_values($data['Event']['Object']);

View File

@ -1215,6 +1215,15 @@ class MispObject extends AppModel
}
$result = $this->Attribute->editAttribute($attribute, $event, $user, $object['id'], false, $force);
}
$attributes = [];
foreach ($object['Attribute'] as $k => $attribute) {
if (!empty($object['deleted'])) {
$attribute['deleted'] = 1;
}
$attributes[] = $this->Attribute->editAttribute2($attribute, $event, $user, $object['id'], false, $force);
}
$result = $this->Attribute->editAttributeBulk($attributes, $event, $user);
$result = $this->Attribute->editAttributePostProcessing($attributes, $event, $user);
}
return true;
}

View File

@ -39,10 +39,18 @@ class Module_attribute_edition_operation extends WorkflowBaseActionModule
protected function __saveAttributes(array $attributes, array $rData, array $params, array $user): array
{
$success = false;
foreach ($attributes as $attribute) {
$attributes = [];
$newAttributes = [];
foreach ($attributes as $k => $attribute) {
$newAttribute = $this->_editAttribute($attribute, $rData, $params);
$newAttributes[] = $newAttribute;
unset($newAttribute['timestamp']);
$saveSuccess = $this->Attribute->editAttribute($newAttribute, $rData, $user, $newAttribute['object_id']);
$attributes[] = $this->Attribute->editAttribute($newAttribute, $rData, $user, $newAttribute['object_id']);
}
$this->Attribute->editAttributeBulk($attributes, $rData, $user);
$this->Attribute->editAttributePostProcessing($attributes, $rData, $user);
foreach ($attributes as $k => $attribute) {
$saveSuccess = empty($this->Attribute->validationErrors[$k]);
if ($saveSuccess) {
$rData = $this->_overrideAttribute($attribute, $newAttribute, $rData);
}
@ -54,3 +62,14 @@ class Module_attribute_edition_operation extends WorkflowBaseActionModule
];
}
}
foreach ($object['Attribute'] as $k => $attribute) {
if (!empty($object['deleted'])) {
$attribute['deleted'] = 1;
}
$attributes[] = $this->Attribute->editAttribute2($attribute, $event, $user, $object['id'], false, $force);
}
$result = $this->Attribute->editAttributeBulk($attributes, $event, $user);
$result = $this->Attribute->editAttributePostProcessing($attributes, $event, $user);