feat: add messaging resource migration support

This commit is contained in:
Prem Palanisamy
2026-03-10 09:20:57 +00:00
parent 94c6f6e07d
commit ee2e41fa45
5 changed files with 947 additions and 76 deletions
+1 -1
View File
@@ -70,7 +70,7 @@
"utopia-php/locale": "0.8.*",
"utopia-php/logger": "0.6.*",
"utopia-php/messaging": "0.20.*",
"utopia-php/migration": "1.6.*",
"utopia-php/migration": "1.7.*",
"utopia-php/platform": "0.7.*",
"utopia-php/pools": "1.*",
"utopia-php/span": "1.1.*",
Generated
+74 -75
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1cc64e07484256225f56bd525674c3b8",
"content-hash": "b99693284208ff3d006260a089a4f7b9",
"packages": [
{
"name": "adhocore/jwt",
@@ -4058,16 +4058,16 @@
},
{
"name": "utopia-php/domains",
"version": "1.0.5",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/domains.git",
"reference": "0edf6bb2b07f30db849a267027077bf5abb994c6"
"reference": "b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/0edf6bb2b07f30db849a267027077bf5abb994c6",
"reference": "0edf6bb2b07f30db849a267027077bf5abb994c6",
"url": "https://api.github.com/repos/utopia-php/domains/zipball/b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6",
"reference": "b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6",
"shasum": ""
},
"require": {
@@ -4114,9 +4114,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/domains/issues",
"source": "https://github.com/utopia-php/domains/tree/1.0.5"
"source": "https://github.com/utopia-php/domains/tree/1.0.2"
},
"time": "2026-03-03T09:20:50+00:00"
"time": "2026-02-25T08:18:25+00:00"
},
{
"name": "utopia-php/dsn",
@@ -4517,16 +4517,16 @@
},
{
"name": "utopia-php/migration",
"version": "1.6.3",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "c2d016944cb029fa5ff822ceee704785a06ef289"
"reference": "97583ae502e40621ea91a71de19d053c5ae2e558"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/c2d016944cb029fa5ff822ceee704785a06ef289",
"reference": "c2d016944cb029fa5ff822ceee704785a06ef289",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/97583ae502e40621ea91a71de19d053c5ae2e558",
"reference": "97583ae502e40621ea91a71de19d053c5ae2e558",
"shasum": ""
},
"require": {
@@ -4566,9 +4566,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/1.6.3"
"source": "https://github.com/utopia-php/migration/tree/1.7.0"
},
"time": "2026-03-04T07:08:22+00:00"
"time": "2026-03-10T06:36:27+00:00"
},
{
"name": "utopia-php/mongo",
@@ -5215,16 +5215,16 @@
},
{
"name": "utopia-php/vcs",
"version": "2.0.1",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "92a1650824ba0c5e6a1bc46e622ac87c50a08920"
"reference": "058049326e04a2a0c2f0ce8ad00c7e84825aba14"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/92a1650824ba0c5e6a1bc46e622ac87c50a08920",
"reference": "92a1650824ba0c5e6a1bc46e622ac87c50a08920",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/058049326e04a2a0c2f0ce8ad00c7e84825aba14",
"reference": "058049326e04a2a0c2f0ce8ad00c7e84825aba14",
"shasum": ""
},
"require": {
@@ -5258,9 +5258,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/2.0.1"
"source": "https://github.com/utopia-php/vcs/tree/2.0.0"
},
"time": "2026-02-27T12:18:49+00:00"
"time": "2026-02-25T11:36:45+00:00"
},
{
"name": "utopia-php/websocket",
@@ -5438,16 +5438,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "1.11.6",
"version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "f80e302d000cdc2f98b4bb5ff2fc3bd0bdff7b38"
"reference": "6ff411f26f2750eea05c7598c14bb3a2ada898cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/f80e302d000cdc2f98b4bb5ff2fc3bd0bdff7b38",
"reference": "f80e302d000cdc2f98b4bb5ff2fc3bd0bdff7b38",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/6ff411f26f2750eea05c7598c14bb3a2ada898cb",
"reference": "6ff411f26f2750eea05c7598c14bb3a2ada898cb",
"shasum": ""
},
"require": {
@@ -5483,22 +5483,22 @@
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
"support": {
"issues": "https://github.com/appwrite/sdk-generator/issues",
"source": "https://github.com/appwrite/sdk-generator/tree/1.11.6"
"source": "https://github.com/appwrite/sdk-generator/tree/1.11.1"
},
"time": "2026-03-09T07:12:51+00:00"
"time": "2026-02-25T07:15:19+00:00"
},
{
"name": "brianium/paratest",
"version": "v7.19.1",
"version": "v7.19.0",
"source": {
"type": "git",
"url": "https://github.com/paratestphp/paratest.git",
"reference": "95b03194f4cdf5c83175ceead673e21cb66465e7"
"reference": "7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/95b03194f4cdf5c83175ceead673e21cb66465e7",
"reference": "95b03194f4cdf5c83175ceead673e21cb66465e7",
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6",
"reference": "7c6c29af7c4b406b49ce0c6b0a3a81d3684474e6",
"shasum": ""
},
"require": {
@@ -5512,7 +5512,7 @@
"phpunit/php-code-coverage": "^12.5.3 || ^13.0.1",
"phpunit/php-file-iterator": "^6.0.1 || ^7",
"phpunit/php-timer": "^8 || ^9",
"phpunit/phpunit": "^12.5.14 || ^13.0.5",
"phpunit/phpunit": "^12.5.9 || ^13",
"sebastian/environment": "^8.0.3 || ^9",
"symfony/console": "^7.4.4 || ^8.0.4",
"symfony/process": "^7.4.5 || ^8.0.5"
@@ -5522,10 +5522,10 @@
"ext-pcntl": "*",
"ext-pcov": "*",
"ext-posix": "*",
"phpstan/phpstan": "^2.1.40",
"phpstan/phpstan-deprecation-rules": "^2.0.4",
"phpstan/phpstan-phpunit": "^2.0.16",
"phpstan/phpstan-strict-rules": "^2.0.10",
"phpstan/phpstan": "^2.1.38",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.12",
"phpstan/phpstan-strict-rules": "^2.0.8",
"symfony/filesystem": "^7.4.0 || ^8.0.1"
},
"bin": [
@@ -5566,7 +5566,7 @@
],
"support": {
"issues": "https://github.com/paratestphp/paratest/issues",
"source": "https://github.com/paratestphp/paratest/tree/v7.19.1"
"source": "https://github.com/paratestphp/paratest/tree/v7.19.0"
},
"funding": [
{
@@ -5578,7 +5578,7 @@
"type": "paypal"
}
],
"time": "2026-02-25T14:53:45+00:00"
"time": "2026-02-06T10:53:26+00:00"
},
{
"name": "czproject/git-php",
@@ -6398,16 +6398,16 @@
},
{
"name": "phpbench/phpbench",
"version": "1.5.1",
"version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
"reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c"
"reference": "b641dde59d969ea42eed70a39f9b51950bc96878"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpbench/phpbench/zipball/9a28fd0833f11171b949843c6fd663eb69b6d14c",
"reference": "9a28fd0833f11171b949843c6fd663eb69b6d14c",
"url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878",
"reference": "b641dde59d969ea42eed70a39f9b51950bc96878",
"shasum": ""
},
"require": {
@@ -6418,7 +6418,7 @@
"ext-reflection": "*",
"ext-spl": "*",
"ext-tokenizer": "*",
"php": "^8.2",
"php": "^8.1",
"phpbench/container": "^2.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
@@ -6438,9 +6438,8 @@
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^11.5",
"phpunit/phpunit": "^10.4 || ^11.0",
"rector/rector": "^1.2",
"sebastian/exporter": "^6.3.2",
"symfony/error-handler": "^6.1 || ^7.0 || ^8.0",
"symfony/var-dumper": "^6.1 || ^7.0 || ^8.0"
},
@@ -6485,7 +6484,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
"source": "https://github.com/phpbench/phpbench/tree/1.5.1"
"source": "https://github.com/phpbench/phpbench/tree/1.4.3"
},
"funding": [
{
@@ -6493,15 +6492,15 @@
"type": "github"
}
],
"time": "2026-03-05T08:18:58+00:00"
"time": "2025-11-06T19:07:31+00:00"
},
{
"name": "phpstan/phpstan",
"version": "1.12.33",
"version": "1.12.32",
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1",
"reference": "37982d6fc7cbb746dda7773530cda557cdf119e1",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
"reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
"shasum": ""
},
"require": {
@@ -6546,7 +6545,7 @@
"type": "github"
}
],
"time": "2026-02-28T20:30:03+00:00"
"time": "2025-09-30T10:16:31+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -8096,16 +8095,16 @@
},
{
"name": "symfony/console",
"version": "v8.0.7",
"version": "v8.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a"
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
"url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b",
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b",
"shasum": ""
},
"require": {
@@ -8162,7 +8161,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v8.0.7"
"source": "https://github.com/symfony/console/tree/v8.0.4"
},
"funding": [
{
@@ -8182,20 +8181,20 @@
"type": "tidelift"
}
],
"time": "2026-03-06T14:06:22+00:00"
"time": "2026-01-13T13:06:50+00:00"
},
{
"name": "symfony/filesystem",
"version": "v8.0.6",
"version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770"
"reference": "d937d400b980523dc9ee946bb69972b5e619058d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770",
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
"reference": "d937d400b980523dc9ee946bb69972b5e619058d",
"shasum": ""
},
"require": {
@@ -8232,7 +8231,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v8.0.6"
"source": "https://github.com/symfony/filesystem/tree/v8.0.1"
},
"funding": [
{
@@ -8252,20 +8251,20 @@
"type": "tidelift"
}
],
"time": "2026-02-25T16:59:43+00:00"
"time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/finder",
"version": "v8.0.6",
"version": "v8.0.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c"
"reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/441404f09a54de6d1bd6ad219e088cdf4c91f97c",
"reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c",
"url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0",
"reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0",
"shasum": ""
},
"require": {
@@ -8300,7 +8299,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v8.0.6"
"source": "https://github.com/symfony/finder/tree/v8.0.5"
},
"funding": [
{
@@ -8320,7 +8319,7 @@
"type": "tidelift"
}
],
"time": "2026-01-29T09:41:02+00:00"
"time": "2026-01-26T15:08:38+00:00"
},
{
"name": "symfony/options-resolver",
@@ -8790,16 +8789,16 @@
},
{
"name": "symfony/string",
"version": "v8.0.6",
"version": "v8.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4"
"reference": "758b372d6882506821ed666032e43020c4f57194"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
"url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194",
"reference": "758b372d6882506821ed666032e43020c4f57194",
"shasum": ""
},
"require": {
@@ -8856,7 +8855,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v8.0.6"
"source": "https://github.com/symfony/string/tree/v8.0.4"
},
"funding": [
{
@@ -8876,7 +8875,7 @@
"type": "tidelift"
}
],
"time": "2026-02-09T10:14:57+00:00"
"time": "2026-01-12T12:37:40+00:00"
},
{
"name": "textalk/websocket",
@@ -9108,7 +9107,7 @@
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
@@ -9132,5 +9131,5 @@
"platform-overrides": {
"php": "8.3"
},
"plugin-api-version": "2.9.0"
"plugin-api-version": "2.6.0"
}
@@ -317,6 +317,16 @@ class Migrations extends Action
'sites.write',
'tokens.read',
'tokens.write',
'providers.read',
'providers.write',
'topics.read',
'topics.write',
'subscribers.read',
'subscribers.write',
'messages.read',
'messages.write',
'targets.read',
'targets.write',
]
]);
@@ -59,6 +59,30 @@ class MigrationReport extends Model
'default' => 0,
'example' => 5,
])
->addRule(Resource::TYPE_PROVIDER, [
'type' => self::TYPE_INTEGER,
'description' => 'Number of providers to be migrated.',
'default' => 0,
'example' => 5,
])
->addRule(Resource::TYPE_TOPIC, [
'type' => self::TYPE_INTEGER,
'description' => 'Number of topics to be migrated.',
'default' => 0,
'example' => 10,
])
->addRule(Resource::TYPE_SUBSCRIBER, [
'type' => self::TYPE_INTEGER,
'description' => 'Number of subscribers to be migrated.',
'default' => 0,
'example' => 100,
])
->addRule(Resource::TYPE_MESSAGE, [
'type' => self::TYPE_INTEGER,
'description' => 'Number of messages to be migrated.',
'default' => 0,
'example' => 50,
])
->addRule('size', [
'type' => self::TYPE_INTEGER,
'description' => 'Size of files to be migrated in mb.',
@@ -1694,4 +1694,842 @@ trait MigrationsBase
'x-appwrite-key' => $this->getProject()['apiKey']
]);
}
/**
* Messaging
*/
public function testAppwriteMigrationMessagingProvider(): void
{
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Sendgrid',
'apiKey' => 'my-apikey',
'from' => 'migration@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$this->assertNotEmpty($provider['body']['$id']);
$providerId = $provider['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_PROVIDER,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertEquals([Resource::TYPE_PROVIDER], $result['resources']);
$this->assertArrayHasKey(Resource::TYPE_PROVIDER, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['pending']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_PROVIDER]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['warning']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($providerId, $response['body']['$id']);
$this->assertEquals('Migration Sendgrid', $response['body']['name']);
$this->assertEquals('email', $response['body']['type']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingProviderSMTP(): void
{
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/smtp', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration SMTP',
'host' => 'smtp.test.com',
'port' => 587,
'from' => 'migration-smtp@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_PROVIDER,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_PROVIDER, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['error']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_PROVIDER]['success']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($providerId, $response['body']['$id']);
$this->assertEquals('Migration SMTP', $response['body']['name']);
$this->assertEquals('email', $response['body']['type']);
$this->assertEquals('smtp', $response['body']['provider']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingProviderTwilio(): void
{
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/twilio', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Twilio',
'from' => '+15551234567',
'accountSid' => 'test-account-sid',
'authToken' => 'test-auth-token',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_PROVIDER,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_PROVIDER, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_PROVIDER]['error']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_PROVIDER]['success']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($providerId, $response['body']['$id']);
$this->assertEquals('Migration Twilio', $response['body']['name']);
$this->assertEquals('sms', $response['body']['type']);
$this->assertEquals('twilio', $response['body']['provider']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingTopic(): void
{
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Sendgrid Topic',
'apiKey' => 'my-apikey',
'from' => 'migration-topic@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$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'],
], [
'topicId' => ID::unique(),
'name' => 'Migration Topic',
]);
$this->assertEquals(201, $topic['headers']['status-code']);
$this->assertNotEmpty($topic['body']['$id']);
$topicId = $topic['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_PROVIDER,
Resource::TYPE_TOPIC,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_TOPIC, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TOPIC]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TOPIC]['pending']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_TOPIC]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TOPIC]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_TOPIC]['warning']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($topicId, $response['body']['$id']);
$this->assertEquals('Migration Topic', $response['body']['name']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingSubscriber(): void
{
$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' => uniqid() . '-migration-sub@test.com',
'password' => 'password',
]);
$this->assertEquals(201, $user['headers']['status-code']);
$userId = $user['body']['$id'];
$this->assertEquals(1, \count($user['body']['targets']));
$targetId = $user['body']['targets'][0]['$id'];
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Sendgrid Subscriber',
'apiKey' => 'my-apikey',
'from' => uniqid() . '-migration-sub@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$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'],
], [
'topicId' => ID::unique(),
'name' => 'Migration Subscriber Topic',
]);
$this->assertEquals(201, $topic['headers']['status-code']);
$topicId = $topic['body']['$id'];
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topicId . '/subscribers', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'subscriberId' => ID::unique(),
'targetId' => $targetId,
]);
$this->assertEquals(201, $subscriber['headers']['status-code']);
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_USER,
Resource::TYPE_PROVIDER,
Resource::TYPE_TOPIC,
Resource::TYPE_SUBSCRIBER,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_SUBSCRIBER, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_SUBSCRIBER]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_SUBSCRIBER]['pending']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_SUBSCRIBER]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_SUBSCRIBER]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_SUBSCRIBER]['warning']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($topicId, $response['body']['$id']);
$this->assertGreaterThanOrEqual(1, $response['body']['emailTotal']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingMessage(): void
{
$this->getDestinationProject(true);
$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' => uniqid() . '-migration-msg@test.com',
'password' => 'password',
]);
$this->assertEquals(201, $user['headers']['status-code']);
$userId = $user['body']['$id'];
$this->assertEquals(1, \count($user['body']['targets']));
$targetId = $user['body']['targets'][0]['$id'];
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Sendgrid Message',
'apiKey' => 'my-apikey',
'from' => 'migration-msg@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$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'],
], [
'topicId' => ID::unique(),
'name' => 'Migration Message Topic',
]);
$this->assertEquals(201, $topic['headers']['status-code']);
$topicId = $topic['body']['$id'];
$message = $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(),
'targets' => [$targetId],
'topics' => [$topicId],
'subject' => 'Migration Test Email',
'content' => 'This is a migration test email',
'draft' => true,
]);
$this->assertEquals(201, $message['headers']['status-code']);
$this->assertNotEmpty($message['body']['$id']);
$messageId = $message['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_USER,
Resource::TYPE_PROVIDER,
Resource::TYPE_TOPIC,
Resource::TYPE_SUBSCRIBER,
Resource::TYPE_MESSAGE,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_MESSAGE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['error']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['pending']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_MESSAGE]['success']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['processing']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['warning']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($messageId, $response['body']['$id']);
$this->assertEquals('draft', $response['body']['status']);
$this->assertEquals('Migration Test Email', $response['body']['data']['subject']);
$this->assertEquals('This is a migration test email', $response['body']['data']['content']);
$this->assertContains($topicId, $response['body']['topics']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingSmsMessage(): void
{
$this->getDestinationProject(true);
$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' => uniqid() . '-migration-sms@test.com',
'phone' => '+1' . str_pad((string) rand(200000000, 999999999), 10, '0', STR_PAD_LEFT),
'password' => 'password',
]);
$this->assertEquals(201, $user['headers']['status-code']);
$userId = $user['body']['$id'];
$this->assertGreaterThanOrEqual(1, \count($user['body']['targets']));
$smsTarget = null;
foreach ($user['body']['targets'] as $target) {
if ($target['providerType'] === 'sms') {
$smsTarget = $target;
break;
}
}
$this->assertNotNull($smsTarget);
$targetId = $smsTarget['$id'];
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/twilio', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Twilio SMS Msg',
'from' => '+15559876543',
'accountSid' => 'test-account-sid',
'authToken' => 'test-auth-token',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$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'],
], [
'topicId' => ID::unique(),
'name' => 'Migration SMS Topic',
]);
$this->assertEquals(201, $topic['headers']['status-code']);
$topicId = $topic['body']['$id'];
$message = $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(),
'targets' => [$targetId],
'topics' => [$topicId],
'content' => 'Migration SMS test content',
'draft' => true,
]);
$this->assertEquals(201, $message['headers']['status-code']);
$messageId = $message['body']['$id'];
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_USER,
Resource::TYPE_PROVIDER,
Resource::TYPE_TOPIC,
Resource::TYPE_SUBSCRIBER,
Resource::TYPE_MESSAGE,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_MESSAGE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['error']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_MESSAGE]['success']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($messageId, $response['body']['$id']);
$this->assertEquals('draft', $response['body']['status']);
$this->assertEquals('Migration SMS test content', $response['body']['data']['content']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
public function testAppwriteMigrationMessagingScheduledMessage(): void
{
$this->getDestinationProject(true);
$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' => uniqid() . '-migration-sched@test.com',
'password' => 'password',
]);
$this->assertEquals(201, $user['headers']['status-code']);
$userId = $user['body']['$id'];
$targetId = $user['body']['targets'][0]['$id'];
$provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'providerId' => ID::unique(),
'name' => 'Migration Sendgrid Scheduled',
'apiKey' => 'my-apikey',
'from' => 'migration-sched@test.com',
]);
$this->assertEquals(201, $provider['headers']['status-code']);
$providerId = $provider['body']['$id'];
$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'],
], [
'topicId' => ID::unique(),
'name' => 'Migration Scheduled Topic',
]);
$this->assertEquals(201, $topic['headers']['status-code']);
$topicId = $topic['body']['$id'];
$subscriber = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topicId . '/subscribers', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'subscriberId' => ID::unique(),
'targetId' => $targetId,
]);
$this->assertEquals(201, $subscriber['headers']['status-code']);
// Create a scheduled message with a future date using topics only
// Direct targets use source IDs which won't resolve in the destination via API
$futureDate = (new \DateTime('+1 year'))->format(\DateTime::ATOM);
$message = $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(),
'topics' => [$topicId],
'subject' => 'Migration Scheduled Email',
'content' => 'This is a scheduled migration test email',
'scheduledAt' => $futureDate,
]);
$this->assertEquals(201, $message['headers']['status-code']);
$messageId = $message['body']['$id'];
$this->assertEquals('scheduled', $message['body']['status']);
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_USER,
Resource::TYPE_PROVIDER,
Resource::TYPE_TOPIC,
Resource::TYPE_SUBSCRIBER,
Resource::TYPE_MESSAGE,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertArrayHasKey(Resource::TYPE_MESSAGE, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][Resource::TYPE_MESSAGE]['error']);
$this->assertGreaterThanOrEqual(1, $result['statusCounters'][Resource::TYPE_MESSAGE]['success']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals($messageId, $response['body']['$id']);
$this->assertEquals('scheduled', $response['body']['status']);
$this->assertEquals('Migration Scheduled Email', $response['body']['data']['subject']);
$this->assertEquals(
(new \DateTime($futureDate))->getTimestamp(),
(new \DateTime($response['body']['scheduledAt']))->getTimestamp(),
);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/messages/' . $messageId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/topics/' . $topicId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/messaging/providers/' . $providerId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/users/' . $userId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
}