diff --git a/src/Utopia/Messaging/Adapter/SMS/VonageMessages.php b/src/Utopia/Messaging/Adapter/SMS/VonageMessages.php new file mode 100644 index 00000000..396180ef --- /dev/null +++ b/src/Utopia/Messaging/Adapter/SMS/VonageMessages.php @@ -0,0 +1,98 @@ +getTo()[0], '+'); + $from = $this->from ?? $message->getFrom(); + $from = $from !== null ? \ltrim($from, '+') : null; + + $response = new Response($this->getType()); + + if (empty($from)) { + $response->addResult($message->getTo()[0], 'The "from" field is required for the Vonage Messages API.'); + return $response->toArray(); + } + + $result = $this->request( + method: 'POST', + url: $this->getApiEndpoint(), + headers: $this->getRequestHeaders(), + body: [ + 'message_type' => 'text', + 'to' => $to, + 'from' => $from, + 'text' => $message->getContent(), + 'channel' => 'sms', + ], + ); + + if ($result['statusCode'] === 202) { + $response->setDeliveredTo(1); + $response->addResult($message->getTo()[0]); + } else { + $errorMessage = 'Unknown error'; + if (isset($result['response']['detail'])) { + $errorMessage = $result['response']['detail']; + } elseif (isset($result['response']['title'])) { + $errorMessage = $result['response']['title']; + } elseif (!empty($result['error'])) { + $errorMessage = $result['error']; + } + + $response->addResult($message->getTo()[0], $errorMessage); + } + + return $response->toArray(); + } +} diff --git a/src/Utopia/Messaging/Adapter/VonageMessagesBase.php b/src/Utopia/Messaging/Adapter/VonageMessagesBase.php new file mode 100644 index 00000000..22659fa0 --- /dev/null +++ b/src/Utopia/Messaging/Adapter/VonageMessagesBase.php @@ -0,0 +1,50 @@ +apiKey}:{$this->apiSecret}"); + } + + /** + * Build the request headers for the Messages API. + * + * @return array + */ + protected function getRequestHeaders(): array + { + return [ + "Authorization: {$this->getAuthorizationHeader()}", + 'Content-Type: application/json', + 'Accept: application/json', + ]; + } +} diff --git a/tests/Messaging/Adapter/SMS/VonageMessagesTest.php b/tests/Messaging/Adapter/SMS/VonageMessagesTest.php new file mode 100644 index 00000000..b26a758a --- /dev/null +++ b/tests/Messaging/Adapter/SMS/VonageMessagesTest.php @@ -0,0 +1,69 @@ +markTestSkipped('Vonage Messages credentials or recipient are not available.'); + } + + $sender = new VonageMessages( + apiKey: $apiKey, + apiSecret: $apiSecret, + from: \getenv('VONAGE_FROM') ?: 'Vonage', + ); + + $message = new SMS( + to: [$to], + content: 'Test Content', + ); + + $response = $sender->send($message); + + $this->assertResponse($response); + } + + /** + * @throws \Exception + */ + public function testSendSMSWithFallbackFrom(): void + { + $apiKey = \getenv('VONAGE_API_KEY'); + $apiSecret = \getenv('VONAGE_API_SECRET'); + $to = \getenv('VONAGE_TO'); + $from = \getenv('VONAGE_FROM') ?: null; + + if (!$apiKey || !$apiSecret || !$to || !$from) { + $this->markTestSkipped('Vonage Messages credentials or sender/recipient are not available.'); + } + + $sender = new VonageMessages( + apiKey: $apiKey, + apiSecret: $apiSecret, + ); + + $message = new SMS( + to: [$to], + content: 'Test Content', + from: $from, + ); + + $response = $sender->send($message); + + $this->assertResponse($response); + } +}