Skip to content
Open
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
32 changes: 32 additions & 0 deletions src/Utopia/Messaging/Adapter/MMS.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Utopia\Messaging\Adapter;

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

abstract class MMS extends Adapter
{
protected const TYPE = 'mms';
protected const MESSAGE_TYPE = SMSMessage::class;

public function getType(): string
{
return static::TYPE;
}

public function getMessageType(): string
{
return static::MESSAGE_TYPE;
}

/**
* Send an MMS message.
*
* @param SMSMessage $message Message to send.
* @return array{deliveredTo: int, type: string, results: array<array<string, mixed>>}
*
* @throws \Exception If the message fails.
*/
abstract protected function process(SMSMessage $message): array;
}
33 changes: 33 additions & 0 deletions src/Utopia/Messaging/Adapter/MMS/Vonage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Utopia\Messaging\Adapter\MMS;

use Utopia\Messaging\Adapter\MMS as MMSAdapter;
use Utopia\Messaging\Adapter\VonageTrait;
use Utopia\Messaging\Messages\SMS as SMSMessage;

class Vonage extends MMSAdapter
{
use VonageTrait;

protected const NAME = 'Vonage';

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

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

/**
* {@inheritdoc}
* @throws \Exception
*/
protected function process(SMSMessage $message): array
{
return $this->processMessage($message, 'mms');
}
}
34 changes: 34 additions & 0 deletions src/Utopia/Messaging/Adapter/SMS/VonageMessages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Utopia\Messaging\Adapter\SMS;

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

class VonageMessages extends SMSAdapter
{
use VonageTrait;

protected const NAME = 'VonageMessages';

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

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

/**
* {@inheritdoc}
* @throws \Exception
*/
protected function process(SMSMessage $message): array
{
return $this->processMessage($message, 'sms');
}
}
32 changes: 32 additions & 0 deletions src/Utopia/Messaging/Adapter/Viber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Utopia\Messaging\Adapter;

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

abstract class Viber extends Adapter
{
protected const TYPE = 'viber';
protected const MESSAGE_TYPE = SMSMessage::class;

public function getType(): string
{
return static::TYPE;
}

public function getMessageType(): string
{
return static::MESSAGE_TYPE;
}

/**
* Send a Viber message.
*
* @param SMSMessage $message Message to send.
* @return array{deliveredTo: int, type: string, results: array<array<string, mixed>>}
*
* @throws \Exception If the message fails.
*/
abstract protected function process(SMSMessage $message): array;
}
33 changes: 33 additions & 0 deletions src/Utopia/Messaging/Adapter/Viber/Vonage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Utopia\Messaging\Adapter\Viber;

use Utopia\Messaging\Adapter\Viber as ViberAdapter;
use Utopia\Messaging\Adapter\VonageTrait;
use Utopia\Messaging\Messages\SMS as SMSMessage;

class Vonage extends ViberAdapter
{
use VonageTrait;

protected const NAME = 'Vonage';

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

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

/**
* {@inheritdoc}
* @throws \Exception
*/
protected function process(SMSMessage $message): array
{
return $this->processMessage($message, 'viber');
}
}
72 changes: 72 additions & 0 deletions src/Utopia/Messaging/Adapter/VonageTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Utopia\Messaging\Adapter;

use Utopia\Messaging\Helpers\JWT;
use Utopia\Messaging\Messages\SMS as SMSMessage;
use Utopia\Messaging\Response;

trait VonageTrait
{
/**
* @param string $applicationId Vonage Application ID
* @param string $privateKey Vonage Private Key
* @param string|null $from Sender phone number or name
*/
public function __construct(
private string $applicationId,
private string $privateKey,
private ?string $from = null
) {
}

/**
* @throws \Exception
*/
protected function processMessage(SMSMessage $message, string $channel): array
{
$payload = [
'from' => $this->from ?? $message->getFrom(),
'to' => \ltrim($message->getTo()[0], '+'),
'message_type' => 'text',
'text' => $message->getContent(),
'channel' => $channel,
];

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

$response = new Response($this->getType());
$result = $this->request(
method: 'POST',
url: 'https://api.nexmo.com/v1/messages',
headers: [
'Content-Type: application/json',
'Authorization: Bearer ' . $jwt,
'Accept: application/json',
],
body: $payload,
);

$statusCode = $result['statusCode'];
$res = $result['response'];

if ($statusCode >= 200 && $statusCode < 300 && isset($res['message_uuid'])) {
$response->setDeliveredTo(1);
$response->addResult($message->getTo()[0]);
} else {
$error = $res['detail'] ?? $res['title'] ?? 'Unknown error';
$response->addResult($message->getTo()[0], $error);
}

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

namespace Utopia\Messaging\Adapter;

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

abstract class WhatsApp extends Adapter
{
protected const TYPE = 'whatsapp';
protected const MESSAGE_TYPE = SMSMessage::class;

public function getType(): string
{
return static::TYPE;
}

public function getMessageType(): string
{
return static::MESSAGE_TYPE;
}

/**
* Send a WhatsApp message.
*
* @param SMSMessage $message Message to send.
* @return array{deliveredTo: int, type: string, results: array<array<string, mixed>>}
*
* @throws \Exception If the message fails.
*/
abstract protected function process(SMSMessage $message): array;
}
33 changes: 33 additions & 0 deletions src/Utopia/Messaging/Adapter/WhatsApp/Vonage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Utopia\Messaging\Adapter\WhatsApp;

use Utopia\Messaging\Adapter\WhatsApp as WhatsAppAdapter;
use Utopia\Messaging\Adapter\VonageTrait;
use Utopia\Messaging\Messages\SMS as SMSMessage;

class Vonage extends WhatsAppAdapter
{
use VonageTrait;

protected const NAME = 'Vonage';

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

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

/**
* {@inheritdoc}
* @throws \Exception
*/
protected function process(SMSMessage $message): array
{
return $this->processMessage($message, 'whatsapp');
}
}
Loading