Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/Utopia/Messaging/Adapter/SMS/SMSGateApp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Utopia\Messaging\Adapter\SMS;

use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Messages\SMS as SMSMessage;
use Utopia\Messaging\Response;

class SMSGateApp extends SMSAdapter
{
protected const NAME = 'SMS Gateway for Android™';
protected const DEFAULT_API_ENDPOINT = 'https://api.sms-gate.app/3rdparty/v1';

public function __construct(
private readonly string $apiUsername,
private readonly string $apiPassword,
private readonly string $apiEndpoint = self::DEFAULT_API_ENDPOINT,
) {
parent::__construct();
}

public function getName(): string
{
return static::NAME;
}

public function getMaxMessagesPerRequest(): int
{
return 10;
}

protected function process(SMSMessage $message): array
{
$response = new Response($this->getType());

$body = [
'textMessage' => [
'text' => $message->getContent(),
],
'phoneNumbers' => $message->getTo(),
];

$result = $this->request(
method: 'POST',
url: $this->apiEndpoint . '/messages?skipPhoneValidation=true',
headers: [
'Content-Type: application/json',
'Authorization: Basic ' . base64_encode("{$this->apiUsername}:{$this->apiPassword}"),
],
body: $body,
);

if ($result['statusCode'] === 202) {
$success = 0;
foreach ($result['response']['recipients'] as $recipient) {
$response->addResult($recipient['phoneNumber'], $recipient['error'] ?? '');

if ($recipient['state'] !== 'Failed') {
$success++;
}
}

$response->setDeliveredTo($success);
} else {
$errorMessage = $result['response']['message'] ?? 'Unknown error';
foreach ($message->getTo() as $recipient) {
$response->addResult($recipient, $errorMessage);
}
}

return $response->toArray();
}
}
34 changes: 34 additions & 0 deletions tests/Messaging/Adapter/SMS/SMSGateAppTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Utopia\Tests\Adapter\SMS;

use Utopia\Messaging\Adapter\SMS\SMSGateApp;
use Utopia\Messaging\Messages\SMS;
use Utopia\Tests\Adapter\Base;

class SMSGateAppTest extends Base
{
public function testSendSMS(): void
{
$username = \getenv('SMSGATEAPP_USERNAME');
$password = \getenv('SMSGATEAPP_PASSWORD');
$to = \getenv('SMSGATEAPP_TO');

if (!$username || !$password || !$to) {
$this->markTestSkipped('SMSGateApp credentials not configured');
}

$endpoint = \getenv('SMSGATEAPP_ENDPOINT') ?: null;

$sender = new SMSGateApp($username, $password, $endpoint);
Comment on lines +21 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Null endpoint bypasses default

When the credentials and recipient are configured but SMSGATEAPP_ENDPOINT is unset, the test explicitly passes null to the non-nullable string constructor parameter, causing a TypeError instead of using DEFAULT_API_ENDPOINT and sending the SMS.

Prompt To Fix With AI
This is a comment left during a code review.
Path: tests/Messaging/Adapter/SMS/SMSGateAppTest.php
Line: 21-23

Comment:
**Null endpoint bypasses default**

When the credentials and recipient are configured but `SMSGATEAPP_ENDPOINT` is unset, the test explicitly passes `null` to the non-nullable `string` constructor parameter, causing a `TypeError` instead of using `DEFAULT_API_ENDPOINT` and sending the SMS.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex


$message = new SMS(
to: [$to],
content: 'Test content from SMSGateApp'
);

$response = $sender->send($message);

$this->assertResponse($response);
}
}