2020-01-08 02:14:38 +01:00
< ? php
/*
* This file is part of RaspiSMS .
*
* ( c ) Pierre - Lin Bonnemaison < plebwebsas @ gmail . com >
*
* This source file is subject to the GPL - 3.0 license that is bundled
* with this source code in the file LICENSE .
*/
namespace controllers\publics ;
2020-03-04 04:18:26 +01:00
use Monolog\Handler\StreamHandler ;
use Monolog\Logger ;
2020-07-03 03:48:42 +02:00
/**
* Controller of callback pages , like sms status update notification .
*/
2020-01-08 02:14:38 +01:00
class Callback extends \descartes\Controller
{
2020-03-04 04:18:26 +01:00
private $logger ;
2020-03-04 01:40:47 +01:00
private $user ;
2020-01-08 02:14:38 +01:00
private $internal_user ;
private $internal_sended ;
2020-04-03 03:38:35 +02:00
private $internal_received ;
2020-01-08 02:14:38 +01:00
private $internal_adapter ;
2021-03-19 02:45:12 +01:00
private $internal_media ;
2021-03-23 04:31:13 +01:00
private $internal_phone ;
2021-03-23 17:39:13 +01:00
private $internal_call ;
2020-01-08 02:14:38 +01:00
public function __construct ()
{
$bdd = \descartes\Model :: _connect ( DATABASE_HOST , DATABASE_NAME , DATABASE_USER , DATABASE_PASSWORD );
$this -> internal_user = new \controllers\internals\User ( $bdd );
$this -> internal_sended = new \controllers\internals\Sended ( $bdd );
2020-04-03 03:38:35 +02:00
$this -> internal_received = new \controllers\internals\Received ( $bdd );
2021-03-19 02:45:12 +01:00
$this -> internal_media = new \controllers\internals\Media ( $bdd );
2020-01-08 02:14:38 +01:00
$this -> internal_adapter = new \controllers\internals\Adapter ();
2021-03-23 17:39:13 +01:00
$this -> internal_phone = new \controllers\internals\Phone ( $bdd );
$this -> internal_call = new \controllers\internals\Call ( $bdd );
2020-03-04 01:40:47 +01:00
2020-03-04 04:18:26 +01:00
//Logger
$this -> logger = new Logger ( 'Callback ' . uniqid ());
$this -> logger -> pushHandler ( new StreamHandler ( PWD_LOGS . '/callback.log' , Logger :: DEBUG ));
//If invalid api key, quit with error
2020-03-04 01:40:47 +01:00
$this -> user = false ;
2021-01-27 21:37:43 +01:00
$api_key = $_GET [ 'api_key' ] ? ? $_POST [ 'api_key' ] ? ? $_SERVER [ 'HTTP_X_API_KEY' ] ? ? false ;
2020-03-04 01:40:47 +01:00
if ( $api_key )
{
$this -> user = $this -> internal_user -> get_by_api_key ( $api_key );
}
if ( ! $this -> user )
{
http_response_code ( 401 );
echo json_encode ([ 'error' => 'Invalid API key. You must provide a valid GET or POST api_key param.' ]);
2020-03-04 05:10:45 +01:00
$this -> logger -> error ( 'Callback call failed with invalid api key : ' . $api_key );
2021-01-14 03:32:17 +01:00
2020-03-04 01:40:47 +01:00
exit ( 1 );
}
2020-03-04 05:10:45 +01:00
2020-03-04 04:18:26 +01:00
$this -> logger -> info ( 'Callback call succed for user id : ' . $this -> user [ 'id' ]);
2020-01-08 02:14:38 +01:00
}
/**
2020-01-17 18:19:25 +01:00
* Function call on a sended sms status change notification reception .
2020-03-04 05:10:45 +01:00
* We return nothing , and we let the adapter do his things .
2020-01-17 18:19:25 +01:00
*
2020-04-02 01:55:55 +02:00
* @ param string $adapter_uid : Uid of the adapter to use
2020-03-04 05:10:45 +01:00
*
2020-03-04 01:40:47 +01:00
* @ return bool : true on success , false on error
2020-01-08 02:14:38 +01:00
*/
2020-04-02 01:55:55 +02:00
public function update_sended_status ( string $adapter_uid )
2020-01-08 02:14:38 +01:00
{
2020-04-02 01:55:55 +02:00
$this -> logger -> info ( 'Callback status call with adapter uid : ' . $adapter_uid );
2020-03-04 04:18:26 +01:00
2020-01-08 02:14:38 +01:00
//Search for an adapter
$find_adapter = false ;
$adapters = $this -> internal_adapter -> list_adapters ();
foreach ( $adapters as $adapter )
{
2020-04-02 01:55:55 +02:00
if ( mb_strtolower ( $adapter [ 'meta_uid' ]) === $adapter_uid )
2020-01-08 02:14:38 +01:00
{
$find_adapter = $adapter ;
}
}
if ( false === $find_adapter )
{
2020-04-02 01:55:55 +02:00
$this -> logger -> error ( 'Callback status use non existing adapter : ' . $adapter_uid );
2020-03-04 05:10:45 +01:00
2020-01-08 02:14:38 +01:00
return false ;
}
//Instanciate adapter, check if status change is supported and if so call status change callback
$adapter_classname = $find_adapter [ 'meta_classname' ];
if ( ! $find_adapter [ 'meta_support_status_change' ])
{
2020-04-02 01:55:55 +02:00
$this -> logger -> error ( 'Callback status use adapter ' . $adapter_uid . ' which does not support status change.' );
2020-03-04 05:10:45 +01:00
2020-01-08 02:14:38 +01:00
return false ;
}
$callback_return = $adapter_classname :: status_change_callback ();
if ( ! $callback_return )
{
2021-01-17 03:16:57 +01:00
$this -> logger -> error ( 'Callback status with adapter ' . $adapter_uid . ' failed because adapter cannot process data with success.' );
2020-03-04 05:10:45 +01:00
2020-01-08 02:14:38 +01:00
return false ;
}
2020-03-05 23:07:07 +01:00
$sended = $this -> internal_sended -> get_by_uid_and_adapter_for_user ( $this -> user [ 'id' ], $callback_return [ 'uid' ], $adapter_classname );
2020-01-08 02:14:38 +01:00
if ( ! $sended )
{
2020-03-04 04:18:26 +01:00
$this -> logger -> error ( 'Callback status try update inexisting message with uid = ' . $callback_return [ 'uid' ] . '.' );
2020-03-04 05:10:45 +01:00
2020-01-08 02:14:38 +01:00
return false ;
}
2020-03-04 05:10:45 +01:00
2021-05-26 15:46:50 +02:00
//Do not update if current status is delivered
if ( \models\Sended :: STATUS_DELIVERED === $sended [ 'status' ])
2020-04-02 01:55:55 +02:00
{
$this -> logger -> info ( 'Callback status update message ignore because status is already ' . $sended [ 'status' ] . '.' );
2020-06-23 21:06:13 +02:00
2020-04-02 01:55:55 +02:00
return false ;
}
2021-05-26 15:46:50 +02:00
//Do not update if current status is failed and new status is unknown
if ( \models\Sended :: STATUS_FAILED === $sended [ 'status' ] && \models\Sended :: STATUS_UNKNOWN == $callback_return [ 'status' ])
{
$this -> logger -> info ( 'Callback status update message ignore because status is already ' . $sended [ 'status' ] . ' and new status is ' . $callback_return [ 'status' ] . '.' );
return false ;
}
2020-04-02 01:55:55 +02:00
$this -> logger -> info ( 'Callback status update message with uid ' . $callback_return [ 'uid' ] . ' to ' . $callback_return [ 'status' ] . '.' );
2020-03-05 23:07:07 +01:00
$this -> internal_sended -> update_status_for_user ( $this -> user [ 'id' ], $sended [ 'id' ], $callback_return [ 'status' ]);
2020-01-08 02:14:38 +01:00
2020-03-04 01:40:47 +01:00
return true ;
2020-01-08 02:14:38 +01:00
}
2020-06-23 21:06:13 +02:00
2020-04-03 02:15:55 +02:00
/**
* Function call on sms reception notification
* We return nothing , and we let the adapter do his things .
*
* @ param string $adapter_uid : Uid of the adapter to use
2020-06-23 21:06:13 +02:00
* @ param int $id_phone : Phone id
2020-04-03 02:15:55 +02:00
*
* @ return bool : true on success , false on error
*/
2020-06-23 21:06:13 +02:00
public function reception ( string $adapter_uid , int $id_phone )
2020-04-03 02:15:55 +02:00
{
$this -> logger -> info ( 'Callback reception call with adapter uid : ' . $adapter_uid );
2022-09-26 17:31:32 +02:00
$phone = $this -> internal_phone -> get_for_user ( $this -> user [ 'id' ], $id_phone );
if ( ! $phone )
{
$this -> logger -> error ( 'Callback reception use non existing phone : ' . $id_phone );
return false ;
}
2020-04-03 02:15:55 +02:00
//Search for an adapter
$find_adapter = false ;
$adapters = $this -> internal_adapter -> list_adapters ();
foreach ( $adapters as $adapter )
{
if ( mb_strtolower ( $adapter [ 'meta_uid' ]) === $adapter_uid )
{
$find_adapter = $adapter ;
}
}
if ( false === $find_adapter )
{
$this -> logger -> error ( 'Callback reception use non existing adapter : ' . $adapter_uid );
return false ;
}
//Instanciate adapter, check if status change is supported and if so call status change callback
$adapter_classname = $find_adapter [ 'meta_classname' ];
if ( ! $find_adapter [ 'meta_support_reception' ])
{
$this -> logger -> error ( 'Callback recepetion use adapter ' . $adapter_uid . ' which does not support reception.' );
return false ;
}
$response = $adapter_classname :: reception_callback ();
if ( $response [ 'error' ])
{
$this -> logger -> error ( 'Callback reception with adapter ' . $adapter_uid . ' failed : ' . $response [ 'error_message' ]);
2021-03-23 04:31:13 +01:00
return false ;
}
$sms = $response [ 'sms' ];
2021-06-25 02:04:35 +02:00
$mms = ( bool ) ( $sms [ 'mms' ] ? ? false );
2021-03-23 04:31:13 +01:00
$medias = empty ( $sms [ 'medias' ]) ? [] : $sms [ 'medias' ];
2021-03-26 23:32:29 +01:00
$response = $this -> internal_received -> receive ( $this -> user [ 'id' ], $id_phone , $sms [ 'text' ], $sms [ 'origin' ], $sms [ 'at' ], \models\Received :: STATUS_UNREAD , $mms , $medias );
2021-03-23 04:31:13 +01:00
if ( $response [ 'error' ])
{
$this -> logger -> error ( 'Failed receive message : ' . json_encode ( $sms ) . ' with error : ' . $response [ 'error_message' ]);
return false ;
}
$this -> logger -> info ( 'Callback reception successfully received message : ' . json_encode ( $sms ));
return true ;
}
2021-06-17 00:51:33 +02:00
2021-03-23 04:31:13 +01:00
/**
* Function call on call reception notification
* We return nothing , and we let the adapter do his things .
*
2021-06-17 00:51:33 +02:00
* @ param int $id_phone : Phone id
2021-03-23 04:31:13 +01:00
*
* @ return bool : true on success , false on error
*/
public function inbound_call ( int $id_phone )
{
2021-03-26 17:31:09 +01:00
$this -> logger -> info ( 'Callback inbound_call call with phone : ' . $id_phone );
2021-03-23 04:31:13 +01:00
$phone = $this -> internal_phone -> get_for_user ( $this -> user [ 'id' ], $id_phone );
if ( ! $phone )
{
$this -> logger -> error ( 'Callback inbound_call use non existing phone : ' . $id_phone );
return false ;
}
if ( ! class_exists ( $phone [ 'adapter' ]))
{
$this -> logger -> error ( 'Callback inbound_call use non existing adapter : ' . $phone [ 'adapter' ]);
return false ;
}
if ( ! $phone [ 'adapter' ] :: meta_support_inbound_call_callback ())
{
$this -> logger -> error ( 'Callback inbound_call use adapter ' . $phone [ 'adapter' ] . ' which does not support inbound_call callback.' );
return false ;
}
$response = $phone [ 'adapter' ] :: inbound_call_callback ();
if ( $response [ 'error' ])
{
2021-03-23 17:39:13 +01:00
$this -> logger -> error ( 'Callback inbound_call failed : ' . $response [ 'error_message' ]);
2020-06-23 21:06:13 +02:00
2020-04-03 02:15:55 +02:00
return false ;
}
2021-03-23 17:39:13 +01:00
$call = $response [ 'call' ];
2021-03-26 17:31:09 +01:00
2021-03-26 17:39:16 +01:00
if ( empty ( $call ) || empty ( $call [ 'uid' ]) || empty ( $call [ 'start' ]) || empty ( $call [ 'origin' ]))
2021-03-26 17:31:09 +01:00
{
$this -> logger -> error ( 'Callback inbound_call failed : missing required param in call return' );
return false ;
}
2021-03-23 17:39:13 +01:00
$result = $this -> internal_call -> create ( $this -> user [ 'id' ], $id_phone , $call [ 'uid' ], \models\Call :: DIRECTION_INBOUND , $call [ 'start' ], $call [ 'end' ] ? ? null , $call [ 'origin' ]);
2020-04-03 03:38:35 +02:00
2021-03-23 17:39:13 +01:00
if ( ! $result )
2021-03-19 02:45:12 +01:00
{
2021-03-23 17:39:13 +01:00
$this -> logger -> error ( 'Callback inbound_call failed because cannot create call ' . json_encode ( $call ));
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
return false ;
}
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
$this -> logger -> info ( 'Callback inbound_call successfully received inbound call : ' . json_encode ( $call ));
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
return true ;
}
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
/**
* Function call on end call notification
* We return nothing , and we let the adapter do his things .
*
2021-06-17 00:51:33 +02:00
* @ param int $id_phone : Phone id
2021-03-23 17:39:13 +01:00
*
* @ return bool : true on success , false on error
*/
public function end_call ( int $id_phone )
{
$this -> logger -> info ( 'Callback end call with phone : ' . $id_phone );
$phone = $this -> internal_phone -> get_for_user ( $this -> user [ 'id' ], $id_phone );
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
if ( ! $phone )
{
$this -> logger -> error ( 'Callback end call use non existing phone : ' . $id_phone );
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
return false ;
}
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
if ( ! class_exists ( $phone [ 'adapter' ]))
{
$this -> logger -> error ( 'Callback end call use non existing adapter : ' . $phone [ 'adapter' ]);
2021-03-19 02:45:12 +01:00
2021-03-23 17:39:13 +01:00
return false ;
2021-03-19 02:45:12 +01:00
}
2021-03-23 17:39:13 +01:00
if ( ! $phone [ 'adapter' ] :: meta_support_end_call_callback ())
{
$this -> logger -> error ( 'Callback end call use adapter ' . $phone [ 'adapter' ] . ' which does not support end call callback.' );
return false ;
}
$response = $phone [ 'adapter' ] :: end_call_callback ();
2020-04-03 02:15:55 +02:00
if ( $response [ 'error' ])
{
2021-03-23 17:39:13 +01:00
$this -> logger -> error ( 'Callback end call failed : ' . $response [ 'error_message' ]);
2020-06-23 21:06:13 +02:00
2020-04-03 02:15:55 +02:00
return false ;
}
2021-03-23 17:39:13 +01:00
$call = $response [ 'call' ];
2021-03-26 17:39:16 +01:00
if ( empty ( $call ) || empty ( $call [ 'uid' ]) || empty ( $call [ 'end' ]))
2021-03-26 17:31:09 +01:00
{
$this -> logger -> error ( 'Callback end call failed : missing required param in call return' );
return false ;
}
2021-03-23 17:39:13 +01:00
$result = $this -> internal_call -> end ( $this -> user [ 'id' ], $id_phone , $call [ 'uid' ], $call [ 'end' ]);
if ( ! $result )
{
$this -> logger -> error ( 'Callback end call failed because cannot update call ' . json_encode ( $call ));
return false ;
}
2020-06-23 21:06:13 +02:00
2021-03-23 17:39:13 +01:00
$this -> logger -> info ( 'Callback end call successfully update call : ' . json_encode ( $call ));
2021-06-17 00:51:33 +02:00
2020-04-03 02:15:55 +02:00
return true ;
}
2020-01-08 02:14:38 +01:00
}