2013-05-22 10:52:03 +02:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
App :: uses ( 'Xml' , 'Utility' );
/**
* Servers Controller
*
* @ property Server $Server
*
* @ throws ConfigureException // TODO Exception
*/
class ServersController extends AppController {
public $components = array ( 'Security' , 'RequestHandler' ); // XXX ACL component
public $paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 , // LATER we will bump here on a problem once we have more than 9999 events
'order' => array (
'Server.url' => 'ASC'
)
);
public $uses = array ( 'Server' , 'Event' );
public function beforeFilter () {
parent :: beforeFilter ();
// Disable this feature if the sync configuration option is not active
if ( 'true' != Configure :: read ( 'CyDefSIG.sync' ))
throw new ConfigureException ( " The sync feature is not active in the configuration. " );
// permit reuse of CSRF tokens on some pages.
switch ( $this -> request -> params [ 'action' ]) {
case 'push' :
case 'pull' :
$this -> Security -> csrfUseOnce = false ;
}
}
/**
* index method
*
* @ return void
*/
public function index () {
$this -> Server -> recursive = 0 ;
if ( $this -> _IsSiteAdmin ()) {
$this -> paginate = array (
'conditions' => array (),
);
} else {
2013-06-27 17:57:33 +02:00
if ( ! $this -> userRole [ 'perm_sync' ]) $this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
$conditions [ 'Server.org LIKE' ] = $this -> Auth -> user ( 'org' );
$this -> paginate = array (
'conditions' => array ( $conditions ),
);
}
$this -> set ( 'servers' , $this -> paginate ());
}
/**
* add method
*
* @ return void
*/
public function add () {
2013-06-27 17:57:33 +02:00
if (( ! $this -> _IsSiteAdmin ()) && ! ( $this -> Server -> organization == $this -> Auth -> user ( 'org' ) && $this -> userRole [ 'perm_sync' ])) $this -> redirect ( array ( 'controller' => 'servers' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
if ( $this -> request -> is ( 'post' )) {
// force check userid and orgname to be from yourself
$this -> request -> data [ 'Server' ][ 'org' ] = $this -> Auth -> user ( 'org' );
$this -> Server -> create ();
if ( $this -> Server -> save ( $this -> request -> data )) {
$this -> Session -> setFlash ( __ ( 'The server has been saved' ));
$this -> redirect ( array ( 'action' => 'index' ));
} else {
$this -> Session -> setFlash ( __ ( 'The server could not be saved. Please, try again.' ));
}
}
}
/**
* edit method
*
* @ param string $id
* @ return void
* @ throws NotFoundException
*/
public function edit ( $id = null ) {
2013-06-27 17:57:33 +02:00
if ( ! $this -> _IsSiteAdmin () && ! ( $this -> Server -> organization == $this -> Auth -> user ( 'org' ) && $this -> userRole [ 'perm_sync' ])) $this -> redirect ( array ( 'controller' => 'servers' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
$this -> Server -> id = $id ;
if ( ! $this -> Server -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid server' ));
}
if ( $this -> request -> is ( 'post' ) || $this -> request -> is ( 'put' )) {
// say what fields are to be updated
$fieldList = array ( 'url' , 'push' , 'pull' , 'organization' );
if ( " " != $this -> request -> data [ 'Server' ][ 'authkey' ])
$fieldList [] = 'authkey' ;
// Save the data
if ( $this -> Server -> save ( $this -> request -> data , true , $fieldList )) {
$this -> Session -> setFlash ( __ ( 'The server has been saved' ));
$this -> redirect ( array ( 'action' => 'index' ));
} else {
$this -> Session -> setFlash ( __ ( 'The server could not be saved. Please, try again.' ));
}
} else {
$this -> Server -> read ( null , $id );
$this -> Server -> set ( 'authkey' , '' );
$this -> request -> data = $this -> Server -> data ;
}
}
/**
* delete method
*
* @ param string $id
* @ return void
* @ throws MethodNotAllowedException
* @ throws NotFoundException
*/
public function delete ( $id = null ) {
2013-06-27 17:57:33 +02:00
if ( ! $this -> _IsSiteAdmin () && ! ( $this -> Server -> id == $this -> Auth -> user ( 'org' ) && $this -> userRole [ 'perm_sync' ])) $this -> redirect ( array ( 'controller' => 'servers' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ();
}
$this -> Server -> id = $id ;
if ( ! $this -> Server -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid server' ));
}
if ( $this -> Server -> delete ()) {
$this -> Session -> setFlash ( __ ( 'Server deleted' ));
$this -> redirect ( array ( 'action' => 'index' ));
}
$this -> Session -> setFlash ( __ ( 'Server was not deleted' ));
$this -> redirect ( array ( 'action' => 'index' ));
}
2013-06-19 12:13:45 +02:00
/**
* Pull one or more events with attributes from a remote instance .
* Set $technique to
* full - download everything
* incremental - only new events
* < int > - specific id of the event to pull
* For example to download event 10 from server 2 to / servers / pull / 2 / 5
* @ param int $id The id of the server
* @ param unknown_type $technique
* @ throws MethodNotAllowedException
* @ throws NotFoundException
*/
public function pull ( $id = null , $technique = false ) {
2013-06-27 17:57:33 +02:00
if ( ! $this -> _IsSiteAdmin () && ! ( $this -> Server -> organization == $this -> Auth -> user ( 'org' ) && $this -> userRole [ 'perm_sync' ])) $this -> redirect ( array ( 'controller' => 'servers' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
$this -> Server -> id = $id ;
if ( ! $this -> Server -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid server' ));
}
App :: uses ( 'HttpSocket' , 'Network/Http' );
$this -> Server -> read ( null , $id );
if ( false == $this -> Server -> data [ 'Server' ][ 'pull' ]) {
$this -> Session -> setFlash ( __ ( 'Pull setting not enabled for this server.' ));
$this -> redirect ( array ( 'action' => 'index' ));
}
2013-06-19 12:13:45 +02:00
$eventIds = array ();
if ( " full " == $technique ) {
2013-05-22 10:52:03 +02:00
// get a list of the event_ids on the server
$eventIds = $this -> Event -> getEventIdsFromServer ( $this -> Server -> data );
2013-06-18 09:12:09 +02:00
// FIXME this is not clean at all ! needs to be refactored with try catch error handling/communication
2013-05-22 10:52:03 +02:00
if ( $eventIds === 403 ) {
$this -> Session -> setFlash ( __ ( 'Not authorised. This is either due to an invalid auth key, or due to the sync user not having authentication permissions enabled on the remote server.' ));
$this -> redirect ( array ( 'action' => 'index' ));
2013-06-18 09:12:09 +02:00
} else if ( is_string ( $eventIds )) {
$this -> Session -> setFlash ( $eventIds );
$this -> redirect ( array ( 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
}
2013-06-18 09:12:09 +02:00
2013-06-18 11:19:43 +02:00
// reverse array of events, to first get the old ones, and then the new ones
$eventIds = array_reverse ( $eventIds );
2013-06-19 12:13:45 +02:00
} elseif ( " incremental " == $technique ) {
// TODO incremental pull
throw new NotFoundException ( 'Sorry, this is not yet implemented' );
} elseif ( true == $technique ) {
$eventIds [] = intval ( $technique );
2013-07-17 14:06:24 +02:00
} else {
$this -> redirect ( array ( 'action' => 'index' ));
2013-06-19 12:13:45 +02:00
}
// now process the $eventIds to pull each of the events sequentially
if ( ! empty ( $eventIds )) {
2013-05-22 10:52:03 +02:00
$successes = array ();
$fails = array ();
// download each event
if ( null != $eventIds ) {
App :: import ( 'Controller' , 'Events' );
$HttpSocket = new HttpSocket ();
foreach ( $eventIds as & $eventId ) {
$event = $this -> Event -> downloadEventFromServer (
$eventId ,
$this -> Server -> data );
if ( null != $event ) {
// we have an Event array
if ( ! isset ( $event [ 'Event' ][ 'distribution' ])) { // version 1
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'distribution' ] = '1' ;
2013-05-22 10:52:03 +02:00
}
// Distribution
switch ( $event [ 'Event' ][ 'distribution' ]) {
2013-06-10 23:00:45 +02:00
case 1 :
2013-06-18 11:19:43 +02:00
case 'This community only' : // backwards compatibility
2013-06-10 23:00:45 +02:00
// if community only, downgrade to org only after pull
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'distribution' ] = '0' ;
2013-05-22 10:52:03 +02:00
break ;
2013-06-18 09:12:09 +02:00
case 2 :
2013-06-18 11:19:43 +02:00
case 'Connected communities' : // backwards compatibility
2013-06-10 23:00:45 +02:00
// if connected communities downgrade to community only
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'distribution' ] = '1' ;
2013-05-22 10:52:03 +02:00
break ;
2013-06-18 11:19:43 +02:00
case 'All communities' : // backwards compatibility
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'distribution' ] = '3' ;
2013-06-18 11:19:43 +02:00
break ;
case 'Your organisation only' : // backwards compatibility
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'distribution' ] = '0' ;
2013-06-18 11:19:43 +02:00
break ;
2013-05-22 10:52:03 +02:00
}
// correct $event if just one Attribute
if ( is_array ( $event [ 'Event' ][ 'Attribute' ]) && isset ( $event [ 'Event' ][ 'Attribute' ][ 'id' ])) {
$tmp = $event [ 'Event' ][ 'Attribute' ];
unset ( $event [ 'Event' ][ 'Attribute' ]);
$event [ 'Event' ][ 'Attribute' ][ 0 ] = $tmp ;
}
if ( is_array ( $event [ 'Event' ][ 'Attribute' ])) {
$size = is_array ( $event [ 'Event' ][ 'Attribute' ]) ? count ( $event [ 'Event' ][ 'Attribute' ]) : 0 ;
for ( $i = 0 ; $i < $size ; $i ++ ) {
if ( ! isset ( $event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ])) { // version 1
2013-06-10 23:00:45 +02:00
$event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ] = 1 ;
2013-05-22 10:52:03 +02:00
}
switch ( $event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ]) {
2013-06-10 23:00:45 +02:00
case 1 :
2013-06-18 11:19:43 +02:00
case 'This community only' : // backwards compatibility
2013-06-10 23:00:45 +02:00
// if community only, downgrade to org only after pull
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ] = '0' ;
2013-05-22 10:52:03 +02:00
break ;
2013-06-18 09:12:09 +02:00
case 2 :
2013-06-18 11:19:43 +02:00
case 'Connected communities' : // backwards compatibility
2013-06-10 23:00:45 +02:00
// if connected communities downgrade to community only
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ] = '1' ;
2013-05-22 10:52:03 +02:00
break ;
2013-06-18 11:19:43 +02:00
case 'All communities' : // backwards compatibility
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ] = '3' ;
2013-06-18 11:19:43 +02:00
break ;
case 'Your organisation only' : // backwards compatibility
2013-07-16 15:28:04 +02:00
$event [ 'Event' ][ 'Attribute' ][ $i ][ 'distribution' ] = '0' ;
2013-06-18 11:19:43 +02:00
break ;
2013-05-22 10:52:03 +02:00
}
}
$event [ 'Event' ][ 'Attribute' ] = array_values ( $event [ 'Event' ][ 'Attribute' ]);
} else {
unset ( $event [ 'Event' ][ 'Attribute' ]);
}
// Distribution, set reporter of the event, being the admin that initiated the pull
$event [ 'Event' ][ 'user_id' ] = $this -> Auth -> user ( 'id' );
// check if the event already exist (using the uuid)
2013-06-11 00:41:43 +02:00
$existingEvent = null ;
$existingEvent = $this -> Event -> find ( 'first' , array ( 'conditions' => array ( 'Event.uuid' => $event [ 'Event' ][ 'uuid' ])));
2013-06-18 09:12:09 +02:00
$eventsController = new EventsController ();
2013-06-11 00:41:43 +02:00
$eventsController -> constructClasses ();
if ( ! $existingEvent ) {
2013-05-22 10:52:03 +02:00
// add data for newly imported events
2013-06-18 09:12:09 +02:00
$passAlong = $this -> Server -> data [ 'Server' ][ 'url' ];
2013-06-19 12:13:45 +02:00
$result = $eventsController -> _add ( $event , $fromXml = true , $this -> Server -> data [ 'Server' ][ 'organization' ], $passAlong , true );
2013-06-11 00:41:43 +02:00
if ( $result ) $successes [] = $eventId ;
2013-06-19 12:13:45 +02:00
else {
$fails [ $eventId ] = 'Failed (partially?) because of validation errors: ' . print_r ( $eventsController -> Event -> validationErrors , true );
}
2013-06-11 00:41:43 +02:00
} else {
$result = $eventsController -> _edit ( $event , $existingEvent [ 'Event' ][ 'id' ]);
if ( $result === 'success' ) $successes [] = $eventId ;
else $fails [ $eventId ] = $result ;
2013-05-22 10:52:03 +02:00
}
} else {
// error
2013-06-19 12:13:45 +02:00
$fails [ $eventId ] = 'failed downloading the event' ;
2013-05-22 10:52:03 +02:00
}
}
if ( count ( $fails ) > 0 ) {
// there are fails, take the lowest fail
$lastpulledid = min ( array_keys ( $fails ));
} else {
// no fails, take the highest success
$lastpulledid = count ( $successes ) > 0 ? max ( $successes ) : 0 ;
}
// increment lastid based on the highest ID seen
2013-06-06 10:24:27 +02:00
$this -> Server -> set ( 'lastpulledid' , $lastpulledid );
$this -> Server -> save ( $event , array ( 'fieldList' => array ( 'lastpulledid' , 'url' )));
2013-05-22 10:52:03 +02:00
}
}
$this -> set ( 'successes' , $successes );
$this -> set ( 'fails' , $fails );
}
2013-06-19 12:13:45 +02:00
public function push ( $id = null , $technique = false ) {
2013-06-27 17:57:33 +02:00
if ( $this -> Auth -> user ( 'org' ) != 'ADMIN' && ! ( $this -> Server -> organization == $this -> Auth -> user ( 'org' ) && $this -> userRole [ 'perm_sync' ])) $this -> redirect ( array ( 'controller' => 'servers' , 'action' => 'index' ));
2013-05-22 10:52:03 +02:00
$this -> Server -> id = $id ;
if ( ! $this -> Server -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid server' ));
}
App :: uses ( 'HttpSocket' , 'Network/Http' );
$this -> Server -> read ( null , $id );
if ( false == $this -> Server -> data [ 'Server' ][ 'push' ]) {
$this -> Session -> setFlash ( __ ( 'Push setting not enabled for this server.' ));
$this -> redirect ( array ( 'action' => 'index' ));
}
2013-07-17 14:06:24 +02:00
if ( " full " == $technique ) {
$eventid_conditions_key = 'Event.id >' ;
$eventid_conditions_value = 0 ;
} elseif ( " incremental " == $technique ) {
$eventid_conditions_key = 'Event.id >' ;
$eventid_conditions_value = $this -> Server -> data [ 'Server' ][ 'lastpushedid' ];
} elseif ( true == $technique ) {
$eventid_conditions_key = 'Event.id' ;
$eventid_conditions_value = intval ( $technique );
} else {
$this -> redirect ( array ( 'action' => 'index' ));
}
2013-05-22 10:52:03 +02:00
$findParams = array (
2013-07-17 14:06:24 +02:00
'conditions' => array (
$eventid_conditions_key => $eventid_conditions_value ,
'Event.distribution >' => 0 ,
'Event.published' => 1 ,
'Event.attribute_count >' => 0
), //array of conditions
'recursive' => - 1 , //int
'fields' => array ( 'Event.id' ), //array of field names
2013-05-22 10:52:03 +02:00
);
2013-07-17 14:06:24 +02:00
$eventIds = $this -> Event -> find ( 'all' , $findParams );
// now process the $eventIds to pull each of the events sequentially
if ( ! empty ( $eventIds )) {
$successes = array ();
$fails = array ();
$lowestfailedid = null ;
2013-05-22 10:52:03 +02:00
$HttpSocket = new HttpSocket ();
2013-07-17 14:06:24 +02:00
foreach ( $eventIds as $eventId ) {
$this -> Event -> recursive = 1 ;
$event = $this -> Event -> findById ( $eventId [ 'Event' ][ 'id' ]);
unset ( $event [ 'User' ]);
2013-05-22 10:52:03 +02:00
$result = $this -> Event -> uploadEventToServer (
2013-07-17 14:06:24 +02:00
$event ,
$this -> Server -> data ,
$HttpSocket );
2013-05-22 10:52:03 +02:00
if ( true == $result ) {
2013-07-17 14:06:24 +02:00
$successes [] = $event [ 'Event' ][ 'id' ];
2013-05-22 10:52:03 +02:00
} else {
2013-07-17 14:06:24 +02:00
$fails [ $event [ 'Event' ][ 'id' ]] = $result ;
2013-05-22 10:52:03 +02:00
}
}
if ( count ( $fails ) > 0 ) {
2013-07-17 14:06:24 +02:00
// there are fails, take the lowest fail
$lastpushedid = min ( array_keys ( $fails ));
2013-05-22 10:52:03 +02:00
} else {
2013-07-17 14:06:24 +02:00
// no fails, take the highest success
$lastpushedid = max ( $successes );
2013-05-22 10:52:03 +02:00
}
// increment lastid based on the highest ID seen
$this -> Server -> saveField ( 'lastpushedid' , $lastpushedid );
}
$this -> set ( 'successes' , $successes );
$this -> set ( 'fails' , $fails );
}
}