chg: [internal] Faster fetching object templates for merging

pull/8611/head
Jakub Onderka 2022-09-22 16:09:18 +02:00
parent 41f0c6eced
commit ce5fb46654
4 changed files with 52 additions and 50 deletions

View File

@ -1130,16 +1130,17 @@ class ObjectsController extends AppController
$this->set('unmapped', $unmappedAttributes);
}
function proposeObjectsFromAttributes($event_id, $selected_attributes='[]')
public function proposeObjectsFromAttributes($eventId, $selectedAttributes='[]')
{
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException(__('This action can only be reached via AJAX.'));
}
$selected_attributes = json_decode($selected_attributes, true);
$res = $this->MispObject->validObjectsFromAttributeTypes($this->Auth->user(), $event_id, $selected_attributes);
$potential_templates = $res['templates'];
$attribute_types = $res['types'];
usort($potential_templates, function($a, $b) {
$selectedAttributes = $this->_jsonDecode($selectedAttributes);
$res = $this->MispObject->validObjectsFromAttributeTypes($this->Auth->user(), $eventId, $selectedAttributes);
$potentialTemplates = $res['templates'];
$attributeTypes = $res['types'];
usort($potentialTemplates, function($a, $b) {
if ($a['ObjectTemplate']['id'] == $b['ObjectTemplate']['id']) {
return 0;
} else if (is_array($a['ObjectTemplate']['compatibility']) && is_array($b['ObjectTemplate']['compatibility'])) {
@ -1152,9 +1153,9 @@ class ObjectsController extends AppController
return count($a['ObjectTemplate']['invalidTypes']) > count($b['ObjectTemplate']['invalidTypes']) ? 1 : -1;
}
});
$this->set('potential_templates', $potential_templates);
$this->set('selected_types', $attribute_types);
$this->set('event_id', $event_id);
$this->set('potential_templates', $potentialTemplates);
$this->set('selected_types', $attributeTypes);
$this->set('event_id', $eventId);
}
public function groupAttributesIntoObject($event_id, $selected_template, $selected_attribute_ids='[]')

View File

@ -452,7 +452,7 @@ class MispObject extends AppModel
return false;
}
public function saveObject($object, $eventId, $template = false, $user, $errorBehaviour = 'drop', $breakOnDuplicate = false)
public function saveObject(array $object, $eventId, $template = false, $user, $errorBehaviour = 'drop', $breakOnDuplicate = false)
{
$templateFields = array(
'name' => 'name',
@ -482,7 +482,6 @@ class MispObject extends AppModel
}
}
$this->create();
$result = false;
if ($this->save($object)) {
$result = $this->id;
foreach ($object['Attribute'] as $k => $attribute) {
@ -1215,36 +1214,40 @@ class MispObject extends AppModel
return count($orphans);
}
public function validObjectsFromAttributeTypes($user, $event_id, $selected_attribute_ids)
/**
* @param array $user
* @param int $eventId
* @param array $selectedAttributeIds
* @return array|array[]
* @throws Exception
*/
public function validObjectsFromAttributeTypes(array $user, $eventId, array $selectedAttributeIds)
{
$attributes = $this->Attribute->fetchAttributes($user,
array(
'conditions' => array(
'Attribute.id' => $selected_attribute_ids,
'Attribute.event_id' => $event_id,
'Attribute.object_id' => 0
),
)
);
$attributes = $this->Attribute->fetchAttributesSimple($user, [
'conditions' => [
'Attribute.id' => $selectedAttributeIds,
'Attribute.event_id' => $eventId,
'Attribute.object_id' => 0,
],
]);
if (empty($attributes)) {
return array('templates' => array(), 'types' => array());
}
$attribute_types = array();
$attributeTypes = array();
foreach ($attributes as $i => $attribute) {
$attribute_types[$attribute['Attribute']['type']] = 1;
$attributeTypes[$attribute['Attribute']['type']] = true;
$attributes[$i]['Attribute']['object_relation'] = $attribute['Attribute']['type'];
}
$attribute_types = array_keys($attribute_types);
$attributeTypes = array_keys($attributeTypes);
$potential_templates = $this->ObjectTemplate->find('list', array(
$potentialTemplateIds = $this->ObjectTemplate->find('column', array(
'recursive' => -1,
'fields' => array(
'ObjectTemplate.id',
'COUNT(ObjectTemplateElement.type) as type_count'
),
'conditions' => array(
'ObjectTemplate.active' => true,
'ObjectTemplateElement.type' => $attribute_types
'ObjectTemplateElement.type' => $attributeTypes,
),
'joins' => array(
array(
@ -1256,13 +1259,11 @@ class MispObject extends AppModel
)
),
'group' => 'ObjectTemplate.id',
'order' => 'type_count DESC'
));
$potential_template_ids = array_keys($potential_templates);
$templates = $this->ObjectTemplate->find('all', array(
'recursive' => -1,
'conditions' => array('id' => $potential_template_ids),
'conditions' => array('id' => $potentialTemplateIds),
'contain' => 'ObjectTemplateElement'
));
@ -1272,21 +1273,16 @@ class MispObject extends AppModel
$templates[$i]['ObjectTemplate']['invalidTypes'] = $res['invalidTypes'];
$templates[$i]['ObjectTemplate']['invalidTypesMultiple'] = $res['invalidTypesMultiple'];
}
return array('templates' => $templates, 'types' => $attribute_types);
return array('templates' => $templates, 'types' => $attributeTypes);
}
public function groupAttributesIntoObject($user, $event_id, $object, $template, $selected_attribute_ids, $selected_object_relation_mapping, $hard_delete_attribute)
public function groupAttributesIntoObject(array $user, $event_id, array $object, $template, array $selected_attribute_ids, array $selected_object_relation_mapping, $hard_delete_attribute)
{
$saved_object_id = $this->saveObject($object, $event_id, $template, $user);
if (!is_numeric($saved_object_id)) {
return $saved_object_id;
}
$saved_object = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Object.id' => $saved_object_id)
));
$existing_attributes = $this->Attribute->fetchAttributes($user, array('conditions' => array(
'Attribute.id' => $selected_attribute_ids,
'Attribute.event_id' => $event_id,
@ -1299,7 +1295,7 @@ class MispObject extends AppModel
$event = array('Event' => $existing_attributes[0]['Event']);
// Duplicate the attribute and its context, otherwise connected instances will drop the duplicated UUID
foreach ($existing_attributes as $i => $existing_attribute) {
foreach ($existing_attributes as $existing_attribute) {
if (isset($selected_object_relation_mapping[$existing_attribute['Attribute']['id']])) {
$sightings = $this->Event->Sighting->attachToEvent($event, $user, $existing_attribute['Attribute']['id']);
$object_relation = $selected_object_relation_mapping[$existing_attribute['Attribute']['id']];
@ -1308,20 +1304,18 @@ class MispObject extends AppModel
unset($created_attribute['id']);
unset($created_attribute['uuid']);
$created_attribute['object_relation'] = $object_relation;
$created_attribute['object_id'] = $saved_object['Object']['id'];
$created_attribute['object_id'] = $saved_object_id;
if (isset($existing_attribute['AttributeTag'])) {
$created_attribute['AttributeTag'] = $existing_attribute['AttributeTag'];
}
if (!empty($sightings)) {
$created_attribute['Sighting'] = $sightings;
}
$saved_object['Attribute'][$i] = $created_attribute;
$this->Attribute->captureAttribute($created_attribute, $event_id, $user, $saved_object['Object']['id']);
$this->Attribute->captureAttribute($created_attribute, $event_id, $user, $saved_object_id);
$this->Attribute->deleteAttribute($existing_attribute['Attribute']['id'], $user, $hard_delete_attribute);
}
}
return $saved_object['Object']['id'];
return $saved_object_id;
}
public function resolveUpdatedTemplate($template, $object, $update_template_available = false)

View File

@ -206,7 +206,12 @@ class ObjectTemplate extends AppModel
return true;
}
public function checkTemplateConformityBasedOnTypes($template, $attributes)
/**
* @param array $template
* @param array $attributes
* @return array
*/
public function checkTemplateConformityBasedOnTypes(array $template, array $attributes)
{
$to_return = array('valid' => true, 'missingTypes' => array());
if (!empty($template['ObjectTemplate']['requirements'])) {
@ -216,8 +221,9 @@ class ObjectTemplate extends AppModel
$requiredType = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s].type', $requiredField))[0];
$found = false;
foreach ($attributes as $attribute) {
if ($attribute['Attribute']['type'] == $requiredType) {
if ($attribute['Attribute']['type'] === $requiredType) {
$found = true;
break;
}
}
if (!$found) {
@ -231,11 +237,12 @@ class ObjectTemplate extends AppModel
$all_required_type = array();
foreach ($template['ObjectTemplate']['requirements']['requiredOneOf'] as $requiredField) {
$requiredType = Hash::extract($template['ObjectTemplateElement'], sprintf('{n}[object_relation=%s].type', $requiredField));
$requiredType = empty($requiredType) ? NULL : $requiredType[0];
$requiredType = empty($requiredType) ? null : $requiredType[0];
$all_required_type[] = $requiredType;
foreach ($attributes as $attribute) {
if ($attribute['Attribute']['type'] == $requiredType) {
if ($attribute['Attribute']['type'] === $requiredType) {
$found = true;
break;
}
}
}
@ -245,7 +252,7 @@ class ObjectTemplate extends AppModel
}
}
// at this point, an object could created; checking if all attribute are valids
// at this point, an object could created; checking if all attribute are valid
$valid_types = array();
$to_return['invalidTypes'] = array();
$to_return['invalidTypesMultiple'] = array();

View File

@ -15,7 +15,7 @@
<th><?php echo __('Object name'); ?></th>
<th><?php echo __('Category'); ?></th>
<th><?php echo __('Description'); ?></th>
<th title="<?php echo __('Compatiblity or Attribute type missing from the selection'); ?>"><?php echo __('Compatiblity'); ?></th>
<th title="<?php echo __('Compatibility or Attribute type missing from the selection'); ?>"><?php echo __('Compatibility'); ?></th>
</tr>
</thead>
<tbody>
@ -28,7 +28,7 @@
<td><?php echo h($potential_template['ObjectTemplate']['meta-category']); ?></td>
<?php
$v = h($potential_template['ObjectTemplate']['description']);
$v = strlen($v) > 100 ? substr($v, 0, 100) . '...' : $v;
$v = strlen($v) > 100 ? mb_substr($v, 0, 100) . '&hellip;' : $v;
?>
<td style="max-width: 500px;" title="<?php echo h($potential_template['ObjectTemplate']['description']); ?>">
<?php echo $v; ?>