From d52b0a6e70ffb82aa80d7215f5ecda8a79544ef4 Mon Sep 17 00:00:00 2001 From: iglocska Date: Thu, 6 Jun 2013 14:55:13 +0200 Subject: [PATCH] First (still non-working) version of the timestamp + uuid sync - timestamp field added to events and attributes (int length 11 called timestamp, default value 0) - timestamps created on add / edit when apprioriate - during an add, if an event/attribute is not being pushed through a sync with an existing timestamp, create a timestamp - on edit, check whether the timestamp is newer than the old one and only add the attribute or event then --- app/Controller/AttributesController.php | 41 +++++++++++++++++++------ app/Controller/EventsController.php | 32 ++++++++++++++----- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/app/Controller/AttributesController.php b/app/Controller/AttributesController.php index b31660774..1ecdf2afc 100755 --- a/app/Controller/AttributesController.php +++ b/app/Controller/AttributesController.php @@ -101,7 +101,7 @@ class AttributesController extends AppController { public function add($eventId = null) { if ($this->request->is('post')) { $this->loadModel('Event'); - + $date = new DateTime(); // Give error if someone tried to submit a attribute with attachment or malware-sample type. // TODO change behavior attachment options - this is bad ... it should rather by a messagebox or should be filtered out on the view level if (isset($this->request->data['Attribute']['type']) && $this->Attribute->typeIsAttachment($this->request->data['Attribute']['type'])) { @@ -110,8 +110,11 @@ class AttributesController extends AppController { } // remove the published flag from the event - $this->Event->id = $this->request->data['Attribute']['event_id']; - $this->Event->saveField('published', 0); + $this->Event->recursive = -1; + $this->Event->read(null, $this->request->data['Attribute']['event_id']); + $this->Event->set('timestamp', $date->getTimestamp()); + $this->Event->set('published', 0); + $this->Event->save($this->Event->data, array('fieldList' => array('published', 'timestamp', 'info'))); // // multiple attributes in batch import @@ -162,16 +165,26 @@ class AttributesController extends AppController { } else { if (isset($this->request->data['Attribute']['uuid'])) { // TODO here we should start RESTful dialog - // check if the uuid already exists - $existingAttributeCount = $this->Attribute->find('count', array('conditions' => array('Attribute.uuid' => $this->request->data['Attribute']['uuid']))); - if ($existingAttributeCount > 0) { + // check if the uuid already exists and also save the existing attribute for further checks + $existingAttribute = null; + $existingAttribute = $this->Attribute->find('first', array('conditions' => array('Attribute.uuid' => $this->request->data['Attribute']['uuid']))); + //$existingAttributeCount = $this->Attribute->find('count', array('conditions' => array('Attribute.uuid' => $this->request->data['Attribute']['uuid']))); + if ($existingAttribute) { // TODO RESTfull, set responce location header..so client can find right URL to edit - $existingAttribute = $this->Attribute->find('first', array('conditions' => array('Attribute.uuid' => $this->request->data['Attribute']['uuid']))); $this->response->header('Location', Configure::read('CyDefSIG.baseurl') . '/attributes/' . $existingAttribute['Attribute']['id']); $this->response->send(); $this->view($this->Attribute->getId()); $this->render('view'); return false; + } else { + // if the attribute doesn't exist yet, check whether it has a timestamp - if yes, it's from a push, keep the timestamp we had, if no create a timestamp + if (!isset($this->request->data['Attribute']['timestamp'])) { + $this->request->data['Attribute']['timestamp'] = $date->getTimestamp(); + } + } + } else { + if (!isset($this->request->data['Attribute']['timestamp'])) { + $this->request->data['Attribute']['timestamp'] = $date->getTimestamp(); } } @@ -181,8 +194,6 @@ class AttributesController extends AppController { // create the attribute $this->Attribute->create(); - // Notice (8): Undefined index: id [APP/Controller/AttributesController.php, line 234] - // Should be fixed $savedId = $this->Attribute->getId(); if ($this->Attribute->save($this->request->data)) { @@ -492,8 +503,18 @@ class AttributesController extends AppController { if (count($existingAttribute)) { $this->request->data['Attribute']['id'] = $existingAttribute['Attribute']['id']; } + // check if the attribute has a timestamp already set (from a previous instance that is trying to edit via synchronisation) + if (isset($this->request->data['Attribute']['timestamp'])) { + // check which attribute is newer + if ($this->request->data['Attribute']['timestamp'] > $existingAttribute['Attribute']['timestamp']) { + // carry on with adding this attribute - Don't forget! if orgc!=user org, create shadow attribute, not attribute! + } else { + // the old one is newer or the same, replace the request's attribute with the old one + $this->request->data['Attribute'] = $existingAttribute['Attribute']; + } + } - $fieldList = array('category', 'type', 'value1', 'value2', 'to_ids', 'private', 'cluster', 'value'); + $fieldList = array('category', 'type', 'value1', 'value2', 'to_ids', 'private', 'cluster', 'value', 'timestamp'); $this->loadModel('Event'); $this->Event->id = $eventId; diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index d1376b387..af7562bd2 100755 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -419,11 +419,15 @@ class EventsController extends AppController { // force check userid and orgname to be from yourself $auth = $this->Auth; $data['Event']['user_id'] = $auth->user('id'); + $date = new DateTime(); + if ($this->checkAction('perm_sync')) $data['Event']['org'] = Configure::read('CyDefSIG.org'); else $data['Event']['org'] = $auth->user('org'); - if (!$fromXml) { - $data['Event']['orgc'] = $data['Event']['org']; - } + + // set these fields if the event is freshly created and not pushed from another instance. + // Moved out of if (!$fromXML), since we might get a restful event without the orgc/timestamp set + if (!isset ($data['Event']['timestamp'])) $data['Event']['timestamp'] = $date->getTimestamp(); + if (!isset ($data['Event']['orgc'])) $data['Event']['orgc'] = $data['Event']['org']; if ($fromXml) { // FIXME FIXME chri: temporary workaround for unclear org, orgc, from //$data['Event']['orgc'] = $data['Event']['org']; @@ -456,7 +460,7 @@ class EventsController extends AppController { 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision') ); $fieldList = array( - 'Event' => array('org', 'orgc', 'date', 'risk', 'analysis', 'info', 'user_id', 'published', 'uuid', 'private', 'cluster', 'communitie', 'dist_change', 'from'), + 'Event' => array('org', 'orgc', 'date', 'risk', 'analysis', 'info', 'user_id', 'published', 'uuid', 'private', 'cluster', 'communitie', 'dist_change', 'from', 'timestamp'), 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private', 'cluster', 'communitie', 'dist_change') ); @@ -530,7 +534,7 @@ class EventsController extends AppController { } $fieldList = array( - 'Event' => array('date', 'risk', 'analysis', 'info', 'published', 'uuid', 'dist_change', 'from'), + 'Event' => array('date', 'risk', 'analysis', 'info', 'published', 'uuid', 'dist_change', 'from', 'timestamp'), 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private', 'communitie', 'cluster', 'dist_change') ); @@ -541,11 +545,19 @@ class EventsController extends AppController { $existingAttribute = $this->Event->Attribute->findByUuid($attribute['uuid']); if (count($existingAttribute)) { $this->request->data['Attribute'][$c]['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 want to start deleting attributes that don't exist in a pushed event. + if ($this->request->data['Attribute'][$c]['timestamp'] > $existingAttribute['Attribute']['id']); + else $this->request->data['Attribute'][$c] = $existingAttribute['Attribute']; + + /* Should be obsolete with timestamps if (!($this->request->data['Attribute'][$c]['dist_change'] > $existingAttribute['Attribute']['dist_change'])) { unset($this->request->data['Attribute'][$c]['private']); unset($this->request->data['Attribute'][$c]['cluster']); unset($this->request->data['Attribute'][$c]['communitie']); } + */ } $c++; } @@ -555,7 +567,9 @@ class EventsController extends AppController { if ($this->request->data['Event']['dist_change'] > $existingEvent['Event']['dist_change']) { array_push($fieldList['Event'], 'private', 'communitie', 'cluster'); } - + // TODO (iglocska): right now this will always update, make sure that this doesn't happen if the edit was rejected (due to the timestamps being equal, shadow attributes created instead of normal attributes, etc) + $date = new DateTime(); + $this->request->data['Event']['timestamp'] = $date->getTimestamp(); // this saveAssociated() function will save not only the event, but also the attributes // from the attributes attachments are also saved to the disk thanks to the afterSave() fonction of Attribute $saveResult = $this->Event->saveAssociated($this->request->data, array('validate' => true, 'fieldList' => $fieldList)); @@ -583,7 +597,7 @@ class EventsController extends AppController { } } // say what fields are to be updated - $fieldList = array('date', 'risk', 'analysis', 'info', 'published', 'private', 'cluster', 'communitie', 'dist_change'); + $fieldList = array('date', 'risk', 'analysis', 'info', 'published', 'private', 'cluster', 'communitie', 'dist_change', 'timestamp'); //Moved this out of (if ($this->_isAdmin()) to use for the dist_change $this->Event->read(); @@ -596,12 +610,16 @@ class EventsController extends AppController { // we probably also want to remove the published flag $this->request->data['Event']['published'] = 0; + /* we don't need this stuff anymore // If the distribution has changed, up the dist_change count if ($canEditDist) { if ($this->request->data['Event']['distribution'] != $this->Event->data['Event']['distribution']) { $this->request->data['Event']['dist_change'] = 1 + $this->Event->data['Event']['dist_change']; } } + */ + $date = new DateTime(); + $this->request->data['Event']['timestamp'] = $date->getTimestamp(); if ($this->Event->save($this->request->data, true, $fieldList)) { $this->Session->setFlash(__('The event has been saved')); $this->redirect(array('action' => 'view', $id));