From 849f1cc53ee068e31aa4e4ce4d0292be9de1dcac Mon Sep 17 00:00:00 2001 From: Jepp9350 <2jepp9350@gmail.com> Date: Thu, 10 Apr 2025 10:51:32 +0200 Subject: [PATCH] Add GatewayAPI module with configuration, routing, and core logic Introduced a new GatewayAPI module to handle SMS messaging integration. This includes interfaces, core classes for API interaction, configuration management, and routing for config retrieval and update. Added necessary initializations in `index.php` to integrate the module seamlessly. --- services/nginx/app/classes/gatewayapi.php | 169 ++++++++++++++++++ services/nginx/app/index.php | 1 + .../nginx/app/interfaces/gatewayapi_i.php | 44 +++++ .../config/gatewayapi_api_key_c.php | 29 +++ .../config/gatewayapi_api_secret_c.php | 29 +++ .../config/gatewayapi_api_token_c.php | 29 +++ .../config/gatewayapi_enabled_c.php | 29 +++ .../gatewayapi/config/gatewayapi_sender_c.php | 29 +++ .../app/modules/gatewayapi/gatewayapi_c.php | 69 +++++++ .../nginx/app/routes/moduleConfigRoute.php | 38 ++++ .../app/routes/moduleGatewayAPIRoute.php | 21 +++ 11 files changed, 487 insertions(+) create mode 100644 services/nginx/app/classes/gatewayapi.php create mode 100644 services/nginx/app/interfaces/gatewayapi_i.php create mode 100644 services/nginx/app/modules/gatewayapi/config/gatewayapi_api_key_c.php create mode 100644 services/nginx/app/modules/gatewayapi/config/gatewayapi_api_secret_c.php create mode 100644 services/nginx/app/modules/gatewayapi/config/gatewayapi_api_token_c.php create mode 100644 services/nginx/app/modules/gatewayapi/config/gatewayapi_enabled_c.php create mode 100644 services/nginx/app/modules/gatewayapi/config/gatewayapi_sender_c.php create mode 100644 services/nginx/app/modules/gatewayapi/gatewayapi_c.php create mode 100644 services/nginx/app/routes/moduleGatewayAPIRoute.php diff --git a/services/nginx/app/classes/gatewayapi.php b/services/nginx/app/classes/gatewayapi.php new file mode 100644 index 00000000..abcecc02 --- /dev/null +++ b/services/nginx/app/classes/gatewayapi.php @@ -0,0 +1,169 @@ +config = new gatewayapi_c(); + } + + /** + * @inheritDoc + */ + public function send(array $to, string $message): bool + { + $this->requireEnabled(); + $data = [ + "recipients" => array_map(function ($recipient) { + return [ + 'msisdn' => $recipient, + ]; + }, $to), + 'message' => $message, + 'sender' => $this->config->sender->getVariableValue(), + ]; + $headers = [ + 'Authorization: ' . $this->config->api_key->getVariableValue(), + 'Content-Type: application/json' + ]; + try { + self::sendRequest( + '/rest/mtsms', + 'POST', + $data, + ); + } catch (Exception $exception) { + throw new Exception('Failed to send SMS: ' . $exception->getMessage()); + } + return true; + } + + /** + * @inheritDoc + */ + public function requireEnabled(): void + { + if (!$this->isEnabled()) { + throw new Exception('GatewayAPI is not enabled'); + } + } + + /** + * @inheritDoc + * @throws Exception If the enabled property is not set + */ + public function isEnabled(): bool + { + try { + return $this->config->enabled->isTrue(); + } catch (Exception $exception) { + return false; + } + } + + /** + * @inheritDoc + * @throws Exception If the module is not enabled + * @throws Exception If the API key is not set + * @throws Exception If the sender is not set + * @throws Exception If the API URL is not set + * @throws Exception If the request fails + * @throws Exception If the response is not valid JSON + */ + public function sendRequest(string $url, string $method, array $data = [], array $headers = []): array + { + self::requireEnabled(); + $json_encode = json_encode($data); + if ($json_encode === false) { + throw new Exception('Failed to encode data to JSON: ' . json_last_error_msg()); + } + if (empty($url) || empty($method)) { + throw new Exception('URL and method are required'); + } + // Add the token to the headers + return self::curlRequest( + $url, + $method, + $json_encode, + [ + ...$headers, + ...self::getDefaultRequestHeaders(), + ] + ); + } + + /** + * @param string $endpoint The URL endpoint to send the request to (e.g. /rest/mtsms) + * @param string $method The HTTP method to use (GET, POST, PUT, DELETE) + * @param string $json_encode The JSON-encoded data to send + * @param array $headers The headers to send with the request + * @param bool $allow_fail If true, the response will be returned even if the HTTP code is not 200, otherwise an exception will be thrown + * @throws Exception If the request fails + * @throws Exception If the response is not valid JSON + */ + private function curlRequest(string $endpoint, string $method, string $json_encode, array $headers, bool $allow_fail = false): array + { + $curl = curl_init(); + curl_setopt_array($curl, [ + CURLOPT_URL => $this->api_url . $endpoint, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $json_encode, + CURLOPT_HTTPHEADER => $headers + ]); + $response = curl_exec($curl); + $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + curl_close($curl); + if ($http_code !== 200 && !$allow_fail) { + throw new Exception('Request failed with HTTP code ' . $http_code . ': ' . $response); + } + if (empty($response)) { + throw new Exception('Empty response from API'); + } + $response = json_decode($response, true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception('Failed to decode JSON response: ' . json_last_error_msg()); + } + if (!is_array($response)) { + throw new Exception('Invalid response format: ' . gettype($response)); + } + // Check if the response is an array + return $response; + } + + /** + * @inheritDoc + */ + public function getDefaultRequestHeaders(): array + { + return [ + 'Authorization: Token ' . $this->config->api_token->getVariableValue(), + 'Content-Type: application/json', + ]; + } +} \ No newline at end of file diff --git a/services/nginx/app/index.php b/services/nginx/app/index.php index da04e974..82d331cc 100644 --- a/services/nginx/app/index.php +++ b/services/nginx/app/index.php @@ -64,6 +64,7 @@ require_once 'classes/stripe.php'; require_once 'classes/form.php'; require_once 'classes/pdf_generator.php'; require_once 'classes/fxratesapi.php'; +require_once 'classes/gatewayapi.php'; /** * Modules diff --git a/services/nginx/app/interfaces/gatewayapi_i.php b/services/nginx/app/interfaces/gatewayapi_i.php new file mode 100644 index 00000000..57bedfe6 --- /dev/null +++ b/services/nginx/app/interfaces/gatewayapi_i.php @@ -0,0 +1,44 @@ +setupConfig('GatewayAPI'); + $this->allowUpdate([ + gatewayapi_enabled_c::class, + gatewayapi_api_key_c::class, + gatewayapi_api_secret_c::class, + gatewayapi_sender_c::class, + gatewayapi_api_token_c::class, + ]); + $this->enabled = new gatewayapi_enabled_c(); + $this->api_key = new gatewayapi_api_key_c(); + $this->api_secret = new gatewayapi_api_secret_c(); + $this->sender = new gatewayapi_sender_c(); + $this->api_token = new gatewayapi_api_token_c(); + } + +} \ No newline at end of file diff --git a/services/nginx/app/routes/moduleConfigRoute.php b/services/nginx/app/routes/moduleConfigRoute.php index b3040648..08e7ba55 100644 --- a/services/nginx/app/routes/moduleConfigRoute.php +++ b/services/nginx/app/routes/moduleConfigRoute.php @@ -333,5 +333,43 @@ class moduleConfigRoute 'fxratesapi_config' => 'Update fxratesapi config' ] ); + /** GatewayAPI config > GET */ + $this->get('/gatewayapi/config', function () { + global $response; + $this->requirePermission('gatewayapi_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('gatewayapi_config', 'global', 1, $user->id, 'GATEWAYAPI_CONFIG', 'Successfully fetched gatewayapi config'); + $response->success( + (new \classes\gatewayapi())->config->getConfigRequest() + ); + } else { + (new logs_o())->add('gatewayapi_config', 'global', 1, 0, 'GATEWAYAPI_CONFIG', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'gatewayapi_config' => 'Get gatewayapi config' + ] + ); + /** GatewayAPI config > POST */ + $this->post('/gatewayapi/config', function () { + global $response; + $this->requirePermission('gatewayapi_config'); + $user = (new authentication())->get_user(); + if ($user) { + (new logs_o())->add('gatewayapi_config', 'global', 1, $user->id, 'GATEWAYAPI_CONFIG', 'Successfully updated gatewayapi config'); + $response->success( + (new \classes\gatewayapi())->config->postConfigRequest() + ); + } else { + (new logs_o())->add('gatewayapi_config', 'global', 1, 0, 'GATEWAYAPI_CONFIG', 'No user found, or invalid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'gatewayapi_config' => 'Update gatewayapi config' + ] + ); } } \ No newline at end of file diff --git a/services/nginx/app/routes/moduleGatewayAPIRoute.php b/services/nginx/app/routes/moduleGatewayAPIRoute.php new file mode 100644 index 00000000..654d575a --- /dev/null +++ b/services/nginx/app/routes/moduleGatewayAPIRoute.php @@ -0,0 +1,21 @@ +