2020-04-02 01:55:55 +02: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 adapters ;
use Twilio\Rest\Client ;
/**
2020-06-23 21:06:13 +02:00
* Twilio SMS service with a virtual number adapter .
2020-04-02 01:55:55 +02:00
*/
class TwilioVirtualNumberAdapter implements AdapterInterface
{
/**
2021-01-17 03:16:57 +01:00
* Data used to configure interaction with the implemented service . ( e . g : Api credentials , ports numbers , etc . ) .
2020-04-02 01:55:55 +02:00
*/
2021-01-17 03:16:57 +01:00
private $data ;
2020-04-02 01:55:55 +02:00
/**
2020-06-23 21:06:13 +02:00
* Twilio Api client .
2020-04-02 01:55:55 +02:00
*/
private $client ;
/**
2020-06-23 21:06:13 +02:00
* Twilio virtual number to use .
2020-04-02 01:55:55 +02:00
*/
private $number ;
/**
2020-06-23 21:06:13 +02:00
* Callback address Twilio must call on SMS status change .
2020-04-02 01:55:55 +02:00
*/
private $status_change_callback ;
/**
* Adapter constructor , called when instanciated by RaspiSMS .
*
* @ param string $number : Phone number the adapter is used for
2021-02-23 00:31:54 +01:00
* @ param json string $data : JSON string of the data to configure interaction with the implemented service
2020-04-02 01:55:55 +02:00
*/
2021-01-17 03:16:57 +01:00
public function __construct ( string $data )
2020-04-02 01:55:55 +02:00
{
2021-01-17 03:16:57 +01:00
$this -> data = json_decode ( $data , true );
2020-04-02 01:55:55 +02:00
$this -> client = new Client (
2021-01-17 03:16:57 +01:00
$this -> data [ 'account_sid' ],
$this -> data [ 'auth_token' ]
2020-04-02 01:55:55 +02:00
);
2021-01-17 03:16:57 +01:00
$this -> number = $this -> data [ 'number' ];
$this -> status_change_callback = $this -> data [ 'status_change_callback' ];
2020-04-02 01:55:55 +02:00
}
/**
* Classname of the adapter .
*/
public static function meta_classname () : string
{
return __CLASS__ ;
}
/**
* Uniq name of the adapter
2020-06-23 21:06:13 +02:00
* It should be the classname of the adapter un snakecase .
2020-04-02 01:55:55 +02:00
*/
2020-06-23 21:06:13 +02:00
public static function meta_uid () : string
2020-04-02 01:55:55 +02:00
{
return 'twilio_virtual_number_adapter' ;
}
2021-02-23 00:31:54 +01:00
2021-01-26 19:27:30 +01:00
/**
* Should this adapter be hidden in user interface for phone creation and
2021-02-23 00:31:54 +01:00
* available to creation through API only .
2021-01-26 19:27:30 +01:00
*/
public static function meta_hidden () : bool
{
return false ;
}
2020-04-02 01:55:55 +02:00
2022-03-28 01:54:38 +02:00
/**
* Should this adapter data be hidden after creation
* this help to prevent API credentials to other service leak if an attacker gain access to RaspiSMS through user credentials .
*/
public static function meta_hide_data () : bool
{
return false ;
}
2020-04-02 01:55:55 +02:00
/**
* Name of the adapter .
* It should probably be the name of the service it adapt ( e . g : Gammu SMSD , OVH SMS , SIM800L , etc . ) .
*/
public static function meta_name () : string
{
return 'Twilio Numéro virtuel' ;
}
/**
* Description of the adapter .
* A short description of the service the adapter implements .
*/
public static function meta_description () : string
{
$credentials_url = 'https://www.twilio.com/console' ;
return '
2020-07-04 21:35:39 +02:00
Solution de SMS avec numéro virtuel proposé par < a target = " _blank " href = " https://www.twilio.com/sms " > Twilio </ a >. Pour trouver vos clés API Twilio < a target = " _blank " href = " ' . $credentials_url . ' " > cliquez ici .</ a >< br />
2021-02-04 16:44:13 +01:00
Pour plus d\ ' information sur l\ ' utilisation de ce téléphone , reportez - vous à < a href = " https://documentation.raspisms.fr/users/adapters/twilio_virtual_number.html " target = " _blank " > la documentation sur le téléphone " Twilio Numéro Virtuel " .</ a >
2020-04-02 01:55:55 +02:00
' ;
}
/**
2021-01-17 03:16:57 +01:00
* List of entries we want in data for the adapter .
2020-04-02 01:55:55 +02:00
*
* @ return array : Every line is a field as an array with keys : name , title , description , required
*/
2021-01-17 03:16:57 +01:00
public static function meta_data_fields () : array
2020-04-02 01:55:55 +02:00
{
return [
[
'name' => 'account_sid' ,
'title' => 'Account SID' ,
'description' => 'Identifiant unique Twilio, trouvable sur la page d\'accueil de la console Twilio.' ,
'required' => true ,
],
[
'name' => 'auth_token' ,
'title' => 'Auth Token' ,
'description' => 'Jeton d\'identification Twilio, trouvable sous le Account SID.' ,
'required' => true ,
],
[
'name' => 'number' ,
'title' => 'Numéro de téléphone virtuel' ,
'description' => 'Numéro de téléphone virtuel Twilio à utiliser parmis les numéro actifs (format international), <a href="https://www.twilio.com/console/phone-numbers/incoming" target="_blank">voir la liste ici</a>.' ,
'required' => true ,
2022-07-12 13:16:22 +02:00
'type' => 'phone_number' ,
2020-04-02 01:55:55 +02:00
],
[
'name' => 'status_change_callback' ,
'title' => 'Callback de changement de status' ,
'description' => 'L\'adresse que Twilio devra appeler pour signaler le changement de statut d\'un SMS. Laissez tel quel par défaut.' ,
'required' => true ,
'default_value' => \descartes\Router :: url ( 'Callback' , 'update_sended_status' , [ 'adapter_uid' => self :: meta_uid ()], [ 'api_key' => $_SESSION [ 'user' ][ 'api_key' ] ? ? '<your_api_key>' ]),
],
];
}
/**
* Does the implemented service support reading smss .
*/
public static function meta_support_read () : bool
{
return true ;
}
/**
* Does the implemented service support flash smss .
*/
public static function meta_support_flash () : bool
{
return false ;
}
/**
* Does the implemented service support status change .
*/
public static function meta_support_status_change () : bool
{
return true ;
}
2020-04-03 02:15:55 +02:00
/**
* Does the implemented service support reception callback .
*/
public static function meta_support_reception () : bool
{
return false ;
}
2020-04-02 01:55:55 +02:00
/**
2021-06-17 00:51:33 +02:00
* Does the implemented service support mms reception .
2020-04-02 01:55:55 +02:00
*/
2021-03-19 02:45:12 +01:00
public static function meta_support_mms_reception () : bool
{
return false ;
}
/**
2021-06-17 00:51:33 +02:00
* Does the implemented service support mms sending .
2021-03-19 02:45:12 +01:00
*/
public static function meta_support_mms_sending () : bool
{
return false ;
}
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
public static function meta_support_inbound_call_callback () : bool
{
return false ;
}
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
public static function meta_support_end_call_callback () : bool
{
return false ;
}
2021-03-19 02:45:12 +01:00
2021-06-17 00:51:33 +02:00
public function send ( string $destination , string $text , bool $flash = false , bool $mms = false , array $medias = []) : array
2020-04-02 01:55:55 +02:00
{
$response = [
'error' => false ,
'error_message' => null ,
'uid' => null ,
];
try
{
$message = $this -> client -> messages -> create (
$destination ,
[
'from' => $this -> number ,
'body' => $text ,
'statusCallback' => $this -> status_change_callback ,
]
);
2020-06-23 21:06:13 +02:00
if ( null !== $message -> errorCode )
2020-04-02 01:55:55 +02:00
{
$response [ 'error' ] = true ;
$response [ 'error_message' ] = $message -> errorMessage ;
2020-06-23 21:06:13 +02:00
2020-04-02 01:55:55 +02:00
return $response ;
}
$response [ 'uid' ] = $message -> sid ;
2020-06-23 21:06:13 +02:00
2020-04-02 01:55:55 +02:00
return $response ;
}
catch ( \Throwable $t )
{
$response [ 'error' ] = true ;
$response [ 'error_message' ] = $t -> getMessage ();
2020-06-23 21:06:13 +02:00
2020-04-02 01:55:55 +02:00
return $response ;
}
}
public function read () : array
{
$response = [
'error' => false ,
'error_message' => null ,
'smss' => [],
];
try
{
$messages = $this -> client -> messages -> read ([
'to' => $this -> number ,
], 20 );
foreach ( $messages as $record )
{
2020-06-23 21:06:13 +02:00
if ( 'inbound' !== $record -> direction )
2020-04-02 01:55:55 +02:00
{
continue ;
}
$timezone = date_default_timezone_get ();
$record -> dateCreated -> setTimezone ( new \DateTimeZone ( $timezone ));
$response [ 'smss' ][] = [
'at' => $record -> dateCreated -> format ( 'Y-m-d H:i:s' ),
'text' => $record -> body ,
'origin' => $record -> from ,
];
//Remove sms to prevent double reading
$this -> client -> messages ( $record -> sid ) -> delete ();
}
return $response ;
}
catch ( \Throwable $t )
{
$response [ 'error' ] = true ;
$response [ 'error_message' ] = $t -> getMessage ();
2020-06-23 21:06:13 +02:00
2020-04-02 01:55:55 +02:00
return $response ;
}
}
public function test () : bool
{
try
{
$phone_numbers = $this -> client -> incomingPhoneNumbers -> read ([ 'phoneNumber' => $this -> number ], 20 );
foreach ( $phone_numbers as $record )
{
//If not the same number, return false
2020-06-23 21:06:13 +02:00
if ( $record -> phoneNumber !== $this -> number )
2020-04-02 01:55:55 +02:00
{
continue ;
}
return true ; //Same number, its all ok we can return true
}
return false ;
}
catch ( \Throwable $t )
{
return false ;
}
}
public static function status_change_callback ()
{
$sid = $_REQUEST [ 'MessageSid' ] ? ? false ;
$status = $_REQUEST [ 'MessageStatus' ] ? ? false ;
2020-04-03 02:15:55 +02:00
2020-04-02 01:55:55 +02:00
if ( ! $sid || ! $status )
{
return false ;
}
switch ( $status )
{
2020-06-23 21:06:13 +02:00
case 'delivered' :
2020-04-03 02:15:55 +02:00
$status = \models\Sended :: STATUS_DELIVERED ;
2020-04-02 01:55:55 +02:00
2020-04-03 02:15:55 +02:00
break ;
2021-01-14 03:32:17 +01:00
2020-06-23 21:06:13 +02:00
case 'failed' :
$status = \models\Sended :: STATUS_FAILED ;
2020-04-02 01:55:55 +02:00
2020-06-23 21:06:13 +02:00
break ;
2021-01-14 03:32:17 +01:00
2020-06-23 21:06:13 +02:00
default :
2020-04-03 02:15:55 +02:00
$status = \models\Sended :: STATUS_UNKNOWN ;
2020-06-23 21:06:13 +02:00
2020-04-03 02:15:55 +02:00
break ;
2020-04-02 01:55:55 +02:00
}
return [ 'uid' => $sid , 'status' => $status ];
}
2020-04-03 02:15:55 +02:00
2020-06-23 21:06:13 +02:00
public static function reception_callback () : array
2020-04-03 02:15:55 +02:00
{
return [];
}
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
public function inbound_call_callback () : array
{
return [];
}
2021-06-17 00:51:33 +02:00
2021-03-23 17:39:13 +01:00
public function end_call_callback () : array
{
return [];
}
2020-04-02 01:55:55 +02:00
}