2015-12-16 00:48:30 +01:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
2020-07-28 00:01:32 +02:00
/**
* @ property Sighting $Sighting
2020-09-01 17:03:31 +02:00
* @ property Event $Event
2020-07-28 00:01:32 +02:00
*/
2018-07-19 11:48:22 +02:00
class SightingsController extends AppController
{
public $components = array ( 'Session' , 'RequestHandler' );
2015-12-16 00:48:30 +01:00
2018-07-19 11:48:22 +02:00
public function beforeFilter ()
{
parent :: beforeFilter ();
}
2015-12-16 00:48:30 +01:00
2018-07-19 11:48:22 +02:00
public $paginate = array (
2021-05-31 17:45:29 +02:00
'limit' => 60 ,
'maxLimit' => 9999 , // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'order' => array ( 'Sighting.date_sighting' => 'DESC' ),
2018-07-19 11:48:22 +02:00
);
2015-12-16 00:48:30 +01:00
2018-07-19 11:48:22 +02:00
// takes an attribute ID or UUID
public function add ( $id = false )
{
if ( $this -> request -> is ( 'post' )) {
$now = time ();
$values = false ;
$timestamp = false ;
$error = false ;
if ( $id === 'stix' ) {
$result = $this -> Sighting -> handleStixSighting ( file_get_contents ( 'php://input' ));
if ( $result [ 'success' ]) {
$result [ 'data' ] = json_decode ( $result [ 'data' ], true );
$timestamp = isset ( $result [ 'data' ][ 'timestamp' ]) ? strtotime ( $result [ 'data' ][ 'timestamp' ]) : $now ;
$type = '0' ;
$source = '' ;
if ( isset ( $result [ 'data' ][ 'values' ])) {
$values = $result [ 'data' ][ 'values' ];
} else {
$error = 'No valid values found that could be extracted from the sightings document.' ;
}
} else {
$error = $result [ 'message' ];
}
} else {
if ( isset ( $this -> request -> data [ 'request' ])) {
$this -> request -> data = $this -> request -> data [ 'request' ];
}
if ( isset ( $this -> request -> data [ 'Sighting' ])) {
$this -> request -> data = $this -> request -> data [ 'Sighting' ];
}
if ( ! empty ( $this -> request -> data [ 'date' ]) && ! empty ( $this -> request -> data [ 'time' ])) {
$timestamp = DateTime :: createFromFormat ( 'Y-m-d:H:i:s' , $this -> request -> data [ 'date' ] . ':' . $this -> request -> data [ 'time' ]);
$timestamp = $timestamp -> getTimestamp ();
} else {
$timestamp = isset ( $this -> request -> data [ 'timestamp' ]) ? $this -> request -> data [ 'timestamp' ] : $now ;
}
if ( isset ( $this -> request -> data [ 'value' ])) {
$this -> request -> data [ 'values' ] = array ( $this -> request -> data [ 'value' ]);
}
$values = isset ( $this -> request -> data [ 'values' ]) ? $this -> request -> data [ 'values' ] : false ;
if ( ! $id && isset ( $this -> request -> data [ 'uuid' ])) {
$id = $this -> request -> data [ 'uuid' ];
}
if ( ! $id && isset ( $this -> request -> data [ 'id' ])) {
$id = $this -> request -> data [ 'id' ];
}
$type = isset ( $this -> request -> data [ 'type' ]) ? $this -> request -> data [ 'type' ] : '0' ;
$source = isset ( $this -> request -> data [ 'source' ]) ? trim ( $this -> request -> data [ 'source' ]) : '' ;
}
if ( ! $error ) {
2019-11-22 21:53:51 +01:00
$result = $this -> Sighting -> saveSightings ( $id , $values , $timestamp , $this -> Auth -> user (), $type , $source , false , true );
2018-07-19 11:48:22 +02:00
}
if ( ! is_numeric ( $result )) {
$error = $result ;
}
if ( $this -> request -> is ( 'ajax' )) {
if ( $error ) {
$error_message = 'Could not add the Sighting. Reason: ' . $error ;
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $error_message )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
} else {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $result . ' ' . $this -> Sighting -> type [ $type ] . (( $result == 1 ) ? '' : 's' ) . ' added.' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
} else {
if ( $error ) {
2018-10-30 17:14:42 +01:00
$error_message = __ ( 'Could not add the Sighting. Reason: ' ) . $error ;
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
$this -> set ( 'message' , $error_message );
$this -> set ( '_serialize' , array ( 'message' ));
} else {
$this -> Flash -> error ( $error_message );
$this -> redirect ( $this -> referer ());
}
2018-07-19 11:48:22 +02:00
} else {
2018-10-30 17:14:42 +01:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
2019-08-20 10:52:12 +02:00
$sighting = $this -> Sighting -> find ( 'first' , array ( 'conditions' => array ( 'Sighting.id' => $this -> Sighting -> id ), 'recursive' => - 1 ));
return $this -> RestResponse -> viewData ( $sighting , $this -> response -> type ());
2018-10-30 17:14:42 +01:00
} else {
$this -> Flash -> success ( __ ( 'Sighting added' ));
$this -> redirect ( $this -> referer ());
}
2018-07-19 11:48:22 +02:00
}
}
} else {
if ( $this -> _isRest ()) {
return $this -> RestResponse -> describe ( 'Sightings' , 'add' , false , $this -> response -> type ());
}
if ( ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ( 'This method is only accessible via POST requests and ajax GET requests.' );
} else {
$this -> layout = false ;
$this -> loadModel ( 'Attribute' );
$attributes = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => array ( 'Attribute.id' => $id ), 'flatten' => 1 ));
if ( empty ( $attributes )) {
throw new MethodNotAllowedExeption ( 'Invalid Attribute.' );
}
$this -> set ( 'event_id' , $attributes [ 0 ][ 'Attribute' ][ 'event_id' ]);
$this -> set ( 'id' , $id );
$this -> render ( 'ajax/add_sighting' );
}
}
}
2017-02-16 22:41:22 +01:00
2018-07-19 11:48:22 +02:00
public function advanced ( $id , $context = 'attribute' )
{
if ( empty ( $id )) {
throw new MethodNotAllowedException ( 'Invalid ' . $context . '.' );
}
$input_id = $id ;
$id = $this -> Sighting -> explodeIdList ( $id );
if ( $context == 'attribute' ) {
$this -> loadModel ( 'Attribute' );
$attributes = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => array ( 'Attribute.id' => $id ), 'flatten' => 1 ));
if ( empty ( $attributes )) {
throw new MethodNotAllowedException ( 'Invalid attribute.' );
}
} else {
$this -> loadModel ( 'Event' );
$events = $this -> Event -> fetchEvent ( $this -> Auth -> user (), array ( 'eventid' => $id , 'metadata' => true ));
if ( empty ( $events )) {
throw new MethodNotAllowedException ( 'Invalid event.' );
}
}
$this -> set ( 'context' , $context );
$this -> set ( 'id' , $input_id );
$this -> render ( '/Sightings/ajax/advanced' );
}
2017-02-16 22:41:22 +01:00
2021-05-31 17:45:29 +02:00
public function quickAdd ( $id = false , $type = 1 , $onvalue = false )
2018-11-23 14:11:33 +01:00
{
2018-10-30 17:14:42 +01:00
if ( ! $this -> userRole [ 'perm_modify_org' ]) {
throw new MethodNotAllowedException ( __ ( 'You are not authorised to remove sightings data as you don\'t have permission to modify your organisation\'s data.' ));
}
if ( ! $this -> request -> is ( 'post' )) {
$this -> loadModel ( 'Attribute' );
$attribute = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => array ( 'Attribute.id' => $id , 'Attribute.deleted' => 0 ), 'flatten' => 1 ));
if ( empty ( $attribute )) {
throw new MethodNotAllowedException ( __ ( 'Attribute not found' ));
} else {
$attribute = $attribute [ 0 ][ 'Attribute' ];
if ( ! $onvalue ) {
$this -> set ( 'id' , $attribute [ 'id' ]);
$this -> set ( 'tosight' , $attribute [ 'id' ]);
} else {
$this -> set ( 'id' , '' );
$this -> set ( 'tosight' , $attribute [ 'value' ]);
}
$this -> set ( 'value' , $attribute [ 'value' ]);
$this -> set ( 'event_id' , $attribute [ 'event_id' ]);
2019-01-29 16:07:03 +01:00
$this -> set ( 'sighting_type' , $type );
2018-10-30 17:14:42 +01:00
$this -> set ( 'onvalue' , $onvalue );
$this -> render ( 'ajax/quickAddConfirmationForm' );
}
} else {
if ( ! isset ( $id )) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => __ ( 'Invalid request.' ))), 'status' => 200 , 'type' => 'json' ));
2018-10-30 17:14:42 +01:00
} else {
if ( $onvalue ) {
$result = $this -> Sighting -> add ();
} else {
$result = $this -> Sighting -> add ( $id );
}
if ( $result ) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => __ ( 'Sighting added.' ))), 'status' => 200 , 'type' => 'json' ));
2018-10-30 17:14:42 +01:00
} else {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => __ ( 'Sighting could not be added' ))), 'status' => 200 , 'type' => 'json' ));
2018-10-30 17:14:42 +01:00
}
}
}
}
2018-07-19 11:48:22 +02:00
public function quickDelete ( $id , $rawId , $context )
{
if ( ! $this -> userRole [ 'perm_modify_org' ]) {
throw new MethodNotAllowedException ( 'You are not authorised to remove sightings data as you don\'t have permission to modify your organisation\'s data.' );
}
if ( ! $this -> request -> is ( 'post' )) {
$this -> set ( 'id' , $id );
$sighting = $this -> Sighting -> find ( 'first' , array ( 'conditions' => array ( 'Sighting.id' => $id ), 'recursive' => - 1 , 'fields' => array ( 'Sighting.attribute_id' )));
$this -> set ( 'rawId' , $rawId );
$this -> set ( 'context' , $context );
$this -> render ( 'ajax/quickDeleteConfirmationForm' );
} else {
if ( ! isset ( $id )) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => 'Invalid request.' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
} else {
$sighting = $this -> Sighting -> find ( 'first' , array ( 'conditions' => array ( 'Sighting.id' => $id ), 'recursive' => - 1 ));
if ( empty ( $sighting )) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => 'Invalid sighting.' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
if ( ! $this -> _isSiteAdmin () && $sighting [ 'Sighting' ][ 'org_id' ] != $this -> Auth -> user ( 'org_id' )) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => 'Invalid sighting.' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
$result = $this -> Sighting -> delete ( $id );
if ( $result ) {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Sighting deleted.' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
} else {
2021-05-31 17:45:29 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => 'Sighting could not be deleted' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
}
}
}
2015-12-16 00:48:30 +01:00
2020-12-10 20:44:16 +01:00
// takes a sighting ID or UUID
2018-07-19 11:48:22 +02:00
public function delete ( $id )
{
if ( ! $this -> userRole [ 'perm_modify_org' ]) {
throw new MethodNotAllowedException ( 'You are not authorised to remove sightings data as you don\'t have permission to modify your organisation\'s data.' );
}
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( 'This action can only be accessed via a post request.' );
}
2020-12-10 20:44:16 +01:00
$sighting = $this -> Sighting -> find ( 'first' , array (
'conditions' => Validation :: uuid ( $id ) ? [ 'Sighting.uuid' => $id ] : [ 'Sighting.id' => $id ],
'recursive' => - 1 ,
'fields' => [ 'id' , 'org_id' ],
));
2018-07-19 11:48:22 +02:00
if ( empty ( $sighting )) {
throw new NotFoundException ( 'Invalid sighting.' );
}
2020-12-10 20:44:16 +01:00
if ( ! $this -> _isSiteAdmin () && $sighting [ 'Sighting' ][ 'org_id' ] != $this -> Auth -> user ( 'org_id' )) {
throw new NotFoundException ( 'Invalid sighting.' );
2018-07-19 11:48:22 +02:00
}
$result = $this -> Sighting -> delete ( $sighting [ 'Sighting' ][ 'id' ]);
if ( ! $result ) {
return $this -> RestResponse -> saveFailResponse ( 'Sighting' , 'delete' , $id , 'Could not delete the Sighting.' );
} else {
2020-12-10 20:44:16 +01:00
return $this -> RestResponse -> saveSuccessResponse ( 'Sighting' , 'delete' , $id , false , 'Sighting successfully deleted.' );
2018-07-19 11:48:22 +02:00
}
}
2017-01-05 20:48:03 +01:00
2018-07-19 11:48:22 +02:00
public function index ( $eventid = false )
{
$this -> loadModel ( 'Event' );
$sightingConditions = array ();
if ( $eventid ) {
$sightingConditions = array ( 'Sighting.event_id' => $eventid );
}
$sightedEvents = $this -> Sighting -> find ( 'list' , array (
2021-05-31 17:45:29 +02:00
'group' => [ 'Sighting.id' , 'Sighting.event_id' ],
2018-07-19 11:48:22 +02:00
'fields' => array ( 'Sighting.event_id' ),
'conditions' => $sightingConditions
));
if ( empty ( $sightedEvents )) {
$this -> RestResponse -> viewData ( array ());
}
$conditions = array ( 'metadata' => true , 'contain' => false );
if ( $eventid ) {
$conditions [ 'eventid' ] = $sightedEvents ;
}
2021-04-21 09:09:29 +02:00
$events = $this -> Event -> fetchEventIds ( $this -> Auth -> user (), [
'eventIdList' => $sightedEvents
]);
2018-07-19 11:48:22 +02:00
$sightings = array ();
if ( ! empty ( $events )) {
foreach ( $events as $k => $event ) {
$sightings = array_merge ( $sightings , $this -> Sighting -> attachToEvent ( $event , $this -> Auth -> user ()));
}
}
return $this -> RestResponse -> viewData ( $sightings );
}
2017-02-06 14:08:55 +01:00
2019-07-29 16:46:02 +02:00
public function listSightings ( $id = false , $context = 'attribute' , $org_id = false )
2018-07-19 11:48:22 +02:00
{
$rawId = $id ;
2019-07-29 16:46:02 +02:00
$parameters = array ( 'id' , 'context' , 'org_id' );
foreach ( $parameters as $parameter ) {
if ( $this -> request -> is ( 'post' ) && isset ( $this -> request -> data [ $parameter ])) {
${$parameter} = $this -> request -> data [ $parameter ];
}
}
2018-07-19 11:48:22 +02:00
if ( $org_id ) {
2019-08-14 15:08:19 +02:00
$this -> loadModel ( 'Organisation' );
$org_id = $this -> Toolbox -> findIdByUuid ( $this -> Organisation , $org_id );
2019-02-28 20:27:36 +01:00
}
2019-07-16 09:31:49 +02:00
$sightings = $this -> Sighting -> listSightings ( $this -> Auth -> user (), $id , $context , $org_id );
2020-11-11 22:23:21 +01:00
if ( $this -> _isRest ()) {
return $this -> RestResponse -> viewData ( $sightings , $this -> response -> type ());
}
2018-07-19 11:48:22 +02:00
$this -> set ( 'org_id' , $org_id );
$this -> set ( 'rawId' , $rawId );
$this -> set ( 'context' , $context );
$this -> set ( 'types' , array ( 'Sighting' , 'False-positive' , 'Expiration' ));
2020-11-11 22:23:21 +01:00
$this -> set ( 'sightings' , $sightings );
2018-07-19 11:48:22 +02:00
$this -> layout = false ;
$this -> render ( 'ajax/list_sightings' );
}
2017-02-16 22:41:22 +01:00
2018-07-19 11:48:22 +02:00
public function viewSightings ( $id , $context = 'attribute' )
{
$this -> loadModel ( 'Event' );
$id = $this -> Sighting -> explodeIdList ( $id );
if ( $context === 'attribute' ) {
2020-11-11 09:00:50 +01:00
$objects = $this -> Event -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => array ( 'Attribute.id' => $id , 'Attribute.deleted' => 0 ), 'flatten' => 1 ));
if ( empty ( $objects )) {
2018-07-19 11:48:22 +02:00
throw new MethodNotAllowedException ( 'Invalid object.' );
}
2020-11-11 09:00:50 +01:00
$statistics = $this -> Sighting -> attributesStatistics ( $objects , $this -> Auth -> user (), true );
} elseif ( $context === 'event' ) {
2018-07-19 11:48:22 +02:00
// let's set the context to event here, since we reuse the variable later on for some additional lookups.
// Passing $context = 'org' could have interesting results otherwise...
2020-09-01 17:03:31 +02:00
$events = $this -> Event -> fetchSimpleEvents ( $this -> Auth -> user (), [ 'conditions' => [ 'id' => $id ]]);
2020-11-11 09:00:50 +01:00
$statistics = $this -> Sighting -> eventsStatistic ( $events , $this -> Auth -> user (), true );
} else {
throw new MethodNotAllowedException ( 'Invalid context' );
2018-07-19 11:48:22 +02:00
}
2020-11-11 09:00:50 +01:00
$this -> set ( 'csv' , $statistics [ 'csv' ][ 'all' ]);
2018-07-19 11:48:22 +02:00
$this -> layout = 'ajax' ;
$this -> render ( 'ajax/view_sightings' );
}
2019-11-22 21:53:51 +01:00
// Save sightings synced over, restricted to sync users
public function bulkSaveSightings ( $eventId = false )
{
2020-12-31 22:48:27 +01:00
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( 'This method is only accessible via POST requests.' );
}
if ( empty ( $this -> request -> data [ 'Sighting' ])) {
$sightings = $this -> request -> data ;
} else {
$sightings = $this -> request -> data [ 'Sighting' ];
}
try {
$saved = $this -> Sighting -> bulkSaveSightings ( $eventId , $sightings , $this -> Auth -> user ());
if ( $saved > 0 ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $saved . ' sightings added.' )), 'status' => 200 , 'type' => 'json' ));
2019-11-22 21:53:51 +01:00
} else {
2020-12-31 22:48:27 +01:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'success' => 'No sightings added.' )), 'status' => 200 , 'type' => 'json' ));
2019-11-22 21:53:51 +01:00
}
2020-12-31 22:48:27 +01:00
} catch ( NotFoundException $e ) {
throw new MethodNotAllowedException ( $e -> getMessage ());
2019-11-22 21:53:51 +01:00
}
}
2015-12-16 00:48:30 +01:00
}