diff --git a/config/data-provider.php b/config/data-provider.php index c4b71142d..e5518ed94 100644 --- a/config/data-provider.php +++ b/config/data-provider.php @@ -19,6 +19,7 @@ 'africastalking' => false, 'httpsms' => false, 'infobip' => false, + 'sislog' => false, ], 'authenticable-providers' => [ diff --git a/config/features.php b/config/features.php index b19086ca3..168df9f27 100644 --- a/config/features.php +++ b/config/features.php @@ -33,6 +33,7 @@ 'africastalking' => false, 'httpsms' => true, 'infobip' => true, + 'sislog' => false, ], // Client limits diff --git a/src/Ushahidi/DataSource/DataSourceManager.php b/src/Ushahidi/DataSource/DataSourceManager.php index 134f0ec74..e4b35678f 100644 --- a/src/Ushahidi/DataSource/DataSourceManager.php +++ b/src/Ushahidi/DataSource/DataSourceManager.php @@ -39,6 +39,7 @@ class DataSourceManager 'smssync' => SMSSync\SMSSync::class, 'twilio' => Twilio\Twilio::class, 'twitter' => Twitter\Twitter::class, + 'sislog' => Sislog\Sislog::class, ]; /** @@ -334,4 +335,9 @@ function ($consumer_key, $consumer_secret, $oauth_access_token, $oauth_access_to } ); } + + protected function createSislogSource(array $config) + { + return new Sislog\Sislog($config); + } } diff --git a/src/Ushahidi/DataSource/Sislog/Sislog.php b/src/Ushahidi/DataSource/Sislog/Sislog.php new file mode 100644 index 000000000..2c18d0dbe --- /dev/null +++ b/src/Ushahidi/DataSource/Sislog/Sislog.php @@ -0,0 +1,181 @@ + + * @package DataSource\Sislog + * @copyright 2024 Ushahidi + * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License Version 3 (GPLv3) + */ + +use Illuminate\Routing\Router; +use Illuminate\Support\Facades\Log; +use Ushahidi\DataSource\Contracts\MessageType; +use Ushahidi\DataSource\Contracts\MessageStatus; +use Ushahidi\DataSource\Contracts\CallbackDataSource; +use Ushahidi\DataSource\Contracts\OutgoingDataSource; +use Ushahidi\DataSource\Concerns\MapsInboundFields; + +class Sislog implements CallbackDataSource, OutgoingDataSource +{ + use MapsInboundFields; + + protected $config; + + /** + * Client to talk to the sislog API + * + * @var \Vonage\Message\Client + */ + private $client; + + protected $defaultServer = ''; + + /** + * Constructor function for DataSource + */ + public function __construct(array $config, \GuzzleHttp\Client $client = null) + { + $this->config = $config; + $this->client = $client; + } + + public function getName() + { + return 'Sislog'; + } + + public function getId() + { + return strtolower($this->getName()); + } + + public function getServices() + { + return [MessageType::SMS]; + } + + public function getOptions() + { + return [ + 'server_url' => [ + 'label' => 'FrontlineSMS Server URL', + 'input' => 'text', + 'description' => 'The URL where the Sislog server is installed, i.e. https://server.url.com/', + 'rules' => ['required'] + ], + 'from' => [ + 'label' => 'From', + 'input' => 'text', + 'description' => 'The from number', + 'rules' => ['required'] + ], + 'api_username' => [ + 'label' => 'Username', + 'input' => 'text', + 'description' => 'The API username', + 'rules' => ['required'] + ], + 'api_password' => [ + 'label' => 'Password', + 'input' => 'text', + 'description' => 'The API password', + 'rules' => ['required'] + ], + // 'api_secret' => [ + // 'label' => 'API secret', + // 'input' => 'text', + // 'description' => 'The API secret', + // 'rules' => ['required'] + // ] + ]; + } + + public function getInboundFields() + { + return [ + 'Message' => 'text' + ]; + } + + public function isUserConfigurable() + { + return true; + } + + /** + * @return mixed + */ + public function send($to, $message, $title = "", $contact_type = null) + { + // Obtain server url, ensure it ends with '/' + $serverUrl = $this->config['server_url'] ?? $this->defaultServer; + if (substr($serverUrl, -1) != '/') { + $serverUrl = $serverUrl . '/'; + } + // Check we have the required config + if (!isset($this->config['api_username']) || !isset($this->config['api_password'])) { + Log::warning('Could not send message with Sislog, incomplete config'); + return [MessageStatus::FAILED, false]; + } + + $auth = 'Authorization: Basic ' . base64_encode("$this->config['api_username']:$this->config['api_password']"); + + + // Prepare data to send to frontline cloud + $data = [ + "From" => "", + "To" => $to, + "Content" => $message + // "ClientReference" => $message + ]; + + // Make a POST request to send the data to frontline cloud + + try { + $response = $this->client->request('POST', $serverUrl . $this->apiUrl, [ + 'headers' => [ + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'Authorization' => $auth + ], + 'json' => $data + ]); + // Successfully executed the request + + if ($response->getStatusCode() === 200) { + return [MessageStatus::SENT, false]; + } + + // Log warning to log file. + $status = $response->getStatusCode(); + Log::warning( + 'Could not make a successful POST request', + ['message' => $response->messages[$status], 'status' => $status] + ); + } catch (\GuzzleHttp\Exception\ClientException | \GuzzleHttp\Exception\RequestException $e) { + // Log warning to log file. + Log::warning( + 'Could not make a successful POST request', + ['message' => $e->getMessage()] + ); + } + } + + public static function registerRoutes(Router $router) + { + $router->post('sms/sislog', 'Ushahidi\DataSource\Sislog\SislogController@handleRequest'); + } + + public function verifySecret($secret) + { + if (isset($this->config['secret']) and $secret === $this->config['secret']) { + return true; + } + + return false; + } +} diff --git a/src/Ushahidi/DataSource/Sislog/SislogController.php b/src/Ushahidi/DataSource/Sislog/SislogController.php new file mode 100644 index 000000000..7cba77b97 --- /dev/null +++ b/src/Ushahidi/DataSource/Sislog/SislogController.php @@ -0,0 +1,87 @@ + + * @package Ushahidi\DataSource + * @copyright 2024 Ushahidi + * @license https://www.gnu.org/licenses/agpl-3.0.html GNU Affero General Public License Version 3 (AGPL3) + */ + +use Ushahidi\DataSource\DataSourceController; +use Ushahidi\Contracts\Contact; +use Ushahidi\DataSource\Contracts\MessageType; +use Illuminate\Http\Request; + +class SislogController extends DataSourceController +{ + protected $source = 'sislog'; + + public function handleRequest(Request $request) + { + //// Authenticate the request + // if (!$this->source->verifySecret($request->input('secret'))) { + // return response(['payload' => [ + // 'success' => false, + // 'error' => 'Incorrect or missing secret key' + // ]], 403); + // } + + // Process incoming messages from Sislog only if the request is POST + if ($request->method() == 'POST') { + return $this->incoming($request); + } + + + // Set the response + return ['payload' => [ + 'success' => true, + 'error' => null + ]]; + } + + /** + * Process messages received from Sislog + */ + private function incoming($request) + { + $from = $request->input('msisdn'); + + if (empty($from)) { + return response(['payload' => [ + 'success' => false, + 'error' => 'Missing from value' + ]], 400); + } + + $message_text = $request->input('msg'); + + if (empty($message_text)) { + return response(['payload' => [ + 'success' => false, + 'error' => 'Missing message' + ]], 400); + } + + // Allow for Alphanumeric sender + $from = preg_replace("/[^0-9A-Za-z+ ]/", "", $from); + + + $this->save([ + 'type' => MessageType::SMS, + 'from' => $from, + 'contact_type' => Contact::PHONE, + 'message' => $message_text, + 'title' => null, + 'data_source' => 'sislog' + ]); + + return ['payload' => [ + 'success' => true, + 'error' => null + ]]; + } +}