Skip to content

feat: add Vonage multi-channel Messages adapter (#8139)#110

Open
deepshekhardas wants to merge 1 commit into
utopia-php:mainfrom
deepshekhardas:feat/8139-vonage-messages-adapter
Open

feat: add Vonage multi-channel Messages adapter (#8139)#110
deepshekhardas wants to merge 1 commit into
utopia-php:mainfrom
deepshekhardas:feat/8139-vonage-messages-adapter

Conversation

@deepshekhardas
Copy link
Copy Markdown

@deepshekhardas deepshekhardas commented Mar 16, 2026

Adds a Vonage multi-channel Messages adapter supporting SMS, WhatsApp, Viber, and MMS.

Changes

  • New \VonageTrait\ with shared HTTP transport (\src/Utopia/Messaging/Adapter/VonageTrait.php)
  • New SMS adapter: \VonageMessages\ (\src/Utopia/Messaging/Adapter/SMS/VonageMessages.php)
  • New WhatsApp adapter: \Vonage\ (\src/Utopia/Messaging/Adapter/WhatsApp/Vonage.php)
  • New Viber adapter: \Vonage\ (\src/Utopia/Messaging/Adapter/Viber/Vonage.php)
  • New MMS adapter: \Vonage\ (\src/Utopia/Messaging/Adapter/MMS/Vonage.php)
  • Abstract \MMS\ adapter class (\src/Utopia/Messaging/Adapter/MMS.php)
  • Abstract \Viber\ adapter class (\src/Utopia/Messaging/Adapter/Viber.php)
  • Abstract \WhatsApp\ adapter class (\src/Utopia/Messaging/Adapter/WhatsApp.php)
  • Tests for the Vonage Messages SMS adapter

Testing

  • Unit tests added for VonageMessages adapter
  • Follows existing adapter patterns (Telnyx, Mock, etc.)

Closes #8139

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 16, 2026

Warning

Rate limit exceeded

@deepshekhardas has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 29 minutes and 8 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7a7c8cc9-e56f-4b5b-b848-bdb8839131d9

📥 Commits

Reviewing files that changed from the base of the PR and between fcb4c3c and ba22934.

📒 Files selected for processing (9)
  • src/Utopia/Messaging/Adapter/MMS.php
  • src/Utopia/Messaging/Adapter/MMS/Vonage.php
  • src/Utopia/Messaging/Adapter/SMS/VonageMessages.php
  • src/Utopia/Messaging/Adapter/Viber.php
  • src/Utopia/Messaging/Adapter/Viber/Vonage.php
  • src/Utopia/Messaging/Adapter/VonageTrait.php
  • src/Utopia/Messaging/Adapter/WhatsApp.php
  • src/Utopia/Messaging/Adapter/WhatsApp/Vonage.php
  • tests/Messaging/Adapter/SMS/VonageMessagesTest.php
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can generate walkthrough in a markdown collapsible section to save space.

Enable the reviews.collapse_walkthrough setting to generate walkthrough in a markdown collapsible section.

@deepshekhardas deepshekhardas force-pushed the feat/8139-vonage-messages-adapter branch from ba22934 to d623ac7 Compare June 2, 2026 01:54
@deepshekhardas
Copy link
Copy Markdown
Author

Rebased onto latest main. Could you please review? 🙏

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Jun 2, 2026

Greptile Summary

This PR introduces Vonage multi-channel messaging support (SMS via the Messages API, WhatsApp, Viber, and MMS) by extracting shared JWT authentication and HTTP request logic into a VonageTrait, and adding new abstract base adapters (MMS, Viber, WhatsApp) that mirror the existing SMS adapter pattern.

  • VonageMessages.php has a fatal missing import: use Utopia\\Messaging\\Adapter\\VonageTrait; is absent, so PHP resolves use VonageTrait; against the current namespace and throws a "Class not found" error. The other three adapters (WhatsApp, Viber, MMS) import the trait correctly.
  • Test file is non-functional: every test method calls setEndpoint() which isn't defined on any of these adapters (only on Mock), and all four methods pass the array returned by send() directly to json_decode(), which is a TypeError in PHP 8.

Confidence Score: 2/5

Not safe to merge — the primary new adapter (VonageMessages) will crash on instantiation, and none of the tests will run successfully.

The missing trait import in VonageMessages.php makes that adapter completely unusable at runtime. The entire test suite for this feature also fails before executing a single assertion: setEndpoint() doesn't exist on any of the new adapters, and json_decode() receives an array instead of a string.

src/Utopia/Messaging/Adapter/SMS/VonageMessages.php (missing trait import) and tests/Messaging/Adapter/SMS/VonageMessagesTest.php (undefined method call and type mismatch in all four test methods).

Important Files Changed

Filename Overview
src/Utopia/Messaging/Adapter/SMS/VonageMessages.php Missing use Utopia\Messaging\Adapter\VonageTrait; import causes a fatal PHP error; also carries two unused imports (JWT, Response).
src/Utopia/Messaging/Adapter/VonageTrait.php Core shared logic for JWT auth and Vonage Messages API calls; two separate \time() calls for iat/exp could drift by one second.
tests/Messaging/Adapter/SMS/VonageMessagesTest.php All four test methods call setEndpoint() (undefined on these adapters) and pass the array return of send() to json_decode() — both cause fatal errors.
src/Utopia/Messaging/Adapter/MMS/Vonage.php Thin adapter delegating to VonageTrait::processMessage with channel='mms'; imports and trait usage are correct.
src/Utopia/Messaging/Adapter/Viber/Vonage.php Thin adapter delegating to VonageTrait::processMessage with channel='viber'; imports and trait usage are correct.
src/Utopia/Messaging/Adapter/WhatsApp/Vonage.php Thin adapter delegating to VonageTrait::processMessage with channel='whatsapp'; imports and trait usage are correct.
src/Utopia/Messaging/Adapter/MMS.php New abstract MMS base adapter; mirrors the existing SMS and WhatsApp abstract class structure cleanly.
src/Utopia/Messaging/Adapter/Viber.php New abstract Viber base adapter; consistent with the project's adapter pattern.
src/Utopia/Messaging/Adapter/WhatsApp.php New abstract WhatsApp base adapter; consistent with the project's adapter pattern.

Reviews (1): Last reviewed commit: "feat: add Vonage multi-channel Messages ..." | Re-trigger Greptile

Comment on lines +5 to +8
use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Helpers\JWT;
use Utopia\Messaging\Messages\SMS as SMSMessage;
use Utopia\Messaging\Response;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P0 VonageTrait is never imported in this file. Because VonageMessages lives in Utopia\Messaging\Adapter\SMS, PHP will look for Utopia\Messaging\Adapter\SMS\VonageTrait when it encounters use VonageTrait; — a class that doesn't exist — causing a fatal "Class not found" error at runtime. Additionally, JWT and Response are imported here but never used directly in this class (they are consumed by the trait), making those imports both redundant and misleading.

Suggested change
use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Helpers\JWT;
use Utopia\Messaging\Messages\SMS as SMSMessage;
use Utopia\Messaging\Response;
use Utopia\Messaging\Adapter\SMS as SMSAdapter;
use Utopia\Messaging\Adapter\VonageTrait;
use Utopia\Messaging\Messages\SMS as SMSMessage;

Comment on lines +37 to +45

// This assumes the mock server returns a success response
// In a real environment, we'd check the request-catcher data
$this->assertNotEmpty($result);
}

public function testSendWhatsApp(): void
{
$sender = new VonageWhatsApp($this->applicationId, $this->privateKey);
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 setEndpoint() is undefined on these adapters. None of VonageMessages, VonageWhatsApp, VonageViber, or VonageMMS define a setEndpoint() method — it only exists on Mock. Every test method in this class will crash with "Call to undefined method" before reaching any assertions. The same issue occurs in all four test methods (testSendSMS, testSendWhatsApp, testSendViber, testSendMMS). Either add setEndpoint() / getEndpoint() to VonageTrait, or use an environment variable / constructor parameter to override the base URL.

Comment on lines +43 to +45
public function testSendWhatsApp(): void
{
$sender = new VonageWhatsApp($this->applicationId, $this->privateKey);
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 json_decode receives an array, not a string. send() returns array, so \json_decode($response, true) is called with an array argument. In PHP 8 this causes a TypeError; in earlier versions it silently returns null, making assertNotEmpty($result) fail. The same pattern is repeated in all four test methods. Either call send() directly and use assertResponse() (already defined in Base), or cast to JSON before decoding.

Comment on lines +36 to +42
$jwt = JWT::encode(
[
'application_id' => $this->applicationId,
'iat' => \time(),
'jti' => \bin2hex(\random_bytes(16)),
'exp' => \time() + 3600,
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Both iat and exp call ime() separately. In the unlikely but possible case where the system clock advances between the two calls, exp will differ from iat + 3600 by a second. Capture the timestamp once to guarantee consistency.

Suggested change
$jwt = JWT::encode(
[
'application_id' => $this->applicationId,
'iat' => \time(),
'jti' => \bin2hex(\random_bytes(16)),
'exp' => \time() + 3600,
],
$now = \time();
$jwt = JWT::encode(
[
'application_id' => $this->applicationId,
'iat' => $now,
'jti' => \bin2hex(\random_bytes(16)),
'exp' => $now + 3600,
],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant