RESTfull/sync

redid the sync, so if add and exist, send HTTP 302 and different
Location, and do edit there.
Still, the final result has to compare the attributes and if needed
RESTfull delete.
pull/61/head
noud 2012-12-07 13:56:19 +01:00
parent be939c2b9e
commit e24ff690bb
3 changed files with 122 additions and 63 deletions

View File

@ -273,26 +273,15 @@ class EventsController extends AppController {
$existingEventCount = $this->Event->find('count', array('conditions' => array('Event.uuid' => $data['Event']['uuid'])));
if ($existingEventCount > 0) {
$message = 'Error - inserting/updating existing event not possible using REST';
// TODO RESTfull, set responce location header..so client can find right URL to edit
$existingEvent = $this->Event->find('first', array('conditions' => array('Event.uuid' => $data['Event']['uuid'])));
$this->response->header('Location', Configure::read('CyDefSIG.baseurl') . '/events/' . $existingEvent['Event']['id']);
$this->response->send();
$this->set(array('message' => $message,'_serialize' => array('message'))); // $this->Event->validationErrors
$this->render('edit');
return false;
// Removed this code because it created bugs
// $existingEvent = $this->Event->find('first', array('conditions' => array('Event.uuid' => $data['Event']['uuid'])));
// $data['Event']['id'] = $existingEvent['Event']['id'];
// $data['Event']['org'] = $existingEvent['Event']['org'];
// // attributes..
// $c = 0;
// if (isset($data['Attribute'])) {
// foreach ($data['Attribute'] as $attribute) {
// // ..do some
// $existingAttributeCount = $this->Event->Attribute->find('count', array('conditions' => array('Attribute.uuid' => $attribute['uuid'])));
// if ($existingAttributeCount > 0) {
// $existingAttribute = $this->Event->Attribute->find('first', array('conditions' => array('Attribute.uuid' => $attribute['uuid'])));
// $data['Attribute'][$c]['id'] = $existingAttribute['Attribute']['id'];
// }
// $c++;
// }
// }
}
}
@ -330,43 +319,63 @@ class EventsController extends AppController {
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->_isRest()) {
// disable edit for REST
$message = 'Error - updating existing event not possible using REST';
$this->set(array('message' => $message,'_serialize' => array('message'))); // $this->Event->validationErrors
$this->render('edit');
return false;
// Workaround for different structure in XML/array than what CakePHP expects
$this->Event->cleanupEventArrayFromXML($this->request->data);
// // Workaround for different structure in XML/array than what CakePHP expects
// $this->Event->cleanupEventArrayFromXML($this->request->data);
// the event_id field is not set (normal) so make sure no validation errors are thrown
// LATER do this with $this->validator()->remove('event_id');
unset($this->Event->Attribute->validate['event_id']);
unset($this->Event->Attribute->validate['value']['unique']); // otherwise gives bugs because event_id is not set
// // the event_id field is not set (normal) so make sure no validation errors are thrown
// // LATER do this with $this->validator()->remove('event_id');
// unset($this->Event->Attribute->validate['event_id']);
// unset($this->Event->Attribute->validate['value']['unique']); // otherwise gives bugs because event_id is not set
// http://book.cakephp.org/2.0/en/models/saving-your-data.html
// Creating or updating is controlled by the models id field.
// If $Model->id is set, the record with this primary key is updated.
// Otherwise a new record is created
// $fieldList = array(
// 'Event' => array('org', 'date', 'risk', 'info', 'published', 'uuid', 'private'),
// 'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private')
// );
// // 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
// if ($this->Event->saveAssociated($this->request->data, array('validate' => true, 'fieldList' => $fieldList))) {
// $message = 'Saved';
// reposition to get the event.id with given uuid
$existingEvent = $this->Event->findByUuid($this->request->data['Event']['uuid']);
if (count($existingEvent)) {
$this->request->data['Event']['id'] = $existingEvent['Event']['id'];
}
// $this->set('event', $this->Event);
// reposition to get the attribute.id with given uuid
$c = 0;
if (isset($this->request->data['Attribute'])) {
foreach ($this->request->data['Attribute'] as $attribute) {
$existingAttribute = $this->Event->Attribute->findByUuid($attribute['uuid']);
if (count($existingAttribute)) {
$this->request->data['Attribute'][$c]['id'] = $existingAttribute['Attribute']['id'];
}
$c++;
}
}
// // REST users want to see the newly created event
// $this->view($this->Event->getId());
// $this->render('view');
// return true;
// } else {
// $message = 'Error';
// $this->set(array('message' => $message,'_serialize' => array('message'))); // $this->Event->validationErrors
// $this->render('edit');
// //throw new MethodNotAllowedException("Validation ERROR: \n".var_export($this->Event->validationErrors, true));
// return false;
// }
$fieldList = array(
'Event' => array('org', 'date', 'risk', 'info', 'published', 'uuid', 'private'),
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'private')
);
// 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
if ($this->Event->saveAssociated($this->request->data, array('validate' => true, 'fieldList' => $fieldList))) {
// TODO RESTfull: we now need to compare attributes, to see if we need to do a RESTfull attribute delete
$message = 'Saved';
$this->set('event', $this->Event);
// REST users want to see the newly created event
$this->view($this->Event->getId());
$this->render('view');
return true;
} else {
$message = 'Error';
$this->set(array('message' => $message,'_serialize' => array('message'))); // $this->Event->validationErrors
$this->render('edit');
//throw new MethodNotAllowedException("Validation ERROR: \n".var_export($this->Event->validationErrors, true));
return false;
}
}
// say what fields are to be updated

View File

@ -232,13 +232,21 @@ class Event extends AppModel {
return $data;
}
public function uploadEventToServer($event, $server, $HttpSocket=null) {
$newLocation = $this->RESTfullEventToServer($event, $server, null, $HttpSocket);
if (is_string($newLocation)) { // HTTP/1.1 302 Found and Location: http://<newLocation>
$this->RESTfullEventToServer($event, $server, $newLocation, $HttpSocket);
}
return true;
}
/**
* Uploads the event and the associated Attributes to another Server
* TODO move this to a component
*
* @return bool true if success, error message if failed
*/
public function uploadEventToServer($event, $server, $HttpSocket=null) {
public function RESTfullEventToServer($event, $server, $urlPath, $HttpSocket=null) {
if (true == $event['Event']['private']) { // never upload private events
return "Event is private and non exportable";
}
@ -257,7 +265,7 @@ class Event extends AppModel {
//'Connection' => 'keep-alive' // LATER followup cakephp ticket 2854 about this problem http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/2854
)
);
$uri = $url . '/events';
$uri = isset($urlPath) ? $urlPath : $url . '/events';
// LATER try to do this using a separate EventsController and renderAs() function
$xmlArray = array();
@ -296,22 +304,27 @@ class Event extends AppModel {
// TODO NETWORK for now do not know how to catch the following..
// TODO NETWORK No route to host
$response = $HttpSocket->post($uri, $data, $request);
if ($response->code == '200') { // 200 (OK) + entity-action-result
if ($response->isOk()) {
return true;
} else {
try {
// parse the XML response and keep the reason why it failed
$xmlArray = Xml::toArray(Xml::build($response->body));
} catch (XmlException $e) {
return true;
}
if (strpos($xmlArray['response']['name'],"Event already exists")) { // strpos, so i can piggyback some value if needed.
switch ($response->code) {
case '200': // 200 (OK) + entity-action-result
if ($response->isOk()) {
return true;
} else {
return $xmlArray['response']['name'];
try {
// parse the XML response and keep the reason why it failed
$xmlArray = Xml::toArray(Xml::build($response->body));
} catch (XmlException $e) {
return true;
}
if (strpos($xmlArray['response']['name'],"Event already exists")) { // strpos, so i can piggyback some value if needed.
return true;
} else {
return $xmlArray['response']['name'];
}
}
}
break;
case '302': // Found
return $response->headers['Location'];
break;
}
}
}

37
app/View/Events/xml/add.ctp Executable file
View File

@ -0,0 +1,37 @@
<?php
$xmlArray = array();
// rearrange things to be compatible with the Xml::fromArray()
$event['Event']['Attribute'] = $event['Attribute'];
unset($event['Attribute']);
// cleanup the array from things we do not want to expose
// remove value1 and value2 from the output
foreach ($event['Event']['Attribute'] as $key => $value) {
unset($event['Event']['Attribute'][$key]['value1']);
unset($event['Event']['Attribute'][$key]['value2']);
unset($event['Event']['Attribute'][$key]['category_order']);
}
// hide the private fields is we are not in sync mode
if ('true' != Configure::read('CyDefSIG.sync')) {
unset($event['Event']['private']);
foreach ($event['Event']['Attribute'] as $key => $value) {
unset($event['Event']['Attribute'][$key]['private']);
}
}
// hide the org field is we are not in showorg mode
if ('true' != Configure::read('CyDefSIG.showorg') && !$isAdmin) {
unset($event['Event']['org']);
}
// build up a list of the related events
if (isset($relatedEvents)) {
foreach ($relatedEvents as $relatedEvent) {
$event['Event']['RelatedEvent'][] = $relatedEvent['Event'];
}
}
// display the XML to the user
$xmlArray['response']['Event'][] = $event['Event'];
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
echo $xmlObject->asXML();