From 99b5ac8669d60997454ceef3c1758f8d7067c21f Mon Sep 17 00:00:00 2001 From: prateek banga Date: Thu, 19 Oct 2023 13:29:48 +0530 Subject: [PATCH 1/5] adds push and sms controllers --- .env | 2 + app/controllers/api/messaging.php | 379 ++++++++- composer.lock | 2 +- docker-compose.yml | 3 +- tests/e2e/Services/GraphQL/Base.php | 76 ++ tests/e2e/Services/GraphQL/MessagingTest.php | 761 +++++++++++++++++- .../e2e/Services/Messaging/MessagingBase.php | 598 +++++++++++++- 7 files changed, 1805 insertions(+), 16 deletions(-) diff --git a/.env b/.env index aa90470729..127efd2e4a 100644 --- a/.env +++ b/.env @@ -108,3 +108,5 @@ _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL= _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION= +_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY= +_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN= diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 72f0b9fdb4..8735cf57de 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -22,6 +22,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; use Utopia\Database\Validator\UID; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; +use Utopia\Validator\JSON; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -1593,7 +1594,7 @@ App::post('/v1/messaging/messages/email') $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty()) { + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'email') { throw new Exception(Exception::PROVIDER_NOT_FOUND); } @@ -1602,14 +1603,183 @@ App::post('/v1/messaging/messages/email') 'providerId' => $provider->getId(), 'providerInternalId' => $provider->getInternalId(), 'to' => $to, + 'description' => $description, 'data' => [ 'subject' => $subject, 'content' => $content, 'html' => $html, - 'description' => $description, ], 'status' => $status, - 'search' => $messageId . ' ' . $description . ' ' . $subject, + 'search' => $messageId . ' ' . $description . ' ' . $subject . ' ' . $providerId, + ])); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::post('/v1/messaging/messages/sms') + ->desc('Create an sms.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createSMS') + ->label('sdk.description', '/docs/references/messaging/create-sms.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new UID(), 'SMS Provider ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('content', '', new Text(64230), 'SMS Content.') + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, string $providerId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'sms') { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $message = $dbForProject->createDocument('messages', new Document([ + '$id' => $messageId, + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'description' => $description, + 'data' => [ + 'content' => $content, + ], + 'status' => $status, + 'search' => $messageId . ' ' . $description . ' ' . $providerId, + ])); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->setStatusCode(Response::STATUS_CODE_CREATED) + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::post('/v1/messaging/messages/push') + ->desc('Create a push notification.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.create') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'createPushNotification') + ->label('sdk.description', '/docs/references/messaging/create-push-notification.md') + ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') + ->param('providerId', '', new UID(), 'Push Provider ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('title', '', new Text(256), 'Title for push notification.') + ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('data', null, new JSON(), 'Additional Data for push notification.', true) + ->param('action', '', new Text(256), 'Action for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification.', true) + ->param('sound', '', new Text(256), 'Sound for push notification.', true) + ->param('color', '', new Text(256), 'Color for push notification.', true) + ->param('tag', '', new Text(256), 'Tag for push notification.', true) + ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, string $providerId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; + + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty() || $provider->getAttribute('type') !== 'push') { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $pushData = [ + 'title' => $title, + 'body' => $body, + ]; + + if (!is_null($data)) { + $pushData['data'] = $data; + } + + if ($action) { + $pushData['action'] = $action; + } + + if ($icon) { + $pushData['icon'] = $icon; + } + + if ($sound) { + $pushData['sound'] = $sound; + } + + if ($color) { + $pushData['color'] = $color; + } + + if ($tag) { + $pushData['tag'] = $tag; + } + + if ($badge) { + $pushData['badge'] = $badge; + } + + $message = $dbForProject->createDocument('messages', new Document([ + '$id' => $messageId, + 'providerId' => $provider->getId(), + 'providerInternalId' => $provider->getInternalId(), + 'to' => $to, + 'description' => $description, + 'data' => $pushData, + 'status' => $status, + 'search' => $messageId . ' ' . $description . ' ' . $title . ' ' . $providerId, ])); if ($status === 'processing') { @@ -1704,7 +1874,7 @@ App::patch('/v1/messaging/messages/email/:messageId') ->label('sdk.namespace', 'messaging') ->label('sdk.method', 'updateEmail') ->label('sdk.description', '/docs/references/messaging/update-email.md') - ->label('sdk.response.code', Response::STATUS_CODE_CREATED) + ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_MESSAGE) ->param('messageId', '', new UID(), 'Message ID.') @@ -1744,21 +1914,212 @@ App::patch('/v1/messaging/messages/email/:messageId') $data['content'] = $content; } - if (!empty($description)) { - $data['description'] = $description; - } - if (!empty($html)) { $data['html'] = $html; } $message->setAttribute('data', $data); - $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject']); + $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $data['subject'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($description)) { + $message->setAttribute('description', $description); + } if (!empty($status)) { $message->setAttribute('status', $status); } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::patch('/v1/messaging/messages/sms/:messageId') + ->desc('Update an sms.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.update') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updateSMS') + ->label('sdk.description', '/docs/references/messaging/update-email.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('content', '', new Text(64230), 'Email Content.', true) + ->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + if ($message->getAttribute('status') === 'sent') { + throw new Exception(Exception::MESSAGE_ALREADY_SENT); + } + + if (\count($to) > 0) { + $message->setAttribute('to', $to); + } + + $data = $message->getAttribute('data'); + + if (!empty($content)) { + $data['content'] = $content; + } + + $message->setAttribute('data', $data); + $message->setAttribute('search', $message->getId() . ' ' . $data['description'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($status)) { + $message->setAttribute('status', $status); + } + + if (!empty($description)) { + $message->setAttribute('description', $description); + } + + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); + + if ($status === 'processing') { + $messaging + ->setMessageId($message->getId()) + ->setProject($project); + + if (!empty($deliveryTime)) { + $messaging + ->setDeliveryTime($deliveryTime) + ->schedule(); + } else { + $messaging->trigger(); + } + } + + $response + ->dynamic($message, Response::MODEL_MESSAGE); + }); + +App::patch('/v1/messaging/messages/push/:messageId') + ->desc('Update a push notification.') + ->groups(['api', 'messaging']) + ->label('audits.event', 'messages.update') + ->label('audits.resource', 'messages/{response.$id}') + ->label('scope', 'messages.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'updatePushNotification') + ->label('sdk.description', '/docs/references/messaging/update-push-notification.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_MESSAGE) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.', true) + ->param('description', '', new Text(256), 'Description for Message.', true) + ->param('title', '', new Text(256), 'Title for push notification.', true) + ->param('body', '', new Text(64230), 'Body for push notification.', true) + ->param('data', null, new JSON(), 'Additional Data for push notification.', true) + ->param('action', '', new Text(256), 'Action for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification.', true) + ->param('sound', '', new Text(256), 'Sound for push notification.', true) + ->param('color', '', new Text(256), 'Color for push notification.', true) + ->param('tag', '', new Text(256), 'Tag for push notification.', true) + ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) + ->inject('dbForProject') + ->inject('project') + ->inject('messaging') + ->inject('response') + ->action(function (string $messageId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + if ($message->getAttribute('status') === 'sent') { + throw new Exception(Exception::MESSAGE_ALREADY_SENT); + } + + if (\count($to) > 0) { + $message->setAttribute('to', $to); + } + + $pushData = $message->getAttribute('data'); + + if ($title) { + $pushData['title'] = $title; + } + + if ($body) { + $pushData['body'] = $body; + } + + if (!is_null($data)) { + $pushData['data'] = $data; + } + + if ($action) { + $pushData['action'] = $action; + } + + if ($icon) { + $pushData['icon'] = $icon; + } + + if ($sound) { + $pushData['sound'] = $sound; + } + + if ($color) { + $pushData['color'] = $color; + } + + if ($tag) { + $pushData['tag'] = $tag; + } + + if ($badge) { + $pushData['badge'] = $badge; + } + + $message->setAttribute('data', $pushData); + $message->setAttribute('search', $message->getId() . ' ' . $pushData['description'] . ' ' . $pushData['title'] . ' ' . $message->getAttribute('providerId')); + + if (!empty($status)) { + $message->setAttribute('status', $status); + } + + if (!empty($description)) { + $message->setAttribute('description', $description); + } + + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { diff --git a/composer.lock b/composer.lock index 8f7ca86d06..e44b093609 100644 --- a/composer.lock +++ b/composer.lock @@ -6019,5 +6019,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/docker-compose.yml b/docker-compose.yml index a365ce17ba..c8a7b6c64b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -197,7 +197,8 @@ services: - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL - _APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION - + - _APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY + - _APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN appwrite-realtime: entrypoint: realtime <<: *x-logging diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index f3947c53b4..9cd4fe0629 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -240,9 +240,15 @@ trait Base // Messages public static string $CREATE_EMAIL = 'create_email'; + public static string $CREATE_SMS = 'create_sms'; + public static string $CREATE_PUSH_NOTIFICATION = 'create_push_notification'; public static string $LIST_MESSAGES = 'list_messages'; public static string $GET_MESSAGE = 'get_message'; + public static string $UPDATE_EMAIL = 'update_email'; + public static string $UPDATE_SMS = 'update_sms'; + public static string $UPDATE_PUSH_NOTIFICATION = 'update_push_notification'; + // Complex queries public static string $COMPLEX_QUERY = 'complex_query'; @@ -2098,6 +2104,34 @@ trait Base description } }'; + case self::$CREATE_SMS: + return 'mutation createSMS($messageId: String!, $providerId: String!, $to: [String!]!, $content: String!, $status: String, $description: String, $deliveryTime: String) { + messagingCreateSMS(messageId: $messageId, providerId: $providerId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$CREATE_PUSH_NOTIFICATION: + return 'mutation createPushNotification($messageId: String!, $providerId: String!, $to: [String!]!, $title: String!, $body: String!, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingCreatePushNotification(messageId: $messageId, providerId: $providerId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; case self::$LIST_MESSAGES: return 'query listMessages { messagingListMessages { @@ -2129,6 +2163,48 @@ trait Base description } }'; + case self::$UPDATE_EMAIL: + return 'mutation updateEmail($messageId: String!, $to: [String!], $subject: String, $content: String, $status: String, $description: String, $html: Boolean, $deliveryTime: String) { + messagingUpdateEmail(messageId: $messageId, to: $to, subject: $subject, content: $content, status: $status, description: $description, html: $html, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$UPDATE_SMS: + return 'mutation updateSMS($messageId: String!, $to: [String!], $content: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdateSMS(messageId: $messageId, to: $to, content: $content, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; + case self::$UPDATE_PUSH_NOTIFICATION: + return 'mutation updatePushNotification($messageId: String!, $to: [String!], $title: String, $body: String, $data: Json, $action: String, $icon: String, $sound: String, $color: String, $tag: String, $badge: String, $status: String, $description: String, $deliveryTime: String) { + messagingUpdatePushNotification(messageId: $messageId, to: $to, title: $title, body: $body, data: $data, action: $action, icon: $icon, sound: $sound, color: $color, tag: $tag, badge: $badge, status: $status, description: $description, deliveryTime: $deliveryTime) { + _id + providerId + to + deliveryTime + deliveredAt + deliveryErrors + deliveredTo + status + description + } + }'; case self::$COMPLEX_QUERY: return 'mutation complex($databaseId: String!, $databaseName: String!, $collectionId: String!, $collectionName: String!, $documentSecurity: Boolean!, $collectionPermissions: [String!]!) { databasesCreate(databaseId: $databaseId, name: $databaseName) { diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 8c3e4970e7..ec8f4b0a6a 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -573,8 +573,8 @@ class MessagingTest extends Scope $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'userId' => ID::custom('test-user'), - 'email' => $to, + 'userId' => ID::unique(), + 'email' => 'random1-mail@mail.org', 'password' => 'password', 'name' => 'Messaging User', ] @@ -658,5 +658,762 @@ class MessagingTest extends Scope $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendEmail + */ + public function testUpdateEmail(array $email) + { + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + $this->markTestSkipped('Email provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MAILGUN_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun2', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'from' => $from, + 'isEuRegion' => $isEuRegion, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMailgunProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random2-mail@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_EMAIL); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ], + ]; + $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $email['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_EMAIL); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingCreateEmail']['_id'], + 'status' => 'processing', + ], + ]; + $email = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $email['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $email['body']['data']['messagingUpdateEmail']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + } + + public function testSendSMS() + { + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-1', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random3-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'content' => '454665', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingCreateSMS']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendSMS + */ + public function testUpdateSMS(array $sms) + { + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_MSG91_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-2', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateMsg91Provider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random4-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'content' => '345463', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_SMS); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingCreateSMS']['_id'], + 'status' => 'processing', + ], + ]; + $sms = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $sms['body']['data']['messagingUpdateSMS']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + } + + public function testSendPushNotification() + { + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_FCM_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'FCM1', + 'serverKey' => $serverKey, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + + $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random5-mail@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'title' => 'Push Notification Title', + 'body' => 'Push Notifiaction Body', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingCreatePushNotification']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); + + return $message['body']['data']['messagingGetMessage']; + } + + /** + * @depends testSendPushNotification + */ + public function testUpdatePushNotification(array $push) + { + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $query = $this->getQuery(self::$CREATE_FCM_PROVIDER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => ID::unique(), + 'name' => 'FCM2', + 'serverKey' => $serverKey, + ], + ]; + $provider = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $provider['headers']['status-code']); + var_dump($provider['body']); + $providerId = $provider['body']['data']['messagingCreateFcmProvider']['_id']; + + $query = $this->getQuery(self::$CREATE_TOPIC); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'providerId' => $providerId, + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Active users', + ], + ]; + $topic = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $topic['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'userId' => ID::unique(), + 'email' => 'random5-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ] + ]; + $user = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $user['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_USER_TARGET); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'targetId' => ID::unique(), + 'userId' => $user['body']['data']['usersCreate']['_id'], + 'providerId' => $providerId, + 'identifier' => $to, + ], + ]; + $target = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $target['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_SUBSCRIBER); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'subscriberId' => ID::unique(), + 'topicId' => $topic['body']['data']['messagingCreateTopic']['_id'], + 'targetId' => $target['body']['data']['usersCreateTarget']['_id'], + ], + ]; + $subscriber = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $graphQLPayload); + + $this->assertEquals(200, $subscriber['headers']['status-code']); + + $query = $this->getQuery(self::$CREATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => ID::unique(), + 'providerId' => $providerId, + 'status' => 'draft', + 'to' => [$topic['body']['data']['messagingCreateTopic']['_id']], + 'title' => 'Push Notification Title', + 'body' => 'Push Notifiaction Body', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + $query = $this->getQuery(self::$UPDATE_PUSH_NOTIFICATION); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingCreatePushNotification']['_id'], + 'status' => 'processing', + ], + ]; + $push = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $query = $this->getQuery(self::$GET_MESSAGE); + $graphQLPayload = [ + 'query' => $query, + 'variables' => [ + 'messageId' => $push['body']['data']['messagingUpdatePushNotification']['_id'], + ], + ]; + $message = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), $graphQLPayload); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['data']['messagingGetMessage']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['data']['messagingGetMessage']['deliveryErrors'])); } } diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index 1c349a2dbe..b4ed8311df 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -416,16 +416,16 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ], [ - 'userId' => ID::custom('test-user'), + 'userId' => ID::unique(), 'email' => $to, 'password' => 'password', 'name' => 'Messaging User', - ], false); + ]); $this->assertEquals(201, $user['headers']['status-code']); // Create Target - $target = $this->client->call(Client::METHOD_POST, '/users/test-user/targets', [ + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], @@ -475,5 +475,597 @@ trait MessagingBase $this->assertEquals(200, $message['headers']['status-code']); $this->assertEquals(1, $message['body']['deliveredTo']); $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendEmail + */ + public function testUpdateEmail(array $email) + { + + $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); + $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); + $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); + $domain = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_DOMAIN'); + $isEuRegion = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_IS_EU_REGION'); + if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) { + $this->markTestSkipped('Email provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/mailgun', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Mailgun-provider-2', + 'apiKey' => $apiKey, + 'domain' => $domain, + 'isEuRegion' => filter_var($isEuRegion, FILTER_VALIDATE_BOOLEAN), + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create Email + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + $email = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $email['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + } + + public function testSendSMS() + { + + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-1', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random1-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create SMS + $sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'to' => [$topic['body']['$id']], + 'content' => '064763', + ]); + + $this->assertEquals(201, $sms['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $sms['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendSMS + */ + public function testUpdateSMS(array $sms) + { + + $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); + $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); + $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); + $authKey = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_AUTH_KEY'); + if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) { + $this->markTestSkipped('SMS provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/msg91', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'Msg91-2', + 'senderId' => $senderId, + 'authKey' => $authKey, + 'from' => $from + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random2-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create SMS + $sms = $this->client->call(Client::METHOD_POST, '/messaging/messages/sms', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'content' => '047487', + ]); + + $this->assertEquals(201, $sms['headers']['status-code']); + + $sms = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/sms/' . $sms['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $sms['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $sms['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + } + + public function testSendPushNotification() + { + + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'FCM-1', + 'serverKey' => $serverKey, + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random3-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create push notification + $push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'to' => [$topic['body']['$id']], + 'title' => 'Test-Notification', + 'body' => 'Test-Notification-Body', + ]); + + $this->assertEquals(201, $push['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $push['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); + + return $message; + } + + /** + * @depends testSendPushNotification + */ + public function testUpdatePushNotification(array $push) + { + + $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); + $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); + if (empty($to) || empty($serverKey)) { + $this->markTestSkipped('Push provider not configured'); + } + + $message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + // Test failure as the message has already been sent. + $this->assertEquals(400, $message['headers']['status-code']); + + // Create provider + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/fcm', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]), [ + 'providerId' => ID::unique(), + 'name' => 'FCM-2', + 'serverKey' => $serverKey, + ]); + $this->assertEquals(201, $provider['headers']['status-code']); + + // Create Topic + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'providerId' => $provider['body']['$id'], + 'topicId' => ID::unique(), + 'name' => 'topic1', + 'description' => 'Test Topic' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + // Create User + $user = $this->client->call(Client::METHOD_POST, '/users', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'userId' => ID::unique(), + 'email' => 'random4-email@mail.org', + 'password' => 'password', + 'name' => 'Messaging User', + ]); + + $this->assertEquals(201, $user['headers']['status-code']); + + // Create Target + $target = $this->client->call(Client::METHOD_POST, '/users/' . $user['body']['$id'] . '/targets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'targetId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'identifier' => $to, + ]); + + $this->assertEquals(201, $target['headers']['status-code']); + + // Create Subscriber + $subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['body']['$id'] . '/subscribers', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subscriberId' => ID::unique(), + 'targetId' => $target['body']['$id'], + ]); + + $this->assertEquals(201, $subscriber['headers']['status-code']); + + // Create push notification + $push = $this->client->call(Client::METHOD_POST, '/messaging/messages/push', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'messageId' => ID::unique(), + 'providerId' => $provider['body']['$id'], + 'status' => 'draft', + 'to' => [$topic['body']['$id']], + 'title' => 'Test-Notification', + 'body' => 'Test-Notification-Body', + ]); + + $this->assertEquals(201, $push['headers']['status-code']); + + $push = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/push/' . $push['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'status' => 'processing', + ]); + + $this->assertEquals(200, $push['headers']['status-code']); + + \sleep(5); + + $message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $push['body']['$id'], [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $message['headers']['status-code']); + $this->assertEquals(1, $message['body']['deliveredTo']); + $this->assertEquals(0, \count($message['body']['deliveryErrors'])); } } From db9e7b0199b39f27dfb009446a9c79cf86986ab7 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:28:23 +0530 Subject: [PATCH 2/5] review changes --- app/config/errors.php | 5 +++ app/controllers/api/messaging.php | 65 +++++++++++++++++++++---------- src/Appwrite/Extend/Exception.php | 1 + 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 5514e8e68e..07741eddac 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -790,5 +790,10 @@ return [ 'name' => Exception::MESSAGE_ALREADY_SENT, 'description' => 'Message with the requested ID has already been sent.', 'code' => 400, + ], + Exception::MESSAGE_ALREADY_SCHEDULED => [ + 'name' => Exception::MESSAGE_ALREADY_SCHEDULED, + 'description' => 'Message with the requested ID has already been scheduled for delivery.', + 'code' => 400, ] ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8735cf57de..ae048020ac 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1580,8 +1580,8 @@ App::post('/v1/messaging/messages/email') ->param('providerId', '', new UID(), 'Email Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') ->param('subject', '', new Text(998), 'Email Subject.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'Email Content.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('html', false, new Boolean(), 'Is content of type HTML', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) @@ -1589,15 +1589,19 @@ App::post('/v1/messaging/messages/email') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $subject, string $description, string $content, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $subject, string $content, string $description, string $status, bool $html, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'email') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'email') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerId' => $provider->getId(), @@ -1633,7 +1637,7 @@ App::post('/v1/messaging/messages/email') }); App::post('/v1/messaging/messages/sms') - ->desc('Create an sms.') + ->desc('Create an SMS.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.create') ->label('audits.resource', 'messages/{response.$id}') @@ -1648,23 +1652,27 @@ App::post('/v1/messaging/messages/sms') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new UID(), 'SMS Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('content', '', new Text(64230), 'SMS Content.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $description, string $content, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $content, string $description, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'sms') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'sms') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $message = $dbForProject->createDocument('messages', new Document([ '$id' => $messageId, 'providerId' => $provider->getId(), @@ -1713,31 +1721,35 @@ App::post('/v1/messaging/messages/push') ->param('messageId', '', new CustomId(), 'Message ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.') ->param('providerId', '', new UID(), 'Push Provider ID.') ->param('to', [], new ArrayList(new Text(Database::LENGTH_KEY)), 'List of Topic IDs or List of User IDs or List of Target IDs.') - ->param('description', '', new Text(256), 'Description for Message.', true) ->param('title', '', new Text(256), 'Title for push notification.') ->param('body', '', new Text(64230), 'Body for push notification.') + ->param('description', '', new Text(256), 'Description for Message.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) - ->param('icon', '', new Text(256), 'Icon for push notification.', true) - ->param('sound', '', new Text(256), 'Sound for push notification.', true) - ->param('color', '', new Text(256), 'Color for push notification.', true) - ->param('tag', '', new Text(256), 'Tag for push notification.', true) - ->param('badge', '', new Text(256), 'Badge for push notification.', true) + ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) + ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) + ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) + ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) + ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') ->inject('messaging') ->inject('response') - ->action(function (string $messageId, string $providerId, array $to, string $description, string $title, string $body, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { + ->action(function (string $messageId, string $providerId, array $to, string $title, string $body, string $description, ?array $data, string $action, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $deliveryTime, Database $dbForProject, Document $project, Messaging $messaging, Response $response) { $messageId = $messageId == 'unique()' ? ID::unique() : $messageId; $provider = $dbForProject->getDocument('providers', $providerId); - if ($provider->isEmpty() || $provider->getAttribute('type') !== 'push') { + if ($provider->isEmpty()) { throw new Exception(Exception::PROVIDER_NOT_FOUND); } + if ($provider->getAttribute('type') !== 'push') { + throw new Exception(Exception::PROVIDER_INCORRECT_TYPE); + } + $pushData = [ 'title' => $title, 'body' => $body, @@ -1900,6 +1912,10 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } @@ -1983,6 +1999,10 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } @@ -2044,12 +2064,11 @@ App::patch('/v1/messaging/messages/push/:messageId') ->param('body', '', new Text(64230), 'Body for push notification.', true) ->param('data', null, new JSON(), 'Additional Data for push notification.', true) ->param('action', '', new Text(256), 'Action for push notification.', true) - ->param('icon', '', new Text(256), 'Icon for push notification.', true) - ->param('sound', '', new Text(256), 'Sound for push notification.', true) - ->param('color', '', new Text(256), 'Color for push notification.', true) - ->param('tag', '', new Text(256), 'Tag for push notification.', true) - ->param('badge', '', new Text(256), 'Badge for push notification.', true) - ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) + ->param('icon', '', new Text(256), 'Icon for push notification. Available only for Android and Web Platform.', true) + ->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true) + ->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true) + ->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true) + ->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true) ->param('deliveryTime', null, new DatetimeValidator(requireDateInFuture: true), 'Delivery time for message in ISO 8601 format. DateTime value must be in future.', true) ->inject('dbForProject') ->inject('project') @@ -2066,6 +2085,10 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } + if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); + } + if (\count($to) > 0) { $message->setAttribute('to', $to); } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index ee17ccef0c..6650accb9d 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -241,6 +241,7 @@ class Exception extends \Exception /** Message */ public const MESSAGE_NOT_FOUND = 'message_not_found'; public const MESSAGE_ALREADY_SENT = 'message_already_sent'; + public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled'; protected $type = ''; protected $errors = []; From e4d2d15f7047d7e1700f6825e6512f39738a32aa Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:31:56 +0530 Subject: [PATCH 3/5] review changes --- app/controllers/api/messaging.php | 13 +++++++++++++ tests/e2e/Services/Messaging/MessagingBase.php | 6 ------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index ae048020ac..8e79912566 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1679,6 +1679,7 @@ App::post('/v1/messaging/messages/sms') 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, + 'deliveryTime' => $deliveryTime, 'data' => [ 'content' => $content, ], @@ -1789,6 +1790,7 @@ App::post('/v1/messaging/messages/push') 'providerInternalId' => $provider->getInternalId(), 'to' => $to, 'description' => $description, + 'deliveryTime' => $deliveryTime, 'data' => $pushData, 'status' => $status, 'search' => $messageId . ' ' . $description . ' ' . $title . ' ' . $providerId, @@ -1945,6 +1947,10 @@ App::patch('/v1/messaging/messages/email/:messageId') $message->setAttribute('status', $status); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2024,6 +2030,10 @@ App::patch('/v1/messaging/messages/sms/:messageId') $message->setAttribute('description', $description); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } + $message = $dbForProject->updateDocument('messages', $message->getId(), $message); if ($status === 'processing') { @@ -2142,6 +2152,9 @@ App::patch('/v1/messaging/messages/push/:messageId') $message->setAttribute('description', $description); } + if (!is_null($deliveryTime)) { + $message->setAttribute('deliveryTime', $deliveryTime); + } $message = $dbForProject->updateDocument('messages', $message->getId(), $message); diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index b4ed8311df..5b374e97b1 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -372,7 +372,6 @@ trait MessagingBase public function testSendEmail() { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); @@ -484,7 +483,6 @@ trait MessagingBase */ public function testUpdateEmail(array $email) { - $to = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_RECEIVER_EMAIL'); $from = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_FROM'); $apiKey = App::getEnv('_APP_MESSAGE_EMAIL_PROVIDER_MAILGUN_API_KEY'); @@ -611,7 +609,6 @@ trait MessagingBase public function testSendSMS() { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); @@ -720,7 +717,6 @@ trait MessagingBase */ public function testUpdateSMS(array $sms) { - $to = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_TO'); $from = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_FROM'); $senderId = App::getEnv('_APP_MESSAGE_SMS_PROVIDER_MSG91_SENDER_ID'); @@ -844,7 +840,6 @@ trait MessagingBase public function testSendPushNotification() { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); if (empty($to) || empty($serverKey)) { @@ -950,7 +945,6 @@ trait MessagingBase */ public function testUpdatePushNotification(array $push) { - $to = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_RECEIVER_TOKEN'); $serverKey = App::getEnv('_APP_MESSAGE_PUSH_PROVIDER_FCM_SERVERY_KEY'); if (empty($to) || empty($serverKey)) { From 24b2d7044178ba085d511ebbcf45c39b2ccf9215 Mon Sep 17 00:00:00 2001 From: prateek banga Date: Fri, 20 Oct 2023 13:33:27 +0530 Subject: [PATCH 4/5] review changes --- app/controllers/api/messaging.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 8e79912566..58490baef7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1972,7 +1972,7 @@ App::patch('/v1/messaging/messages/email/:messageId') }); App::patch('/v1/messaging/messages/sms/:messageId') - ->desc('Update an sms.') + ->desc('Update an SMS.') ->groups(['api', 'messaging']) ->label('audits.event', 'messages.update') ->label('audits.resource', 'messages/{response.$id}') From d714760eb807c15ee64a8e284a63964b8abb2e7e Mon Sep 17 00:00:00 2001 From: Prateek Banga Date: Fri, 20 Oct 2023 13:51:13 +0530 Subject: [PATCH 5/5] review changeS --- app/controllers/api/messaging.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 58490baef7..2f2deabdd7 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1914,7 +1914,7 @@ App::patch('/v1/messaging/messages/email/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2005,7 +2005,7 @@ App::patch('/v1/messaging/messages/sms/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); } @@ -2095,7 +2095,7 @@ App::patch('/v1/messaging/messages/push/:messageId') throw new Exception(Exception::MESSAGE_ALREADY_SENT); } - if (!is_null($message->getAttribute('deliveryTime')) && is_null($deliveryTime) && $message->getAttribute('deliveryTime') < new \DateTime()) { + if (!is_null($message->getAttribute('deliveryTime')) && $message->getAttribute('deliveryTime') < new \DateTime()) { throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED); }