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
3 changes: 3 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ FAST2SMS_MESSAGE_ID=
FAST2SMS_TO=
INFORU_API_TOKEN=
INFORU_SENDER_ID=
SEMAPHORE_API_KEY=
SEMAPHORE_TO=
SEMAPHORE_SENDER_NAME=
135 changes: 135 additions & 0 deletions src/Utopia/Messaging/Adapter/SMS/Semaphore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

namespace Utopia\Messaging\Adapter\SMS;

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

// Reference Material
// https://semaphore.co/docs

class Semaphore extends SMSAdapter
{
protected const NAME = 'Semaphore';

/**
* @param string $apikey Semaphore api key
*/


public function __construct(
private string $apikey
) {
}

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

public function getMaxMessagesPerRequest(): int
{
// NOTE: user can do upto 1000 numbers per API call
return 1000;
}

/**
* {@inheritdoc}
*/
public function process(SMSMessage $message): array
{
$response = new Response($this->getType());
$result = $this->request(
method: 'POST',
url: 'https://api.semaphore.co/api/v4/messages',
headers: [
'Content-Type: application/json',
],
body: [
'apikey' => $this->apikey,
'number' => $message->getTo()[0],

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 Bulk sends drop recipients

When a message contains 2–1000 recipients, the adapter accepts the message but submits and records only getTo()[0], causing every remaining recipient to be silently omitted from delivery and results.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Utopia/Messaging/Adapter/SMS/Semaphore.php
Line: 51

Comment:
**Bulk sends drop recipients**

When a message contains 2–1000 recipients, the adapter accepts the message but submits and records only `getTo()[0]`, causing every remaining recipient to be silently omitted from delivery and results.

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

Fix in Claude Code Fix in Codex

'message' => $message->getContent(),
'sendername' => $message->getFrom()
],
);

if ($result['statusCode'] === 200) {
if ($result['response'][0] && count($result['response'][0]) > 1) {

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 Validation errors access missing index

When Semaphore returns its documented 200 validation-error object keyed by fields such as sendername, this condition reads the nonexistent numeric key 0, causing an undefined-array-key warning before error handling continues.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Utopia/Messaging/Adapter/SMS/Semaphore.php
Line: 58

Comment:
**Validation errors access missing index**

When Semaphore returns its documented 200 validation-error object keyed by fields such as `sendername`, this condition reads the nonexistent numeric key `0`, causing an undefined-array-key warning before error handling continues.

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

Fix in Claude Code Fix in Codex

$response->addResult($message->getTo()[0]);

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 Successful delivery count stays zero

When Semaphore returns a successful response, this branch adds a result without updating deliveredTo, causing successful sends to report zero deliveries and fail the shared adapter response assertion.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Utopia/Messaging/Adapter/SMS/Semaphore.php
Line: 59

Comment:
**Successful delivery count stays zero**

When Semaphore returns a successful response, this branch adds a result without updating `deliveredTo`, causing successful sends to report zero deliveries and fail the shared adapter response assertion.

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

Fix in Claude Code Fix in Codex

} else {
foreach ($result['response'] as $variableName) {
$errorMessage = $variableName;
if (is_array($variableName)) {
$response->addResult($message->getTo()[0], $errorMessage[0]);
} else {
$response->addResult($message->getTo()[0], 'Unknown error');
}
}
}
}
if ($result['statusCode'] === 500) {
$response->addResult($message->getTo()[0], $result['response'][0]);
}
Comment on lines +70 to +73

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 Non-500 failures lose results

When Semaphore returns an authentication, validation, rate-limit, service, or transport failure with a status other than 500, neither branch adds a result, causing the adapter to return an empty result set with no recipient or error details.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/Utopia/Messaging/Adapter/SMS/Semaphore.php
Line: 70-73

Comment:
**Non-500 failures lose results**

When Semaphore returns an authentication, validation, rate-limit, service, or transport failure with a status other than 500, neither branch adds a result, causing the adapter to return an empty result set with no recipient or error details.

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

Fix in Claude Code Fix in Codex


return $response->toArray();
}
}


// Below is a Sample Error response for bad payload
// The status code is 200 even if there is an error.
// The status code is 200 if semaphore returns a response irrespective of good or error response

// $errorResponse = array(
// "url" => "https://api.semaphore.co/api/v4/messages",
// "statusCode" => 200,
// "response" => array(
// "sendername" => array(
// "The selected sendername is invalid."
// )
// ),
// "error" => ""
// );



// Below is a Sample Error response when Semaphore credits are empty

// $errorResponse = [
// "url" => "https://api.semaphore.co/api/v4/messages",
// "statusCode" => 500,
// "response" => [
// "Your current balance of 0 credits is not sufficient. This transaction requires 1 credits."
// ],
// "error" => ""
// ];



// Below is a sample success response
// Unlike error response, More than 1 keys are returned in the response array. Refer to docs

// $successResponse = array(
// "url" => "https://api.semaphore.co/api/v4/messages",
// "statusCode" => 200,
// "response" => array(
// array(
// "message_id" => 212210271,
// "user_id" => 40495,
// "user" => "hello@gmail.com",
// "account_id" => 40356,
// "account" => "Semiphore",
// "recipient" => "639358574402",
// "message" => "Nice meeting you",
// "sender_name" => "Semaphore",
// "network" => "Globe",
// "status" => "Pending",
// "type" => "Single",
// "source" => "Api",
// "created_at" => "2024-03-12 23:14:50",
// "updated_at" => "2024-03-12 23:14:50"
// )
// ),
// "error" => ""
// );
25 changes: 25 additions & 0 deletions tests/Messaging/Adapter/SMS/SemaphoreTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Utopia\Tests\Adapter\SMS;

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

class SemaphoreTest extends Base
{
public function testSendSMS(): void
{
$sender = new Semaphore(getenv('SEMAPHORE_API_KEY'));

$message = new SMS(
[getenv('SEMAPHORE_TO')],
'Test Content',
getenv('SEMAPHORE_SENDER_NAME')
);

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

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