mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge remote-tracking branch 'origin/1.8.x' into feat-txn
# Conflicts: # app/config/errors.php # app/config/roles.php # app/controllers/api/databases.php # composer.json # composer.lock # src/Appwrite/Extend/Exception.php # src/Appwrite/Utopia/Response.php # tests/e2e/Services/Databases/Legacy/DatabasesBase.php
This commit is contained in:
+112
-10
@@ -26,9 +26,9 @@ class AbuseTest extends Scope
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseCreateDocument()
|
||||
public function testAbuseCreateDocumentCollectionsAPI()
|
||||
{
|
||||
$data = $this->createCollection();
|
||||
$data = $this->createCollectionOrTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 120;
|
||||
@@ -52,9 +52,9 @@ class AbuseTest extends Scope
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseUpdateDocument()
|
||||
public function testAbuseUpdateDocumentCollectionsAPI()
|
||||
{
|
||||
$data = $this->createCollection();
|
||||
$data = $this->createCollectionOrTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 120;
|
||||
@@ -90,9 +90,9 @@ class AbuseTest extends Scope
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseDeleteDocument()
|
||||
public function testAbuseDeleteDocumentCollectionsAPI()
|
||||
{
|
||||
$data = $this->createCollection();
|
||||
$data = $this->createCollectionOrTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 60;
|
||||
@@ -124,6 +124,104 @@ class AbuseTest extends Scope
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseCreateDocumentTablesAPI()
|
||||
{
|
||||
$data = $this->createCollectionOrTable(false);
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 120;
|
||||
|
||||
for ($i = 0; $i <= $max + 1; $i++) {
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/tables/' . $collectionId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'The Hulk ' . $i,
|
||||
],
|
||||
]);
|
||||
|
||||
if ($i < $max) {
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
} else {
|
||||
$this->assertEquals(429, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseUpdateDocumentTablesAPI()
|
||||
{
|
||||
$data = $this->createCollectionOrTable(false);
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 120;
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/tables/' . $collectionId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'The Hulk',
|
||||
],
|
||||
]);
|
||||
|
||||
$rowId = $row['body']['$id'];
|
||||
|
||||
for ($i = 0; $i <= $max + 1; $i++) {
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/tables/' . $collectionId . '/rows/' . $rowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'The Hulk ' . $i,
|
||||
],
|
||||
]);
|
||||
|
||||
if ($i < $max) {
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
} else {
|
||||
$this->assertEquals(429, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseDeleteDocumentTablesAPI()
|
||||
{
|
||||
$data = $this->createCollectionOrTable(false);
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
$max = 60;
|
||||
|
||||
for ($i = 0; $i <= $max + 1; $i++) {
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/tables/' . $collectionId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'The Hulk',
|
||||
],
|
||||
]);
|
||||
|
||||
$documentId = $document['body']['$id'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/tables/' . $collectionId . '/rows/' . $documentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
if ($i < $max) {
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
} else {
|
||||
$this->assertEquals(429, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testAbuseCreateFile()
|
||||
{
|
||||
$data = $this->createBucket();
|
||||
@@ -211,7 +309,7 @@ class AbuseTest extends Scope
|
||||
}
|
||||
}
|
||||
|
||||
private function createCollection(): array
|
||||
private function createCollectionOrTable(bool $isCollection = true): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -227,12 +325,16 @@ class AbuseTest extends Scope
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [
|
||||
$endpoint = $isCollection ? 'collections' : 'tables';
|
||||
$idParam = $isCollection ? 'collectionId' : 'tableId';
|
||||
$attributePath = $isCollection ? 'attributes' : 'columns';
|
||||
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . "/$endpoint", [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'collectionId' => ID::unique(),
|
||||
$idParam => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
@@ -244,7 +346,7 @@ class AbuseTest extends Scope
|
||||
|
||||
$collectionId = $movies['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . "/$endpoint/" . $collectionId . "/$attributePath/string", [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
|
||||
@@ -60,7 +60,7 @@ class HTTPTest extends Scope
|
||||
'origin' => 'http://localhost',
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(200, $response['headers']['status-code'], "Simple GET /robots.txt HTTP request failed: " . \json_encode($response));
|
||||
$this->assertStringContainsString('# robotstxt.org/', $response['body']);
|
||||
}
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@ class UsageTest extends Scope
|
||||
}
|
||||
|
||||
/** @depends testStorageStats */
|
||||
public function testPrepareDatabaseStats(array $data): array
|
||||
public function testPrepareDatabaseStatsCollectionsAPI(array $data): array
|
||||
{
|
||||
$requestsTotal = $data['requestsTotal'];
|
||||
|
||||
@@ -583,9 +583,8 @@ class UsageTest extends Scope
|
||||
]);
|
||||
}
|
||||
|
||||
/** @depends testPrepareDatabaseStats */
|
||||
|
||||
public function testDatabaseStats(array $data): array
|
||||
/** @depends testPrepareDatabaseStatsCollectionsAPI */
|
||||
public function testDatabaseStatsCollectionsAPI(array $data): array
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
@@ -658,7 +657,258 @@ class UsageTest extends Scope
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @depends testDatabaseStats */
|
||||
/** @depends testDatabaseStatsCollectionsAPI */
|
||||
public function testPrepareDatabaseStatsTablesAPI(array $data): array
|
||||
{
|
||||
$rowsTotal = 0;
|
||||
$tablesTotal = 0;
|
||||
$databasesTotal = $data['databasesTotal'];
|
||||
$documentsTotal = $data['documentsTotal'];
|
||||
$collectionsTotal = $data['collectionsTotal'];
|
||||
|
||||
$requestsTotal = $data['requestsTotal'];
|
||||
|
||||
for ($i = 0; $i < self::CREATE; $i++) {
|
||||
$name = uniqid() . ' database';
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/databases',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'databaseId' => 'unique()',
|
||||
'name' => $name,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals($name, $response['body']['name']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$requestsTotal += 1;
|
||||
$databasesTotal += 1;
|
||||
|
||||
$databaseId = $response['body']['$id'];
|
||||
|
||||
if ($i < (self::CREATE / 2)) {
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/databases/' . $databaseId,
|
||||
array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
);
|
||||
|
||||
$this->assertEmpty($response['body']);
|
||||
|
||||
$databasesTotal -= 1;
|
||||
$requestsTotal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < self::CREATE; $i++) {
|
||||
$name = uniqid() . ' table';
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/databases/' . $databaseId . '/grids/tables',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'tableId' => 'unique()',
|
||||
'name' => $name,
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals($name, $response['body']['name']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$requestsTotal += 1;
|
||||
$tablesTotal += 1;
|
||||
|
||||
$tableId = $response['body']['$id'];
|
||||
|
||||
if ($i < (self::CREATE / 2)) {
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/databases/' . $databaseId . '/grids/tables/' . $tableId,
|
||||
array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
);
|
||||
|
||||
$this->assertEmpty($response['body']);
|
||||
|
||||
$tablesTotal -= 1;
|
||||
$requestsTotal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns' . '/string',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'key' => 'name',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals('name', $response['body']['key']);
|
||||
|
||||
sleep(self::WAIT);
|
||||
|
||||
$requestsTotal += 1;
|
||||
|
||||
for ($i = 0; $i < self::CREATE; $i++) {
|
||||
$name = uniqid() . ' table';
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/databases/' . $databaseId . '/grids/tables/' . $tableId . '/rows',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'rowId' => 'unique()',
|
||||
'data' => ['name' => $name]
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals($name, $response['body']['name']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$requestsTotal += 1;
|
||||
$rowsTotal += 1;
|
||||
|
||||
$rowId = $response['body']['$id'];
|
||||
|
||||
if ($i < (self::CREATE / 2)) {
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_DELETE,
|
||||
'/databases/' . $databaseId . '/grids/tables/' . $tableId . '/rows/' . $rowId,
|
||||
array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()),
|
||||
);
|
||||
|
||||
$this->assertEmpty($response['body']);
|
||||
|
||||
$rowsTotal -= 1;
|
||||
$requestsTotal += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($data, [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'requestsTotal' => $requestsTotal,
|
||||
'databasesTotal' => $databasesTotal,
|
||||
'tablesTotal' => $tablesTotal,
|
||||
'rowsTotal' => $rowsTotal,
|
||||
|
||||
// For clarity
|
||||
'absoluteRowsTotal' => $rowsTotal + $data['documentsTotal'],
|
||||
'absoluteTablesTotal' => $tablesTotal + $data['collectionsTotal'],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @depends testPrepareDatabaseStatsTablesAPI */
|
||||
#[Retry(count: 1)]
|
||||
public function testDatabaseStatsTablesAPI(array $data): array
|
||||
{
|
||||
$tableId = $data['tableId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
$requestsTotal = $data['requestsTotal'];
|
||||
|
||||
$absoluteRowsTotal = $data['absoluteRowsTotal'];
|
||||
$absoluteTablesTotal = $data['absoluteTablesTotal'];
|
||||
|
||||
$rowsTotal = $data['rowsTotal'];
|
||||
$tablesTotal = $data['tablesTotal'];
|
||||
$databasesTotal = $data['databasesTotal'];
|
||||
|
||||
sleep(self::WAIT);
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/project/usage',
|
||||
$this->getConsoleHeaders(),
|
||||
[
|
||||
'period' => '1d',
|
||||
'startDate' => self::getToday(),
|
||||
'endDate' => self::getTomorrow(),
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertGreaterThanOrEqual(31, count($response['body']));
|
||||
$this->assertCount(1, $response['body']['requests']);
|
||||
$this->assertCount(1, $response['body']['network']);
|
||||
$this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']);
|
||||
$this->validateDates($response['body']['requests']);
|
||||
$this->assertEquals($databasesTotal, $response['body']['databasesTotal']);
|
||||
|
||||
// project level includes all i.e. documents + rows total.
|
||||
$this->assertEquals($absoluteRowsTotal, $response['body']['rowsTotal']);
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/databases/usage?range=30d',
|
||||
$this->getConsoleHeaders()
|
||||
);
|
||||
|
||||
$this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']);
|
||||
$this->validateDates($response['body']['databases']);
|
||||
|
||||
// database level includes all i.e. collections + tables total.
|
||||
$this->assertEquals($absoluteTablesTotal, $response['body']['tables'][array_key_last($response['body']['tables'])]['value']); // database level
|
||||
$this->validateDates($response['body']['tables']);
|
||||
|
||||
// database level includes all i.e. documents + rows total.
|
||||
$this->assertEquals($absoluteRowsTotal, $response['body']['rows'][array_key_last($response['body']['rows'])]['value']);
|
||||
$this->validateDates($response['body']['rows']);
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/databases/' . $databaseId . '/usage?range=30d',
|
||||
$this->getConsoleHeaders()
|
||||
);
|
||||
|
||||
$this->assertEquals($tablesTotal, $response['body']['tables'][array_key_last($response['body']['tables'])]['value']);
|
||||
$this->validateDates($response['body']['tables']);
|
||||
|
||||
$this->assertEquals($rowsTotal, $response['body']['rows'][array_key_last($response['body']['rows'])]['value']);
|
||||
$this->validateDates($response['body']['rows']);
|
||||
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/databases/' . $databaseId . '/grids/tables/' . $tableId . '/usage?range=30d',
|
||||
$this->getConsoleHeaders()
|
||||
);
|
||||
|
||||
$this->assertEquals($rowsTotal, $response['body']['rows'][array_key_last($response['body']['rows'])]['value']);
|
||||
$this->validateDates($response['body']['rows']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/** @depends testDatabaseStatsTablesAPI */
|
||||
public function testPrepareFunctionsStats(array $data): array
|
||||
{
|
||||
$executionTime = 0;
|
||||
@@ -675,7 +925,8 @@ class UsageTest extends Scope
|
||||
[
|
||||
'functionId' => 'unique()',
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
'funcKey2' => 'funcValue2',
|
||||
@@ -697,8 +948,7 @@ class UsageTest extends Scope
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true,
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
@@ -70,8 +70,12 @@ trait ProjectCustom
|
||||
'databases.write',
|
||||
'collections.read',
|
||||
'collections.write',
|
||||
'tables.read',
|
||||
'tables.write',
|
||||
'documents.read',
|
||||
'documents.write',
|
||||
'rows.read',
|
||||
'rows.write',
|
||||
'files.read',
|
||||
'files.write',
|
||||
'buckets.read',
|
||||
@@ -140,7 +144,7 @@ trait ProjectCustom
|
||||
'teams.*',
|
||||
'users.*'
|
||||
],
|
||||
'url' => 'http://request-catcher:5000/webhook',
|
||||
'url' => 'http://request-catcher-webhook:5000/',
|
||||
'security' => false,
|
||||
]);
|
||||
|
||||
@@ -200,4 +204,17 @@ trait ProjectCustom
|
||||
|
||||
return $key['body']['secret'];
|
||||
}
|
||||
public function updateProjectinvalidateSessionsProperty(bool $value)
|
||||
{
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . self::$project['$id'] . '/auth/session-invalidation', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
'x-appwrite-project' => 'console',
|
||||
]), [
|
||||
'enabled' => $value,
|
||||
]);
|
||||
|
||||
return $response['headers']['status-code'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ abstract class Scope extends TestCase
|
||||
use Retryable;
|
||||
use Async;
|
||||
|
||||
public const REQUEST_TYPE_WEBHOOK = 'webhook';
|
||||
public const REQUEST_TYPE_SMS = 'sms';
|
||||
|
||||
protected ?Client $client = null;
|
||||
protected string $endpoint = 'http://localhost/v1';
|
||||
|
||||
@@ -37,18 +40,55 @@ abstract class Scope extends TestCase
|
||||
if ($limit === 1) {
|
||||
return end($emails);
|
||||
} else {
|
||||
$lastEmails = array_slice($emails, -1 * $limit);
|
||||
return $lastEmails;
|
||||
return array_slice($emails, -1 * $limit);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function assertLastRequest(callable $probe, $timeoutMs = 20_000, $waitMs = 500): array
|
||||
protected function extractQueryParamsFromEmailLink(string $html): array
|
||||
{
|
||||
$this->assertEventually(function () use (&$request, $probe) {
|
||||
$request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
|
||||
foreach (['/join-us?', '/verification?', '/recovery?'] as $prefix) {
|
||||
$linkStart = strpos($html, $prefix);
|
||||
if ($linkStart !== false) {
|
||||
$hrefStart = strrpos(substr($html, 0, $linkStart), 'href="');
|
||||
if ($hrefStart === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hrefStart += 6;
|
||||
$hrefEnd = strpos($html, '"', $hrefStart);
|
||||
if ($hrefEnd === false || $hrefStart >= $hrefEnd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$link = substr($html, $hrefStart, $hrefEnd - $hrefStart);
|
||||
$link = strtok($link, '#'); // Remove `#title`
|
||||
$queryStart = strpos($link, '?');
|
||||
if ($queryStart === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$queryString = substr($link, $queryStart + 1);
|
||||
parse_str(html_entity_decode($queryString), $queryParams);
|
||||
return $queryParams;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function assertLastRequest(callable $probe, string $type, $timeoutMs = 20_000, $waitMs = 500): array
|
||||
{
|
||||
$hostname = match ($type) {
|
||||
'webhook' => 'request-catcher-webhook',
|
||||
'sms' => 'request-catcher-sms',
|
||||
default => throw new \Exception('Invalid request catcher type.'),
|
||||
};
|
||||
|
||||
$this->assertEventually(function () use (&$request, $probe, $hostname) {
|
||||
$request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true);
|
||||
$request['data'] = json_decode($request['data'], true);
|
||||
|
||||
call_user_func($probe, $request);
|
||||
@@ -57,11 +97,16 @@ abstract class Scope extends TestCase
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use assertLastRequest instead. Used only historically in webhook tests
|
||||
*/
|
||||
protected function getLastRequest(): array
|
||||
{
|
||||
$hostname = 'request-catcher-webhook';
|
||||
|
||||
sleep(2);
|
||||
|
||||
$request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true);
|
||||
$request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true);
|
||||
$request['data'] = json_decode($request['data'], true);
|
||||
|
||||
return $request;
|
||||
|
||||
@@ -170,6 +170,7 @@ trait AccountBase
|
||||
$userId = $response['body']['userId'];
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
|
||||
$this->assertEquals('otpuser@appwrite.io', $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals('OTP for ' . $this->getProject()['name'] . ' Login', $lastEmail['subject']);
|
||||
|
||||
@@ -178,6 +179,7 @@ trait AccountBase
|
||||
$code = ($matches[0] ?? [])[0] ?? '';
|
||||
|
||||
$this->assertNotEmpty($code);
|
||||
$this->assertStringContainsStringIgnoringCase('Use OTP ' . $code . ' to sign in to '. $this->getProject()['name'] . '. Expires in 15 minutes.', $lastEmail['text']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/token', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
|
||||
@@ -480,6 +480,29 @@ class AccountCustomClientTest extends Scope
|
||||
$password = $data['password'] ?? '';
|
||||
$session = $data['session'] ?? '';
|
||||
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$allSessions = array_map(fn ($sessionDetails) => $sessionDetails['$id'], $response['body']['sessions']);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
@@ -500,17 +523,140 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($response['body']['registration']));
|
||||
$this->assertEquals($response['body']['email'], $email);
|
||||
|
||||
$currentSessionId = $data['sessionId'] ?? '';
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(1, $response['body']['total']);
|
||||
// checking the current session or not
|
||||
$this->assertEquals($currentSessionId, $response['body']['sessions'][0]['$id']);
|
||||
$this->assertTrue($response['body']['sessions'][0]['current']);
|
||||
|
||||
// checking for all non active sessions are cleared
|
||||
foreach ($allSessions as $sessionId) {
|
||||
if ($currentSessionId === $sessionId) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/current', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
} else {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
$newPassword = 'new-password';
|
||||
// updating the invalidateSession to false to check sessions are not invalidated
|
||||
$this->updateProjectinvalidateSessionsProperty(false);
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $newPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$allSessions = array_map(fn ($sessionDetails) => $sessionDetails['$id'], $response['body']['sessions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'password' => $newPassword,
|
||||
'oldPassword' => $newPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
foreach ($allSessions as $sessionId) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionId, headers: array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
// setting invalidateSession to true to check the sessions are cleared or not
|
||||
$this->updateProjectinvalidateSessionsProperty(true);
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/account/password', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]), [
|
||||
'password' => $newPassword,
|
||||
'oldPassword' => $newPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$allSessions = array_map(fn ($sessionDetails) => $sessionDetails['$id'], $response['body']['sessions']);
|
||||
|
||||
foreach ($allSessions as $sessionId) {
|
||||
if ($currentSessionId !== $sessionId) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/'.$sessionId, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session,
|
||||
]));
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => 'new-password',
|
||||
'password' => $newPassword,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
@@ -779,18 +925,20 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals($name, $lastEmail['to'][0]['name']);
|
||||
$this->assertEquals('Account Verification', $lastEmail['subject']);
|
||||
$this->assertStringContainsStringIgnoringCase('Verify your email to activate your ' . $this->getProject()['name'] . ' account.', $lastEmail['text']);
|
||||
|
||||
$verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
$expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0);
|
||||
$this->assertNotFalse($expireTime);
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$verification = $tokens['secret'];
|
||||
$expectedExpire = DateTime::formatTz($response['body']['expire']);
|
||||
$this->assertEquals($expectedExpire, $tokens['expire']);
|
||||
|
||||
$secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0);
|
||||
// Secret check
|
||||
$this->assertArrayHasKey('secret', $tokens);
|
||||
$this->assertNotEmpty($tokens['secret']);
|
||||
|
||||
$this->assertNotFalse($secretTest);
|
||||
|
||||
$userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0);
|
||||
|
||||
$this->assertNotFalse($userIDTest);
|
||||
// User ID check
|
||||
$this->assertArrayHasKey('userId', $tokens);
|
||||
$this->assertNotEmpty($tokens['userId']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -1081,20 +1229,28 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals($name, $lastEmail['to'][0]['name']);
|
||||
$this->assertEquals('Password Reset', $lastEmail['subject']);
|
||||
$this->assertStringContainsStringIgnoringCase('Reset your ' . $this->getProject()['name'] . ' password using the link.', $lastEmail['text']);
|
||||
|
||||
$recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
|
||||
$expireTime = strpos($lastEmail['text'], 'expire=' . urlencode(DateTime::format(new \DateTime($response['body']['expire']))), 0);
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
|
||||
$this->assertNotFalse($expireTime);
|
||||
// Secret check
|
||||
$this->assertArrayHasKey('secret', $tokens);
|
||||
$this->assertNotEmpty($tokens['secret']);
|
||||
$this->assertNotFalse($response['body']['secret']);
|
||||
|
||||
$secretTest = strpos($lastEmail['text'], 'secret=' . $response['body']['secret'], 0);
|
||||
// User ID check
|
||||
$this->assertArrayHasKey('userId', $tokens);
|
||||
$this->assertNotEmpty($tokens['userId']);
|
||||
$this->assertNotFalse($response['body']['userId']);
|
||||
|
||||
$this->assertNotFalse($secretTest);
|
||||
|
||||
$userIDTest = strpos($lastEmail['text'], 'userId=' . $response['body']['userId'], 0);
|
||||
|
||||
$this->assertNotFalse($userIDTest);
|
||||
// Expire check
|
||||
$this->assertArrayHasKey('expire', $tokens);
|
||||
$this->assertNotEmpty($tokens['expire']);
|
||||
$this->assertEquals(
|
||||
DateTime::formatTz($response['body']['expire']),
|
||||
$tokens['expire']
|
||||
);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -1132,7 +1288,7 @@ class AccountCustomClientTest extends Scope
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
$data['recovery'] = $recovery;
|
||||
$data['recovery'] = $tokens['secret'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -1279,6 +1435,7 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertNotEmpty($response['body']['expire']);
|
||||
$this->assertEmpty($response['body']['secret']);
|
||||
$this->assertEmpty($response['body']['phrase']);
|
||||
$this->assertStringContainsStringIgnoringCase('New login detected on '. $this->getProject()['name'], $lastEmail['text']);
|
||||
|
||||
$userId = $response['body']['userId'];
|
||||
|
||||
@@ -1287,7 +1444,7 @@ class AccountCustomClientTest extends Scope
|
||||
$this->assertEquals('otpuser2@appwrite.io', $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals('OTP for ' . $this->getProject()['name'] . ' Login', $lastEmail['subject']);
|
||||
|
||||
// FInd 6 concurrent digits in email text - OTP
|
||||
// Find 6 concurrent digits in email text - OTP
|
||||
preg_match_all("/\b\d{6}\b/", $lastEmail['text'], $matches);
|
||||
$code = ($matches[0] ?? [])[0] ?? '';
|
||||
|
||||
@@ -2058,14 +2215,13 @@ class AccountCustomClientTest extends Scope
|
||||
$userId = $response['body']['userId'];
|
||||
|
||||
$smsRequest = $this->assertLastRequest(function (array $request) use ($number) {
|
||||
$this->assertEquals('http://request-catcher:5000/mock-sms', $request['url']);
|
||||
$this->assertEquals('Appwrite Mock Message Sender', $request['headers']['User-Agent']);
|
||||
$this->assertEquals('username', $request['headers']['X-Username']);
|
||||
$this->assertEquals('password', $request['headers']['X-Key']);
|
||||
$this->assertEquals('POST', $request['method']);
|
||||
$this->assertEquals('+123456789', $request['data']['from']);
|
||||
$this->assertEquals($number, $request['data']['to']);
|
||||
});
|
||||
}, Scope::REQUEST_TYPE_SMS);
|
||||
|
||||
$data['token'] = $smsRequest['data']['message'];
|
||||
$data['id'] = $userId;
|
||||
@@ -2409,13 +2565,21 @@ class AccountCustomClientTest extends Scope
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
$this->assertNotEmpty($response['body']['$createdAt']);
|
||||
$this->assertEmpty($response['body']['secret']);
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($response['body']['expire']));
|
||||
|
||||
$smsRequest = $this->assertLastRequest(function ($request) {
|
||||
$tokenCreatedAt = $response['body']['$createdAt'];
|
||||
|
||||
$smsRequest = $this->assertLastRequest(function ($request) use ($tokenCreatedAt) {
|
||||
$this->assertArrayHasKey('data', $request);
|
||||
$this->assertArrayHasKey('message', $request['data']);
|
||||
});
|
||||
$this->assertArrayHasKey('time', $request);
|
||||
$this->assertArrayHasKey('message', $request['data'], "Last request missing message: " . \json_encode($request));
|
||||
|
||||
// Ensure we are not using token from last sms login
|
||||
$tokenRecievedAt = $request['time'];
|
||||
$this->assertGreaterThan($tokenCreatedAt, $tokenRecievedAt);
|
||||
}, Scope::REQUEST_TYPE_SMS);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -2531,6 +2695,7 @@ class AccountCustomClientTest extends Scope
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals($this->getProject()['name'] . ' Login', $lastEmail['subject']);
|
||||
$this->assertStringContainsStringIgnoringCase('Sign in to '. $this->getProject()['name'] . ' with your secure link. Expires in 1 hour.', $lastEmail['text']);
|
||||
$this->assertStringNotContainsStringIgnoringCase('security phrase', $lastEmail['text']);
|
||||
|
||||
$token = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 64);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class DatabasesConsoleClientTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
|
||||
public function testCreateTable(): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'invalidDocumentDatabase',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('invalidDocumentDatabase', $database['body']['name']);
|
||||
$this->assertTrue($database['body']['enabled']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $movies['headers']['status-code']);
|
||||
$this->assertEquals('Movies', $movies['body']['name']);
|
||||
|
||||
/**
|
||||
* Test when database is disabled but can still create tables
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'invalidDocumentDatabase Updated',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->assertFalse($database['body']['enabled']);
|
||||
|
||||
$tvShows = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'TvShows',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Test when table is disabled but can still modify tables
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/' . $movies['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Movies',
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $tvShows['headers']['status-code']);
|
||||
$this->assertEquals('TvShows', $tvShows['body']['name']);
|
||||
|
||||
return ['moviesId' => $movies['body']['$id'], 'databaseId' => $databaseId, 'tvShowsId' => $tvShows['body']['$id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @param array $data
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testListTable(array $data)
|
||||
{
|
||||
/**
|
||||
* Test when database is disabled but can still call list tables
|
||||
*/
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$tables = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $tables['headers']['status-code']);
|
||||
$this->assertEquals(2, $tables['body']['total']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @param array $data
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testGetTable(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$moviesCollectionId = $data['moviesId'];
|
||||
|
||||
/**
|
||||
* Test when database and table are disabled but can still call get table
|
||||
*/
|
||||
$table = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $moviesCollectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $table['headers']['status-code']);
|
||||
$this->assertEquals('Movies', $table['body']['name']);
|
||||
$this->assertEquals($moviesCollectionId, $table['body']['$id']);
|
||||
$this->assertFalse($table['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @param array $data
|
||||
* @throws \Exception
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testUpdateTable(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$moviesCollectionId = $data['moviesId'];
|
||||
|
||||
/**
|
||||
* Test When database and table are disabled but can still call update table
|
||||
*/
|
||||
$table = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/' . $moviesCollectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Movies Updated',
|
||||
'enabled' => false
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $table['headers']['status-code']);
|
||||
$this->assertEquals('Movies Updated', $table['body']['name']);
|
||||
$this->assertEquals($moviesCollectionId, $table['body']['$id']);
|
||||
$this->assertFalse($table['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @param array $data
|
||||
* @throws \Exception
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testDeleteTable(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
$tvShowsId = $data['tvShowsId'];
|
||||
|
||||
/**
|
||||
* Test when database and table are disabled but can still call delete table
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $tvShowsId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
$this->assertEquals("", $response['body']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
public function testGetDatabaseUsage(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '32h'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(15, $response['body']);
|
||||
$this->assertEquals('24h', $response['body']['range']);
|
||||
$this->assertIsNumeric($response['body']['rowsTotal']);
|
||||
$this->assertIsNumeric($response['body']['tablesTotal']);
|
||||
$this->assertIsArray($response['body']['tables']);
|
||||
$this->assertIsArray($response['body']['rows']);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
public function testGetTableUsage(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '32h'
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/randomCollectionId/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/usage', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'range' => '24h'
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(3, count($response['body']));
|
||||
$this->assertEquals('24h', $response['body']['range']);
|
||||
$this->assertIsNumeric($response['body']['rowsTotal']);
|
||||
$this->assertIsArray($response['body']['rows']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @throws \Utopia\Database\Exception\Query
|
||||
*/
|
||||
public function testGetTableLogs(array $data)
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/logs', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $logs['headers']['status-code']);
|
||||
$this->assertIsArray($logs['body']['logs']);
|
||||
$this->assertIsNumeric($logs['body']['total']);
|
||||
|
||||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/logs', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::limit(1)->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $logs['headers']['status-code']);
|
||||
$this->assertIsArray($logs['body']['logs']);
|
||||
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
|
||||
$this->assertIsNumeric($logs['body']['total']);
|
||||
|
||||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/logs', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::offset(1)->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $logs['headers']['status-code']);
|
||||
$this->assertIsArray($logs['body']['logs']);
|
||||
$this->assertIsNumeric($logs['body']['total']);
|
||||
|
||||
$logs = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $data['moviesId'] . '/logs', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [Query::offset(1)->toString(), Query::limit(1)->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $logs['headers']['status-code']);
|
||||
$this->assertIsArray($logs['body']['logs']);
|
||||
$this->assertLessThanOrEqual(1, count($logs['body']['logs']));
|
||||
$this->assertIsNumeric($logs['body']['total']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,893 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class DatabasesCustomClientTest extends Scope
|
||||
{
|
||||
use DatabasesBase;
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
|
||||
public function testAllowedPermissions(): void
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database'
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Collection aliases write to create, update, delete
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::write(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$moviesId = $movies['body']['$id'];
|
||||
|
||||
$this->assertContains(Permission::create(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
|
||||
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
|
||||
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $movies['body']['$permissions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $moviesId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
// Document aliases write to update, delete
|
||||
$row1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $moviesId . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Captain America',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::write(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertNotContains(Permission::create(Role::user($this->getUser()['$id'])), $row1['body']['$permissions']);
|
||||
$this->assertContains(Permission::update(Role::user($this->getUser()['$id'])), $row1['body']['$permissions']);
|
||||
$this->assertContains(Permission::delete(Role::user($this->getUser()['$id'])), $row1['body']['$permissions']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
// Document does not allow create permission
|
||||
$row2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $moviesId . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Captain America',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $row2['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testUpdateWithoutPermission(): array
|
||||
{
|
||||
// If document has been created by server and client tried to update it without adjusting permissions, permission validation should be skipped
|
||||
|
||||
// As a part of preparation, we get ID of currently logged-in user
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
$userId = $response['body']['$id'];
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::custom('permissionCheckDatabase'),
|
||||
'name' => 'Test Database',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('Test Database', $database['body']['name']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
// Create collection
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('permissionCheck'),
|
||||
'name' => 'permissionCheck',
|
||||
'permissions' => [],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// Add attribute to collection
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/permissionCheck/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
// Wait for database worker to finish creating attributes
|
||||
sleep(2);
|
||||
|
||||
// Creating document by server, give read permission to our user + some other user
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/permissionCheck/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'rowId' => ID::custom('permissionCheckDocument'),
|
||||
'data' => [
|
||||
'name' => 'AppwriteBeginner',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user(ID::custom('user2'))),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// Update document
|
||||
// This is the point of this test. We should be allowed to do this action, and it should not fail on permission check
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/permissionCheck/rows/permissionCheckDocument', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'name' => 'AppwriteExpert',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
// Get name of the document, should be the new one
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/permissionCheck/rows/permissionCheckDocument', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals("AppwriteExpert", $response['body']['name']);
|
||||
|
||||
// Cleanup to prevent collision with other tests
|
||||
// Delete collection
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/permissionCheck', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $response['headers']['status-code']);
|
||||
|
||||
|
||||
// Wait for database worker to finish deleting collection
|
||||
sleep(2);
|
||||
|
||||
// Make sure collection has been deleted
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/permissionCheck', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testUpdateTwoWayRelationship(): void
|
||||
{
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database'
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
|
||||
// Creating collection 1
|
||||
$table1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'level1',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creating collection 2
|
||||
$table2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'level2',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
// Creating two way relationship between collection 1 and collection 2 from collection 1
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => 'oneToMany',
|
||||
'twoWay' => true,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => $table2['body']['$id'],
|
||||
'twoWayKey' => $table1['body']['$id']
|
||||
]);
|
||||
|
||||
\sleep(3);
|
||||
|
||||
// Update relation from collection 2 to on delete restrict
|
||||
$this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table2['body']['$id'] . '/columns/' . $table1['body']['$id'] . '/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'onDelete' => 'restrict',
|
||||
]);
|
||||
|
||||
// Fetching attributes after updating relation to compare
|
||||
$table1Attributes = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'], [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]);
|
||||
|
||||
$table1RelationAttribute = $table1Attributes['body']['columns'][0];
|
||||
|
||||
$this->assertEquals($relation['body']['side'], $table1RelationAttribute['side']);
|
||||
$this->assertEquals($relation['body']['twoWayKey'], $table1RelationAttribute['twoWayKey']);
|
||||
$this->assertEquals($relation['body']['relatedTable'], $table1RelationAttribute['relatedTable']);
|
||||
$this->assertEquals('restrict', $table1RelationAttribute['onDelete']);
|
||||
}
|
||||
|
||||
public function testRelationshipSameTwoWayKey(): void
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Same two way key'
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$table1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'c1',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
$table2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'c2',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_ONE_TO_ONE,
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => 'attr1',
|
||||
'twoWayKey' => 'same_key'
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals(202, $relation['headers']['status-code']);
|
||||
$this->assertEquals('same_key', $relation['body']['twoWayKey']);
|
||||
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_ONE_TO_MANY,
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => 'attr2',
|
||||
'twoWayKey' => 'same_key'
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals(409, $relation['body']['code']);
|
||||
$this->assertEquals('Attribute with the requested key already exists. Attribute keys must be unique, try again with a different key.', $relation['body']['message']);
|
||||
|
||||
// twoWayKey is null TwoWayKey is default
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_ONE_TO_MANY,
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => 'attr3',
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals(202, $relation['headers']['status-code']);
|
||||
$this->assertArrayHasKey('twoWayKey', $relation['body']);
|
||||
|
||||
// twoWayKey is null, TwoWayKey is default, second POST
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_ONE_TO_MANY,
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'cascade',
|
||||
'key' => 'attr4',
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals('Attribute with the requested key already exists. Attribute keys must be unique, try again with a different key.', $relation['body']['message']);
|
||||
$this->assertEquals(409, $relation['body']['code']);
|
||||
|
||||
// RelationshipManyToMany
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_MANY_TO_MANY,
|
||||
'twoWay' => true,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => 'songs',
|
||||
'twoWayKey' => 'playlist',
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals(202, $relation['headers']['status-code']);
|
||||
$this->assertArrayHasKey('twoWayKey', $relation['body']);
|
||||
|
||||
// Second RelationshipManyToMany on Same collections
|
||||
$relation = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => Database::RELATION_MANY_TO_MANY,
|
||||
'twoWay' => true,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => 'songs2',
|
||||
'twoWayKey' => 'playlist2',
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
$this->assertEquals(409, $relation['body']['code']);
|
||||
$this->assertEquals('Creating more than one "manyToMany" relationship on the same table is currently not permitted.', $relation['body']['message']);
|
||||
}
|
||||
|
||||
public function testUpdateWithoutRelationPermission(): void
|
||||
{
|
||||
$userId = $this->getUser()['$id'];
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => ID::unique(),
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Creating collection 1
|
||||
$table1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection1'),
|
||||
'name' => ID::custom('collection1'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creating collection 2
|
||||
$table2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection2'),
|
||||
'name' => ID::custom('collection2'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
$table3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection3'),
|
||||
'name' => ID::custom('collection3'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
$table4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection4'),
|
||||
'name' => ID::custom('collection4'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
$table5 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection5'),
|
||||
'name' => ID::custom('collection5'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creating one to one relationship from collection 1 to colletion 2
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table2['body']['$id'],
|
||||
'type' => 'oneToOne',
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => $table2['body']['$id']
|
||||
]);
|
||||
|
||||
// Creating one to one relationship from collection 2 to colletion 3
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table2['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table3['body']['$id'],
|
||||
'type' => 'oneToOne',
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => $table3['body']['$id']
|
||||
]);
|
||||
|
||||
// Creating one to one relationship from collection 3 to colletion 4
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table3['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table4['body']['$id'],
|
||||
'type' => 'oneToOne',
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => $table4['body']['$id']
|
||||
]);
|
||||
|
||||
// Creating one to one relationship from collection 4 to colletion 5
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table4['body']['$id'] . '/columns/relationship', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'relatedTableId' => $table5['body']['$id'],
|
||||
'type' => 'oneToOne',
|
||||
'twoWay' => false,
|
||||
'onDelete' => 'setNull',
|
||||
'key' => $table5['body']['$id']
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => "Title",
|
||||
'size' => 100,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table2['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => "Rating",
|
||||
'size' => 100,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table3['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => "Rating",
|
||||
'size' => 100,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table4['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => "Rating",
|
||||
'size' => 100,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table5['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => "Rating",
|
||||
'size' => 100,
|
||||
'required' => false,
|
||||
'array' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
// Creating parent document with a child reference to test the permissions
|
||||
$parentDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'rowId' => ID::custom($table1['body']['$id']),
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => ID::custom($table2['body']['$id']),
|
||||
'Rating' => '10',
|
||||
$table3['body']['$id'] => [
|
||||
'$id' => ID::custom($table3['body']['$id']),
|
||||
'Rating' => '10',
|
||||
$table4['body']['$id'] => [
|
||||
'$id' => ID::custom($table4['body']['$id']),
|
||||
'Rating' => '10',
|
||||
$table5['body']['$id'] => [
|
||||
'$id' => ID::custom($table5['body']['$id']),
|
||||
'Rating' => '10'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $parentDocument['headers']['status-code']);
|
||||
// This is the point of the test. We should not need any authorization permission to update the document with same data.
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows/' . $table1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::custom($table1['body']['$id']),
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => $table2['body']['$id'],
|
||||
'Rating' => '10',
|
||||
$table3['body']['$id'] => [
|
||||
'$id' => $table3['body']['$id'],
|
||||
'Rating' => '10',
|
||||
$table4['body']['$id'] => [
|
||||
'$id' => $table4['body']['$id'],
|
||||
'Rating' => '10',
|
||||
$table5['body']['$id'] => [
|
||||
'$id' => $table5['body']['$id'],
|
||||
'Rating' => '10'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($parentDocument['body'], $response['body']);
|
||||
|
||||
// Giving update permission of collection 3 to user.
|
||||
$this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/collection3', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection3'),
|
||||
'name' => ID::custom('collection3'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
// This is the point of this test. We should be allowed to do this action, and it should not fail on permission check
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows/' . $table1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => ID::custom($table2['body']['$id']),
|
||||
'Rating' => '10',
|
||||
$table3['body']['$id'] => [
|
||||
'$id' => ID::custom($table3['body']['$id']),
|
||||
'Rating' => '11',
|
||||
$table4['body']['$id'] => [
|
||||
'$id' => ID::custom($table4['body']['$id']),
|
||||
'Rating' => '10',
|
||||
$table5['body']['$id'] => [
|
||||
'$id' => ID::custom($table5['body']['$id']),
|
||||
'Rating' => '11'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(11, $response['body'][$table2['body']['$id']]['collection3']['Rating']);
|
||||
|
||||
// We should not be allowed to update the document as we do not have permission for collection 2.
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows/' . $table1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => ID::custom($table2['body']['$id']),
|
||||
'Rating' => '11',
|
||||
$table3['body']['$id'] => null,
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
// We should not be allowed to update the document as we do not have permission for collection 2.
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table2['body']['$id'] . '/rows/' . $table2['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'Rating' => '11',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $response['headers']['status-code']);
|
||||
|
||||
// Removing update permission from collection 3.
|
||||
$this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/collection3', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection3'),
|
||||
'name' => ID::custom('collection3'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
// Giving update permission to collection 2.
|
||||
$this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/collection2', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::custom('collection2'),
|
||||
'name' => ID::custom('collection2'),
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]);
|
||||
|
||||
// Creating collection 3 new document
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table3['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'rowId' => ID::custom('collection3Doc1'),
|
||||
'data' => [
|
||||
'Rating' => '20'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// We should be allowed to link a new document from collection 3 to collection 2.
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows/' . $table1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => ID::custom($table2['body']['$id']),
|
||||
$table3['body']['$id'] => 'collection3Doc1',
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
||||
|
||||
// We should be allowed to link and create a new document from collection 3 to collection 2.
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $table1['body']['$id'] . '/rows/' . $table1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'Title' => 'Captain America',
|
||||
$table2['body']['$id'] => [
|
||||
'$id' => ID::custom($table2['body']['$id']),
|
||||
$table3['body']['$id'] => [
|
||||
'$id' => ID::custom('collection3Doc2')
|
||||
],
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
class DatabasesPermissionsGuestTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
use DatabasesPermissionsScope;
|
||||
|
||||
public function createTable(): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'InvalidRowDatabase',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('InvalidRowDatabase', $database['body']['name']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
$publicMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
$privateMovies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
$publicTable = ['id' => $publicMovies['body']['$id']];
|
||||
$privateTable = ['id' => $privateMovies['body']['$id']];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $publicTable['id'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $privateTable['id'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'publicTableId' => $publicTable['id'],
|
||||
'privateTableId' => $privateTable['id'],
|
||||
];
|
||||
}
|
||||
|
||||
public function permissionsProvider(): array
|
||||
{
|
||||
return [
|
||||
[[Permission::read(Role::any())]],
|
||||
[[Permission::read(Role::users())]],
|
||||
[[Permission::update(Role::any()), Permission::delete(Role::any())]],
|
||||
[[Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any())]],
|
||||
[[Permission::read(Role::users()), Permission::update(Role::users()), Permission::delete(Role::users())]],
|
||||
[[Permission::read(Role::any()), Permission::update(Role::users()), Permission::delete(Role::users())]],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider permissionsProvider
|
||||
*/
|
||||
public function testReadRows($permissions)
|
||||
{
|
||||
$data = $this->createTable();
|
||||
$publicTableId = $data['publicTableId'];
|
||||
$privateTableId = $data['privateTableId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $publicTableId . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
$privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
'permissions' => $permissions,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $publicResponse['headers']['status-code']);
|
||||
$this->assertEquals(201, $privateResponse['headers']['status-code']);
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
Authorization::cleanRoles();
|
||||
|
||||
$publicRows = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $publicTableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
$privateRows = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(1, $publicRows['body']['total']);
|
||||
$this->assertEquals($permissions, $publicRows['body']['rows'][0]['$permissions']);
|
||||
|
||||
if (\in_array(Permission::read(Role::any()), $permissions)) {
|
||||
$this->assertEquals(1, $privateRows['body']['total']);
|
||||
$this->assertEquals($permissions, $privateRows['body']['rows'][0]['$permissions']);
|
||||
} else {
|
||||
$this->assertEquals(0, $privateRows['body']['total']);
|
||||
}
|
||||
|
||||
foreach ($roles as $role) {
|
||||
Authorization::setRole($role);
|
||||
}
|
||||
}
|
||||
|
||||
public function testWriteRow()
|
||||
{
|
||||
$data = $this->createTable();
|
||||
$publicTableId = $data['publicTableId'];
|
||||
$privateTableId = $data['privateTableId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$roles = Authorization::getRoles();
|
||||
Authorization::cleanRoles();
|
||||
|
||||
$publicResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $publicTableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
]
|
||||
]);
|
||||
|
||||
$publicRowId = $publicResponse['body']['$id'];
|
||||
$this->assertEquals(201, $publicResponse['headers']['status-code']);
|
||||
|
||||
$privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $privateResponse['headers']['status-code']);
|
||||
|
||||
// Create a row in private collection with API key so we can test that update and delete are also not allowed
|
||||
$privateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $privateResponse['headers']['status-code']);
|
||||
$privateRowId = $privateResponse['body']['$id'];
|
||||
|
||||
$publicRow = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $publicTableId . '/rows/' . $publicRowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $publicRow['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $publicRow['body']['title']);
|
||||
|
||||
$privateRow = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows/' . $privateRowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $privateRow['headers']['status-code']);
|
||||
|
||||
$publicRow = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $publicTableId . '/rows/' . $publicRowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(204, $publicRow['headers']['status-code']);
|
||||
|
||||
$privateRow = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $privateTableId . '/rows/' . $privateRowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $privateRow['headers']['status-code']);
|
||||
|
||||
foreach ($roles as $role) {
|
||||
Authorization::setRole($role);
|
||||
}
|
||||
}
|
||||
|
||||
public function testWriteRowWithPermissions()
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'GuestPermissionsWrite',
|
||||
]);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('GuestPermissionsWrite', $database['body']['name']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
$movies = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true
|
||||
]);
|
||||
|
||||
$moviesId = $movies['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $moviesId . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $moviesId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $row['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $row['body']['title']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class DatabasesPermissionsMemberTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
use DatabasesPermissionsScope;
|
||||
|
||||
public array $tables = [];
|
||||
|
||||
public function createUsers(): array
|
||||
{
|
||||
return [
|
||||
'user1' => $this->createUser('user1', 'lorem@ipsum.com'),
|
||||
'user2' => $this->createUser('user2', 'dolor@ipsum.com'),
|
||||
];
|
||||
}
|
||||
|
||||
public function permissionsProvider(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'permissions' => [Permission::read(Role::any())],
|
||||
'any' => 1,
|
||||
'users' => 1,
|
||||
'doconly' => 1,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::users())],
|
||||
'any' => 2,
|
||||
'users' => 2,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('random')))],
|
||||
'any' => 3,
|
||||
'users' => 3,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('lorem'))), Permission::update(Role::user('lorem')), Permission::delete(Role::user('lorem'))],
|
||||
'any' => 4,
|
||||
'users' => 4,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('dolor'))), Permission::update(Role::user('dolor')), Permission::delete(Role::user('dolor'))],
|
||||
'any' => 5,
|
||||
'users' => 5,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('dolor'))), Permission::read(Role::user('lorem')), Permission::update(Role::user('dolor')), Permission::delete(Role::user('dolor'))],
|
||||
'any' => 6,
|
||||
'users' => 6,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::update(Role::any()), Permission::delete(Role::any())],
|
||||
'any' => 7,
|
||||
'users' => 7,
|
||||
'doconly' => 2,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any())],
|
||||
'any' => 8,
|
||||
'users' => 8,
|
||||
'doconly' => 3,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::any()), Permission::update(Role::users()), Permission::delete(Role::users())],
|
||||
'any' => 9,
|
||||
'users' => 9,
|
||||
'doconly' => 4,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('user1')))],
|
||||
'any' => 10,
|
||||
'users' => 10,
|
||||
'doconly' => 5,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::user(ID::custom('user1'))), Permission::read(Role::user(ID::custom('user1')))],
|
||||
'any' => 11,
|
||||
'users' => 11,
|
||||
'doconly' => 6,
|
||||
],
|
||||
[
|
||||
'permissions' => [Permission::read(Role::users()), Permission::update(Role::users()), Permission::delete(Role::users())],
|
||||
'any' => 12,
|
||||
'users' => 12,
|
||||
'doconly' => 7,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup database
|
||||
*
|
||||
* Data providers lose object state so explicitly pass [$users, $tables] to each iteration
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testSetupDatabase(): array
|
||||
{
|
||||
$this->createUsers();
|
||||
|
||||
$db = $this->client->call(Client::METHOD_POST, '/databases', $this->getServerHeader(), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database',
|
||||
]);
|
||||
$this->assertEquals(201, $db['headers']['status-code']);
|
||||
|
||||
$databaseId = $db['body']['$id'];
|
||||
|
||||
$public = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Movies',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
$this->assertEquals(201, $public['headers']['status-code']);
|
||||
$this->tables = ['public' => $public['body']['$id']];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $this->tables['public'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
$private = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Private Movies',
|
||||
'permissions' => [
|
||||
Permission::read(Role::users()),
|
||||
Permission::create(Role::users()),
|
||||
Permission::update(Role::users()),
|
||||
Permission::delete(Role::users()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
$this->assertEquals(201, $private['headers']['status-code']);
|
||||
$this->tables['private'] = $private['body']['$id'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $this->tables['private'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
$doconly = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Row Only Movies',
|
||||
'permissions' => [],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
$this->assertEquals(201, $private['headers']['status-code']);
|
||||
$this->tables['doconly'] = $doconly['body']['$id'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $this->tables['doconly'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
return [
|
||||
'users' => $this->users,
|
||||
'tables' => $this->tables,
|
||||
'databaseId' => $databaseId
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider params are passed before test dependencies
|
||||
* @dataProvider permissionsProvider
|
||||
* @depends testSetupDatabase
|
||||
*/
|
||||
public function testReadRows($permissions, $anyCount, $usersCount, $docOnlyCount, $data)
|
||||
{
|
||||
$users = $data['users'];
|
||||
$tables = $data['tables'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tables['public'] . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
'permissions' => $permissions
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tables['private'] . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
'permissions' => $permissions
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tables['doconly'] . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
'permissions' => $permissions
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Check "any" permission table
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tables['public'] . '/rows', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertEquals($anyCount, $rows['body']['total']);
|
||||
|
||||
/**
|
||||
* Check "users" permission table
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tables['private'] . '/rows', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertEquals($usersCount, $rows['body']['total']);
|
||||
|
||||
/**
|
||||
* Check "user:user1" row only permission table
|
||||
*/
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tables['doconly'] . '/rows', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users['user1']['session'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertEquals($docOnlyCount, $rows['body']['total']);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class DatabasesPermissionsTeamTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
use DatabasesPermissionsScope;
|
||||
|
||||
public array $tables = [];
|
||||
public string $databaseId = 'testpermissiondb';
|
||||
|
||||
public function createTeams(): array
|
||||
{
|
||||
return [
|
||||
'team1' => $this->createTeam('team1', 'Team 1'),
|
||||
'team2' => $this->createTeam('team2', 'Team 2'),
|
||||
];
|
||||
}
|
||||
|
||||
public function createUsers(): array
|
||||
{
|
||||
return [
|
||||
'user1' => $this->createUser('user1', 'lorem@ipsum.com'),
|
||||
'user2' => $this->createUser('user2', 'dolor@ipsum.com'),
|
||||
'user3' => $this->createUser('user3', 'sit@ipsum.com'),
|
||||
];
|
||||
}
|
||||
|
||||
public function createTables($teams)
|
||||
{
|
||||
$db = $this->client->call(Client::METHOD_POST, '/databases', $this->getServerHeader(), [
|
||||
'databaseId' => $this->databaseId,
|
||||
'name' => 'Test Database',
|
||||
]);
|
||||
$this->assertEquals(201, $db['headers']['status-code']);
|
||||
|
||||
$table1 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::custom('table1'),
|
||||
'name' => 'Table 1',
|
||||
'permissions' => [
|
||||
Permission::read(Role::team($teams['team1']['$id'])),
|
||||
Permission::create(Role::team($teams['team1']['$id'], 'admin')),
|
||||
Permission::update(Role::team($teams['team1']['$id'], 'admin')),
|
||||
Permission::delete(Role::team($teams['team1']['$id'], 'admin')),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->tables['table1'] = $table1['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables/' . $this->tables['table1'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$table2 = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables', $this->getServerHeader(), [
|
||||
'tableId' => ID::custom('table2'),
|
||||
'name' => 'Table 2',
|
||||
'permissions' => [
|
||||
Permission::read(Role::team($teams['team2']['$id'])),
|
||||
Permission::create(Role::team($teams['team2']['$id'], 'owner')),
|
||||
Permission::update(Role::team($teams['team2']['$id'], 'owner')),
|
||||
Permission::delete(Role::team($teams['team2']['$id'], 'owner')),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->tables['table2'] = $table2['body']['$id'];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables/' . $this->tables['table2'] . '/columns/string', $this->getServerHeader(), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
return $this->tables;
|
||||
}
|
||||
|
||||
/*
|
||||
* $success = can $user read from $table
|
||||
* [$user, $table, $success]
|
||||
*/
|
||||
public function readRowsProvider(): array
|
||||
{
|
||||
return [
|
||||
['user1', 'table1', true],
|
||||
['user2', 'table1', false],
|
||||
['user3', 'table1', true],
|
||||
['user1', 'table2', false],
|
||||
['user2', 'table2', true],
|
||||
['user3', 'table2', true],
|
||||
];
|
||||
}
|
||||
|
||||
/*
|
||||
* $success = can $user write to $table
|
||||
* [$user, $table, $success]
|
||||
*/
|
||||
public function writeRowsProvider(): array
|
||||
{
|
||||
return [
|
||||
['user1', 'table1', true],
|
||||
['user2', 'table1', false],
|
||||
['user3', 'table1', false],
|
||||
['user1', 'table2', false],
|
||||
['user2', 'table2', true],
|
||||
['user3', 'table2', false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup database
|
||||
*
|
||||
* Data providers lose object state
|
||||
* so explicitly pass $users to each iteration
|
||||
* @return array $users
|
||||
*/
|
||||
public function testSetupDatabase(): array
|
||||
{
|
||||
$this->createUsers();
|
||||
$this->createTeams();
|
||||
|
||||
$this->addToTeam('user1', 'team1', ['admin']);
|
||||
$this->addToTeam('user2', 'team2', ['owner']);
|
||||
|
||||
// user3 in both teams but with no roles
|
||||
$this->addToTeam('user3', 'team1');
|
||||
$this->addToTeam('user3', 'team2');
|
||||
|
||||
$this->createTables($this->teams);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables/' . $this->tables['table1'] . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Lorem',
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables/' . $this->tables['table2'] . '/rows', $this->getServerHeader(), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Ipsum',
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
return $this->users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider params are passed before test dependencies
|
||||
* @depends testSetupDatabase
|
||||
* @dataProvider readRowsProvider
|
||||
*/
|
||||
public function testReadRows($user, $table, $success, $users)
|
||||
{
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/databases/' . $this->databaseId . '/grids/tables/' . $table . '/rows', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'],
|
||||
]);
|
||||
|
||||
if ($success) {
|
||||
$this->assertCount(1, $rows['body']['rows']);
|
||||
} else {
|
||||
$this->assertEquals(401, $rows['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testSetupDatabase
|
||||
* @dataProvider writeRowsProvider
|
||||
*/
|
||||
public function testWriteRows($user, $table, $success, $users)
|
||||
{
|
||||
$rows = $this->client->call(Client::METHOD_POST, '/databases/' . $this->databaseId . '/grids/tables/' . $table . '/rows', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $users[$user]['session'],
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Ipsum',
|
||||
],
|
||||
]);
|
||||
|
||||
if ($success) {
|
||||
$this->assertEquals(201, $rows['headers']['status-code']);
|
||||
} else {
|
||||
// 401 if user is a part of team, 404 otherwise
|
||||
$this->assertContains($rows['headers']['status-code'], [401, 404]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+250
-49
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Tests\E2E\Client;
|
||||
@@ -87,7 +87,7 @@ trait DatabasesBase
|
||||
/**
|
||||
* @depends testCreateCollection
|
||||
*/
|
||||
public function testConsoleProject(array $data)
|
||||
public function testConsoleProject(array $data): void
|
||||
{
|
||||
if ($this->getSide() === 'server') {
|
||||
// Server side can't get past the invalid key check anyway
|
||||
@@ -1344,7 +1344,8 @@ trait DatabasesBase
|
||||
'attributes' => ['actors'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $actorsArray['headers']['status-code']);
|
||||
// Indexes on array attributes are disabled due to MySQL bug
|
||||
$this->assertEquals(400, $actorsArray['headers']['status-code']);
|
||||
|
||||
$twoLevelsArray = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1357,9 +1358,8 @@ trait DatabasesBase
|
||||
'orders' => ['DESC', 'DESC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $twoLevelsArray['headers']['status-code']);
|
||||
$this->assertEquals('DESC', $twoLevelsArray['body']['orders'][0]);
|
||||
$this->assertEquals(null, $twoLevelsArray['body']['orders'][1]); // Overwrite by API (array)
|
||||
// Indexes on array attributes are disabled due to MySQL bug
|
||||
$this->assertEquals(400, $twoLevelsArray['headers']['status-code']);
|
||||
|
||||
$unknown = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1384,7 +1384,9 @@ trait DatabasesBase
|
||||
'attributes' => ['integers'], // array attribute
|
||||
'orders' => ['DESC'], // Check order is removed in API
|
||||
]);
|
||||
$this->assertEquals(202, $index1['headers']['status-code']);
|
||||
|
||||
// Indexes on array attributes are disabled due to MySQL bug
|
||||
$this->assertEquals(400, $index1['headers']['status-code']);
|
||||
|
||||
$index2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1395,7 +1397,9 @@ trait DatabasesBase
|
||||
'type' => 'key',
|
||||
'attributes' => ['integers'], // array attribute
|
||||
]);
|
||||
$this->assertEquals(202, $index2['headers']['status-code']);
|
||||
|
||||
// Indexes on array attributes are disabled due to MySQL bug
|
||||
$this->assertEquals(400, $index2['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Create Indexes by worker
|
||||
@@ -1409,22 +1413,32 @@ trait DatabasesBase
|
||||
]), []);
|
||||
|
||||
$this->assertIsArray($movies['body']['indexes']);
|
||||
$this->assertCount(8, $movies['body']['indexes']);
|
||||
$this->assertCount(4, $movies['body']['indexes']);
|
||||
$this->assertEquals($titleIndex['body']['key'], $movies['body']['indexes'][0]['key']);
|
||||
$this->assertEquals($releaseYearIndex['body']['key'], $movies['body']['indexes'][1]['key']);
|
||||
$this->assertEquals($releaseWithDate1['body']['key'], $movies['body']['indexes'][2]['key']);
|
||||
$this->assertEquals($releaseWithDate2['body']['key'], $movies['body']['indexes'][3]['key']);
|
||||
foreach ($movies['body']['indexes'] as $index) {
|
||||
$this->assertEquals('available', $index['status']);
|
||||
}
|
||||
|
||||
$this->assertEventually(function () use ($databaseId, $data) {
|
||||
$movies = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
foreach ($movies['body']['indexes'] as $index) {
|
||||
$this->assertEquals('available', $index['status']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, 60000, 500);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
public function testGetIndexByKeyWithLengths(array $data): void
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
@@ -1453,27 +1467,6 @@ trait DatabasesBase
|
||||
$this->assertEquals('lengthTestIndex', $index['body']['key']);
|
||||
$this->assertEquals([128, 200], $index['body']['lengths']);
|
||||
|
||||
// Test case for lengths array overriding
|
||||
// set a length for an array attribute, it should get overriden with Database::ARRAY_INDEX_LENGTH
|
||||
$create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'lengthOverrideTestIndex',
|
||||
'type' => 'key',
|
||||
'attributes' => ['actors'],
|
||||
'lengths' => [120]
|
||||
]);
|
||||
$this->assertEquals(202, $create['headers']['status-code']);
|
||||
|
||||
$index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthOverrideTestIndex", [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]);
|
||||
$this->assertEquals([Database::ARRAY_INDEX_LENGTH], $index['body']['lengths']);
|
||||
|
||||
// Test case for count of lengths greater than attributes (should throw 400)
|
||||
$create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [
|
||||
'content-type' => 'application/json',
|
||||
@@ -1515,8 +1508,8 @@ trait DatabasesBase
|
||||
$this->assertEquals(400, $create['headers']['status-code']);
|
||||
}
|
||||
/**
|
||||
* @depends testCreateIndexes
|
||||
*/
|
||||
* @depends testCreateIndexes
|
||||
*/
|
||||
public function testListIndexes(array $data): void
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
@@ -1985,6 +1978,190 @@ trait DatabasesBase
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(2, $documents['body']['total']);
|
||||
|
||||
// test without passing permissions
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2000
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
|
||||
$document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
|
||||
$deleteResponse = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $deleteResponse['headers']['status-code']);
|
||||
|
||||
if ($this->getSide() === 'client') {
|
||||
// Skipped on server side: Creating a document with no permissions results in an empty permissions array, whereas on client side it assigns permissions to the current user
|
||||
|
||||
// test without passing permissions
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2000
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
$this->assertCount(3, $document['body']['$permissions']);
|
||||
$permissionsCreated = $document['body']['$permissions'];
|
||||
// checking the default created permission
|
||||
$defaultPermission = [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id']))
|
||||
];
|
||||
// ignoring the order of the permission and checking the permissions
|
||||
$this->assertEqualsCanonicalizing($defaultPermission, $permissionsCreated);
|
||||
|
||||
$document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
|
||||
// updating the created doc
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2002
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
$this->assertEquals(2002, $document['body']['releaseYear']);
|
||||
$this->assertCount(3, $document['body']['$permissions']);
|
||||
$this->assertEquals($permissionsCreated, $document['body']['$permissions']);
|
||||
|
||||
// removing the delete permission
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2002
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::update(Role::user($this->getUser()['$id']))
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
$this->assertEquals(2002, $document['body']['releaseYear']);
|
||||
$this->assertCount(1, $document['body']['$permissions']);
|
||||
|
||||
$deleteResponse = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(401, $deleteResponse['headers']['status-code']);
|
||||
|
||||
// giving the delete permission
|
||||
$document = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Thor: Ragnarok',
|
||||
'releaseYear' => 2002
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id']))
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Thor: Ragnarok', $document['body']['title']);
|
||||
$this->assertEquals(2002, $document['body']['releaseYear']);
|
||||
$this->assertCount(2, $document['body']['$permissions']);
|
||||
|
||||
$deleteResponse = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $deleteResponse['headers']['status-code']);
|
||||
|
||||
// upsertion for the related document without passing permissions
|
||||
// data should get added
|
||||
$newPersonId = ID::unique();
|
||||
$personNoPerm = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents/' . $newPersonId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'library' => [
|
||||
'$id' => 'library3',
|
||||
'libraryName' => 'Library 3',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals('Library 3', $personNoPerm['body']['library']['libraryName']);
|
||||
$this->assertCount(3, $personNoPerm['body']['library']['$permissions']);
|
||||
$this->assertCount(3, $personNoPerm['body']['$permissions']);
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['fullName', 'library.*'])->toString()
|
||||
],
|
||||
]);
|
||||
$this->assertGreaterThanOrEqual(1, $documents['body']['total']);
|
||||
$documentsDetails = $documents['body']['documents'];
|
||||
foreach ($documentsDetails as $doc) {
|
||||
$this->assertCount(3, $doc['$permissions']);
|
||||
}
|
||||
$found = false;
|
||||
foreach ($documents['body']['documents'] as $doc) {
|
||||
if (isset($doc['library']['libraryName']) && $doc['library']['libraryName'] === 'Library 3') {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found, 'Library 3 should be present in the upserted documents.');
|
||||
|
||||
// Fetch the related library and assert on its permissions (should be default/inherited)
|
||||
$library3 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $library['body']['$id'] . '/documents/library3', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $library3['headers']['status-code']);
|
||||
$this->assertEquals('Library 3', $library3['body']['libraryName']);
|
||||
$this->assertArrayHasKey('$permissions', $library3['body']);
|
||||
$this->assertCount(3, $library3['body']['$permissions']);
|
||||
$this->assertNotEmpty($library3['body']['$permissions']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2079,7 +2256,6 @@ trait DatabasesBase
|
||||
return ['documents' => $documents['body']['documents'], 'databaseId' => $databaseId];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @depends testListDocuments
|
||||
*/
|
||||
@@ -2830,7 +3006,7 @@ trait DatabasesBase
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testInvalidDocumentStructure()
|
||||
public function testInvalidDocumentStructure(): void
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -3693,7 +3869,7 @@ trait DatabasesBase
|
||||
$this->assertCount(1, $documentsUser2['body']['documents']);
|
||||
}
|
||||
|
||||
public function testEnforceCollectionPermissions()
|
||||
public function testEnforceCollectionPermissions(): void
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -4627,7 +4803,11 @@ trait DatabasesBase
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $personCollection . '/documents/' . $person2['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'libraries.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertArrayNotHasKey('$collection', $response['body']);
|
||||
@@ -4637,7 +4817,11 @@ trait DatabasesBase
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $libraryCollection . '/documents/library11', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['person_one_to_many.$id'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertArrayHasKey('person_one_to_many', $response['body']);
|
||||
@@ -4787,7 +4971,11 @@ trait DatabasesBase
|
||||
$album = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $albums['body']['$id'] . '/documents/album1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'artist.name', 'artist.$permissions'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $album['headers']['status-code']);
|
||||
$this->assertEquals('album1', $album['body']['$id']);
|
||||
@@ -4799,7 +4987,11 @@ trait DatabasesBase
|
||||
$artist = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $artists['body']['$id'] . '/documents/' . $album['body']['artist']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'albums.$id', 'albums.name', 'albums.$permissions'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $artist['headers']['status-code']);
|
||||
$this->assertEquals('Artist 1', $artist['body']['name']);
|
||||
@@ -4940,7 +5132,11 @@ trait DatabasesBase
|
||||
$sport = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $sports['body']['$id'] . '/documents/sport1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'players.name', 'players.$permissions'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $sport['headers']['status-code']);
|
||||
$this->assertEquals('sport1', $sport['body']['$id']);
|
||||
@@ -4954,7 +5150,11 @@ trait DatabasesBase
|
||||
$player = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $players['body']['$id'] . '/documents/' . $sport['body']['players'][0]['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'sports.$id', 'sports.name', 'sports.$permissions'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $player['headers']['status-code']);
|
||||
$this->assertEquals('Player 1', $player['body']['name']);
|
||||
@@ -4982,6 +5182,7 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::isNotNull('$id')->toString(),
|
||||
Query::select(['*', 'libraries.*'])->toString(),
|
||||
Query::startsWith('fullName', 'Stevie')->toString(),
|
||||
Query::endsWith('fullName', 'Wonder')->toString(),
|
||||
Query::between('$createdAt', '1975-12-06', '2050-12-01')->toString(),
|
||||
@@ -5343,7 +5544,7 @@ trait DatabasesBase
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'longtext' => file_get_contents(__DIR__ . '/../../../resources/longtext.txt'),
|
||||
'longtext' => file_get_contents(__DIR__ . '../../../../../resources/longtext.txt'),
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
@@ -5571,7 +5772,7 @@ trait DatabasesBase
|
||||
]), ['min' => 7]);
|
||||
$this->assertEquals(400, $err['headers']['status-code']);
|
||||
|
||||
// Test type error on non-numeric attribut
|
||||
// Test type error on non-numeric attribute
|
||||
$typeErr = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
@@ -224,7 +224,7 @@ class DatabasesConsoleClientTest extends Scope
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(11, count($response['body']));
|
||||
$this->assertEquals(15, count($response['body']));
|
||||
$this->assertEquals('24h', $response['body']['range']);
|
||||
$this->assertIsNumeric($response['body']['documentsTotal']);
|
||||
$this->assertIsNumeric($response['body']['collectionsTotal']);
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
+67
-12
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Tests\E2E\Client;
|
||||
@@ -1470,9 +1470,24 @@ class DatabasesCustomServerTest extends Scope
|
||||
$this->assertCount(64, $collection['body']['attributes']);
|
||||
$this->assertCount(0, $collection['body']['indexes']);
|
||||
|
||||
foreach ($collection['body']['attributes'] as $attribute) {
|
||||
$this->assertEquals('available', $attribute['status'], 'attribute: ' . $attribute['key']);
|
||||
}
|
||||
$this->assertEventually(function () use ($databaseId, $collectionId) {
|
||||
$collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
foreach ($collection['body']['attributes'] ?? [] as $attribute) {
|
||||
$this->assertEquals(
|
||||
'available',
|
||||
$attribute['status'],
|
||||
'attribute: ' . $attribute['key']
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, 60000, 500);
|
||||
|
||||
|
||||
// Test indexLimit = 64
|
||||
// MariaDB, MySQL, and MongoDB create 6 indexes per new collection
|
||||
@@ -3650,7 +3665,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
$this->assertEquals(400, $doc3['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function createRelationshipCollections()
|
||||
public function createRelationshipCollections(): void
|
||||
{
|
||||
// Prepare the database with collections and relationships
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
@@ -3699,7 +3714,7 @@ class DatabasesCustomServerTest extends Scope
|
||||
\sleep(2);
|
||||
}
|
||||
|
||||
public function cleanupRelationshipCollection()
|
||||
public function cleanupRelationshipCollection(): void
|
||||
{
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/database1', [
|
||||
'content-type' => 'application/json',
|
||||
@@ -3779,7 +3794,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('new_level_2', $newDocument['body']);
|
||||
$this->assertEquals(1, count($newDocument['body']['new_level_2']));
|
||||
@@ -3889,7 +3908,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('new_level_2', $newDocument['body']);
|
||||
$this->assertNotEmpty($newDocument['body']['new_level_2']);
|
||||
@@ -3999,7 +4022,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('new_level_2', $newDocument['body']);
|
||||
$this->assertNotEmpty($newDocument['body']['new_level_2']);
|
||||
@@ -4010,7 +4037,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('level1', $level2Document['body']);
|
||||
$this->assertNotEmpty($level2Document['body']['level1']);
|
||||
@@ -4109,7 +4140,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['new_level_2.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('new_level_2', $newDocument['body']);
|
||||
$this->assertNotEmpty($newDocument['body']['new_level_2']);
|
||||
@@ -4120,7 +4155,11 @@ class DatabasesCustomServerTest extends Scope
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
]), [
|
||||
'queries' => [
|
||||
Query::select(['*', 'level1.*'])->toString()
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('level1', $level2Document['body']);
|
||||
$this->assertNotEmpty($level2Document['body']['level1']);
|
||||
@@ -4465,6 +4504,14 @@ class DatabasesCustomServerTest extends Scope
|
||||
|
||||
$createBulkDocuments();
|
||||
|
||||
/**
|
||||
* Wait for database to purge cache...
|
||||
*
|
||||
* This test specifically failed on 1.6.x response format,
|
||||
* could be due to the slow or overworked machine, but being safe here!
|
||||
*/
|
||||
sleep(5);
|
||||
|
||||
// TEST: Update all documents
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -4483,6 +4530,14 @@ class DatabasesCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(10, $response['body']['documents']);
|
||||
|
||||
/**
|
||||
* Wait for database to purge cache...
|
||||
*
|
||||
* This test specifically failed on 1.6.x response format,
|
||||
* could be due to the slow or overworked machine, but being safe here!
|
||||
*/
|
||||
sleep(5);
|
||||
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
|
||||
trait DatabasesPermissionsScope
|
||||
{
|
||||
public array $users = [];
|
||||
public array $teams = [];
|
||||
|
||||
public function createUser(string $id, string $email, string $password = 'test123!'): array
|
||||
{
|
||||
$user = $this->client->call(Client::METHOD_POST, '/account', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-dev-key' => $this->getProject()['devKey'] ?? '',
|
||||
], [
|
||||
'userId' => $id,
|
||||
'email' => $email,
|
||||
'password' => $password
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$session = $session['cookies']['a_session_' . $this->getProject()['$id']];
|
||||
|
||||
$user = [
|
||||
'$id' => $user['body']['$id'],
|
||||
'email' => $user['body']['email'],
|
||||
'session' => $session,
|
||||
];
|
||||
$this->users[$id] = $user;
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function getCreatedUser(string $id): array
|
||||
{
|
||||
return $this->users[$id] ?? [];
|
||||
}
|
||||
|
||||
public function createTeam(string $id, string $name): array
|
||||
{
|
||||
$team = $this->client->call(Client::METHOD_POST, '/teams', $this->getServerHeader(), [
|
||||
'teamId' => $id,
|
||||
'name' => $name
|
||||
]);
|
||||
$this->teams[$id] = $team['body'];
|
||||
|
||||
return $team['body'];
|
||||
}
|
||||
|
||||
public function addToTeam(string $user, string $team, array $roles = []): array
|
||||
{
|
||||
$membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team . '/memberships', $this->getServerHeader(), [
|
||||
'teamId' => $team,
|
||||
'email' => $this->getCreatedUser($user)['email'],
|
||||
'roles' => $roles,
|
||||
'url' => 'http://localhost:5000/join-us#title'
|
||||
]);
|
||||
|
||||
return [
|
||||
'user' => $membership['body']['userId'],
|
||||
'membership' => $membership['body']['$id']
|
||||
];
|
||||
}
|
||||
|
||||
public function getServerHeader(): array
|
||||
{
|
||||
return [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
];
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Databases;
|
||||
namespace Tests\E2E\Services\Databases\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
@@ -21,8 +21,8 @@ class FunctionsConsoleClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -39,8 +39,8 @@ class FunctionsConsoleClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Failure',
|
||||
'execute' => ['some-random-string'],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $function2['headers']['status-code']);
|
||||
@@ -453,7 +453,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
{
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Variable E2E Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -481,7 +481,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -502,7 +502,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Download Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -511,7 +511,7 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -52,8 +52,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -84,13 +83,12 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -107,8 +105,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
|
||||
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
@@ -142,10 +140,10 @@ class FunctionsCustomClientTest extends Scope
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test guest execution',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'vars' => [
|
||||
'funcKey1' => 'funcValue1',
|
||||
'funcKey2' => 'funcValue2',
|
||||
@@ -154,8 +152,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -175,8 +172,8 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
@@ -193,15 +190,14 @@ class FunctionsCustomClientTest extends Scope
|
||||
*/
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test synchronous execution',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-fn'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -214,11 +210,11 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||
$this->assertEquals('Test', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals('Test synchronous execution', $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals('PHP', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('8.0', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('Node.js', $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals('22', $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals(APP_VERSION_STABLE, $output['APPWRITE_VERSION']);
|
||||
$this->assertEquals(System::getEnv('_APP_REGION', 'default'), $output['APPWRITE_REGION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
@@ -239,12 +235,12 @@ class FunctionsCustomClientTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js'
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -340,7 +336,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'limit' => 5,
|
||||
'offset' => 2,
|
||||
'useCases' => ['databases'],
|
||||
'runtimes' => ['node-16.0']
|
||||
'runtimes' => ['node-22']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
@@ -352,7 +348,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
$this->assertContains($template['useCases'][0], ['databases']);
|
||||
}
|
||||
|
||||
$this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
$this->assertContains('node-22', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
||||
@@ -35,7 +35,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'specification' => $specifications['body']['specifications'][0]['slug']
|
||||
]);
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
@@ -50,7 +50,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'specification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
@@ -64,8 +64,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'buckets.*.create',
|
||||
'buckets.*.delete',
|
||||
@@ -79,7 +79,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
$this->assertEquals('Test', $function['body']['name']);
|
||||
$this->assertEquals('php-8.0', $function['body']['runtime']);
|
||||
$this->assertEquals('node-22', $function['body']['runtime']);
|
||||
$this->assertEquals(true, $dateValidator->isValid($function['body']['$createdAt']));
|
||||
$this->assertEquals(true, $dateValidator->isValid($function['body']['$updatedAt']));
|
||||
$this->assertEquals('', $function['body']['deploymentId']);
|
||||
@@ -180,7 +180,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// Test search runtime
|
||||
$functions = $this->listFunctions([
|
||||
'search' => 'php-8.0'
|
||||
'search' => 'node-22'
|
||||
]);
|
||||
|
||||
$this->assertEquals($functions['headers']['status-code'], 200);
|
||||
@@ -193,8 +193,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test 2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'buckets.*.create',
|
||||
'buckets.*.delete',
|
||||
@@ -286,8 +286,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
],
|
||||
'schedule' => '0 0 1 1 *',
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
|
||||
$dateValidator = new DatetimeValidator();
|
||||
@@ -322,8 +322,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -338,8 +338,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
'x-sdk-language' => 'cli',
|
||||
], [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -363,7 +362,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $starterTemplate['headers']['status-code']);
|
||||
|
||||
$phpRuntime = array_values(array_filter($starterTemplate['body']['runtimes'], function ($runtime) {
|
||||
return $runtime['name'] === 'php-8.0';
|
||||
return $runtime['name'] === 'node-22';
|
||||
}))[0];
|
||||
|
||||
// If this fails, the template has variables, and this test needs to be updated
|
||||
@@ -373,7 +372,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
[
|
||||
'functionId' => ID::unique(),
|
||||
'name' => $starterTemplate['body']['name'],
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'execute' => $starterTemplate['body']['permissions'],
|
||||
'entrypoint' => $phpRuntime['entrypoint'],
|
||||
'events' => $starterTemplate['body']['events'],
|
||||
@@ -514,7 +513,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -522,7 +521,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
$this->assertEquals('waiting', $deployment['body']['status']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
|
||||
|
||||
$deploymentIdActive = $deployment['body']['$id'] ?? '';
|
||||
|
||||
@@ -533,7 +532,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
}, 50000, 500);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'false'
|
||||
]);
|
||||
|
||||
@@ -573,7 +572,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'false'
|
||||
]);
|
||||
|
||||
@@ -582,7 +581,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
@@ -595,12 +594,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('canceled', $deployment['body']['status']);
|
||||
|
||||
/**
|
||||
* Build worker still runs the build.
|
||||
* 30s sleep gives worker enough time to finish build.
|
||||
* After build finished, it should still be canceled, not ready.
|
||||
*/
|
||||
\sleep(30);
|
||||
// Ensures worker got eventually aware of cancellation and reacted properly
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']);
|
||||
});
|
||||
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
|
||||
@@ -618,7 +617,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
*/
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$folder = 'php-large';
|
||||
$folder = 'large';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
@@ -633,13 +632,13 @@ class FunctionsCustomServerTest extends Scope
|
||||
];
|
||||
$id = '';
|
||||
while (!feof($handle)) {
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz');
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-fx.tar.gz');
|
||||
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
|
||||
if (!empty($id)) {
|
||||
$headers['x-appwrite-id'] = $id;
|
||||
}
|
||||
$largeTag = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge($headers, $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => $curlFile,
|
||||
'activate' => true,
|
||||
'commands' => 'cp blue.mp4 copy.mp4 && ls -al' // +7MB buildSize
|
||||
@@ -652,7 +651,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(202, $largeTag['headers']['status-code']);
|
||||
$this->assertNotEmpty($largeTag['body']['$id']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($largeTag['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $largeTag['body']['entrypoint']);
|
||||
$this->assertEquals('index.js', $largeTag['body']['entrypoint']);
|
||||
$this->assertGreaterThan(1024 * 1024 * 5, $largeTag['body']['sourceSize']); // ~7MB video file
|
||||
$this->assertLessThan(1024 * 1024 * 10, $largeTag['body']['sourceSize']); // ~7MB video file
|
||||
|
||||
@@ -903,8 +902,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString($data['deploymentId'], $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Test1', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('http', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('PHP', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('8.0', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Node.js', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('22', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Global Variable Value', $execution['body']['responseBody']);
|
||||
// $this->assertStringContainsString('êä', $execution['body']['responseBody']); // tests unknown utf-8 chars
|
||||
$this->assertNotEmpty($execution['body']['errors']);
|
||||
@@ -1017,8 +1016,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertStringContainsString('Test1', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('http', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('PHP', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('8.0', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('Node.js', $execution['body']['responseBody']);
|
||||
$this->assertStringContainsString('22', $execution['body']['responseBody']);
|
||||
// $this->assertStringContainsString('êä', $execution['body']['response']); // tests unknown utf-8 chars
|
||||
$this->assertLessThan(1.500, $execution['body']['duration']);
|
||||
|
||||
@@ -1120,8 +1119,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => Specification::S_1VCPU_1GB,
|
||||
]);
|
||||
|
||||
@@ -1148,8 +1147,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => Specification::S_1VCPU_512MB,
|
||||
]);
|
||||
|
||||
@@ -1178,8 +1177,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'specification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
@@ -1236,9 +1235,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test php-8.0',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test timeout execution',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [],
|
||||
'schedule' => '',
|
||||
'timeout' => 5, // Should timeout after 5 seconds
|
||||
@@ -1280,12 +1279,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
*/
|
||||
public function provideCustomExecutions(): array
|
||||
{
|
||||
// Most disabled to keep tests fast
|
||||
return [
|
||||
['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'],
|
||||
['folder' => 'node', 'name' => 'node-18.0', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '18.0'],
|
||||
['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'],
|
||||
['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'],
|
||||
// Swift and Dart disabled on purpose, as it's very slow.
|
||||
// ['folder' => 'php-fn', 'name' => 'php-8.0', 'entrypoint' => 'index.php', 'runtimeName' => 'PHP', 'runtimeVersion' => '8.0'],
|
||||
['folder' => 'node', 'name' => 'node-22', 'entrypoint' => 'index.js', 'runtimeName' => 'Node.js', 'runtimeVersion' => '22'],
|
||||
// ['folder' => 'python', 'name' => 'python-3.9', 'entrypoint' => 'main.py', 'runtimeName' => 'Python', 'runtimeVersion' => '3.9'],
|
||||
// ['folder' => 'ruby', 'name' => 'ruby-3.1', 'entrypoint' => 'main.rb', 'runtimeName' => 'Ruby', 'runtimeVersion' => '3.1'],
|
||||
// [ 'folder' => 'dart', 'name' => 'dart-2.15', 'entrypoint' => 'main.dart', 'runtimeName' => 'Dart', 'runtimeVersion' => '2.15' ],
|
||||
// [ 'folder' => 'swift', 'name' => 'swift-5.5', 'entrypoint' => 'index.swift', 'runtimeName' => 'Swift', 'runtimeVersion' => '5.5' ],
|
||||
];
|
||||
@@ -1324,27 +1323,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
]);
|
||||
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'body' => 'foobar',
|
||||
'async' => 'false'
|
||||
]);
|
||||
|
||||
$output = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
$this->assertEquals($functionId, $output['APPWRITE_FUNCTION_ID']);
|
||||
$this->assertEquals('Test ' . $name, $output['APPWRITE_FUNCTION_NAME']);
|
||||
$this->assertEquals($deploymentId, $output['APPWRITE_FUNCTION_DEPLOYMENT']);
|
||||
$this->assertEquals('http', $output['APPWRITE_FUNCTION_TRIGGER']);
|
||||
$this->assertEquals($runtimeName, $output['APPWRITE_FUNCTION_RUNTIME_NAME']);
|
||||
$this->assertEquals($runtimeVersion, $output['APPWRITE_FUNCTION_RUNTIME_VERSION']);
|
||||
$this->assertEquals('', $output['APPWRITE_FUNCTION_EVENT']);
|
||||
$this->assertEquals('foobar', $output['APPWRITE_FUNCTION_DATA']);
|
||||
$this->assertEquals('variable', $output['CUSTOM_VARIABLE']);
|
||||
$this->assertEmpty($output['APPWRITE_FUNCTION_USER_ID']);
|
||||
$this->assertEmpty($output['APPWRITE_FUNCTION_JWT']);
|
||||
$this->assertEquals($this->getProject()['$id'], $output['APPWRITE_FUNCTION_PROJECT_ID']);
|
||||
$this->assertStringContainsString('Amazing Function Log', $execution['body']['logs']);
|
||||
$this->assertEquals('OK', $execution['body']['responseBody']);
|
||||
$this->assertEmpty($execution['body']['logs']);
|
||||
$this->assertEmpty($execution['body']['errors']);
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
@@ -1357,7 +1343,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertCount(1, $executions['body']['executions']);
|
||||
$this->assertEquals($executions['body']['executions'][0]['$id'], $executionId);
|
||||
$this->assertEquals($executions['body']['executions'][0]['trigger'], 'http');
|
||||
$this->assertStringContainsString('Amazing Function Log', $executions['body']['executions'][0]['logs']);
|
||||
$this->assertEquals(200, $executions['body']['executions'][0]['responseStatusCode']);
|
||||
$this->assertEmpty($executions['body']['executions'][0]['responseBody']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
@@ -1366,15 +1353,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-response'),
|
||||
'code' => $this->packageFunction('binary-response'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1415,15 +1401,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-request'),
|
||||
'code' => $this->packageFunction('binary-request'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1461,49 +1446,6 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testv2Function()
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP V2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'events' => [],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
$variable = $this->client->call(Client::METHOD_PATCH, '/mock/functions-v2', [
|
||||
'content-type' => 'application/json',
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], [
|
||||
'functionId' => $functionId
|
||||
]);
|
||||
$this->assertEquals(204, $variable['headers']['status-code']);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-v2'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$execution = $this->createExecution($functionId, [
|
||||
'body' => 'foobar',
|
||||
'async' => 'false'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $execution['headers']['status-code']);
|
||||
$this->assertEquals('completed', $execution['body']['status']);
|
||||
$this->assertEquals(200, $execution['body']['responseStatusCode']);
|
||||
|
||||
$output = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals(true, $output['v2Woks']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testGetRuntimes()
|
||||
{
|
||||
$runtimes = $this->client->call(Client::METHOD_GET, '/functions/runtimes', array_merge([
|
||||
@@ -1531,17 +1473,16 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Event executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Event executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-event'),
|
||||
'code' => $this->packageFunction('event-handler'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1584,17 +1525,16 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Scopes executions',
|
||||
'commands' => 'bash setup.sh && composer install',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Scopes executions',
|
||||
'commands' => 'bash setup.sh && npm install',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'scopes' => ['users.read'],
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-scopes'),
|
||||
'code' => $this->packageFunction('dynamic-api-key'),
|
||||
'activate' => true,
|
||||
]);
|
||||
|
||||
@@ -1643,16 +1583,15 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Cookie executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Cookie executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
]);
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
@@ -1685,9 +1624,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Cookie executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Cookie executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1695,8 +1634,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1743,9 +1681,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1753,8 +1691,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-response'),
|
||||
'code' => $this->packageFunction('binary-response'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1778,9 +1715,9 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test PHP Binary executions',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'name' => 'Test Binary executions',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1788,8 +1725,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php-binary-request'),
|
||||
'code' => $this->packageFunction('binary-request'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1816,8 +1752,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
]);
|
||||
|
||||
@@ -1851,8 +1787,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function1Id = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1860,8 +1796,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$function2Id = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test2',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'execute' => ['any']
|
||||
]);
|
||||
@@ -1892,7 +1828,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Logging Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -1908,7 +1844,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -1985,7 +1921,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
// Check if the function specifications are correctly set in builds
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Specification Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
@@ -2001,7 +1937,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2027,7 +1963,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Duplicate Deployment Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => ''
|
||||
@@ -2035,7 +1971,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
$deploymentId1 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId1);
|
||||
@@ -2045,7 +1981,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString('APPWRITE_FUNCTION_ID', $execution['body']['responseBody']);
|
||||
|
||||
$function = $this->updateFunction($functionId, [
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Duplicate Deployment Test',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => 'rm index.js && mv maintenance.js index.js'
|
||||
@@ -2089,13 +2025,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'php-8.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Re-activate Test',
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
]);
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
|
||||
$function = $this->getFunction($functionId);
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertArrayHasKey('latestDeploymentId', $function['body']);
|
||||
@@ -2106,7 +2041,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEmpty($function['body']['latestDeploymentStatus']);
|
||||
|
||||
$deploymentId1 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php-cookie'),
|
||||
'code' => $this->packageFunction('cookies'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId1);
|
||||
@@ -2124,7 +2059,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertStringContainsString('cookieValue', $execution['body']['responseBody']);
|
||||
|
||||
$deploymentId2 = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId2);
|
||||
@@ -2192,8 +2127,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => 'cd non-existing-directory',
|
||||
'execute' => ['any']
|
||||
@@ -2203,8 +2138,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2221,8 +2155,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
// canceled deployment
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -2250,8 +2183,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => '',
|
||||
'execute' => ['users']
|
||||
@@ -2262,7 +2195,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
@@ -2284,8 +2217,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => '',
|
||||
'execute' => ['any']
|
||||
@@ -2296,7 +2229,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
@@ -25,8 +25,8 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -36,8 +36,7 @@ class FunctionsScheduleTest extends Scope
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -77,14 +76,13 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -179,15 +177,14 @@ class FunctionsScheduleTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::user($this->getUser()['$id'])->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
'logging' => true,
|
||||
]);
|
||||
|
||||
$this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
|
||||
@@ -13,12 +13,28 @@ trait Base
|
||||
public static string $GET_DATABASE = 'get_database';
|
||||
public static string $UPDATE_DATABASE = 'update_database';
|
||||
public static string $DELETE_DATABASE = 'delete_database';
|
||||
|
||||
// Collections
|
||||
public static string $CREATE_COLLECTION = 'create_collection';
|
||||
public static string $GET_COLLECTION = 'get_collection';
|
||||
public static string $GET_COLLECTIONS = 'list_collections';
|
||||
public static string $UPDATE_COLLECTION = 'update_collection';
|
||||
public static string $DELETE_COLLECTION = 'delete_collection';
|
||||
|
||||
// Grid databases
|
||||
public static string $GRIDS_CREATE_DATABASE = 'grids_create_database';
|
||||
public static string $GRIDS_GET_DATABASES = 'grids_get_databases';
|
||||
public static string $GRIDS_GET_DATABASE = 'grids_get_database';
|
||||
public static string $GRIDS_UPDATE_DATABASE = 'grids_update_database';
|
||||
public static string $GRIDS_DELETE_DATABASE = 'grids_delete_database';
|
||||
|
||||
// Grid tables
|
||||
public static string $CREATE_TABLE = 'create_table';
|
||||
public static string $GET_TABLE = 'get_table';
|
||||
public static string $GET_TABLES = 'list_tables';
|
||||
public static string $UPDATE_TABLE = 'update_table';
|
||||
public static string $DELETE_TABLE = 'delete_table';
|
||||
|
||||
// Attributes
|
||||
public static string $CREATE_STRING_ATTRIBUTE = 'create_string_attribute';
|
||||
public static string $CREATE_INTEGER_ATTRIBUTE = 'create_integer_attribute';
|
||||
@@ -45,18 +61,74 @@ trait Base
|
||||
public static string $GET_ATTRIBUTES = 'get_attributes';
|
||||
public static string $GET_ATTRIBUTE = 'get_attribute';
|
||||
public static string $DELETE_ATTRIBUTE = 'delete_attribute';
|
||||
// Indexes
|
||||
public static string $CREATE_INDEX = 'create_index';
|
||||
public static string $GET_INDEXES = 'get_indexes';
|
||||
public static string $GET_INDEX = 'get_index';
|
||||
public static string $DELETE_INDEX = 'delete_index';
|
||||
|
||||
// Grids columns
|
||||
public static string $CREATE_STRING_COLUMN = 'create_string_column';
|
||||
public static string $CREATE_INTEGER_COLUMN = 'create_integer_column';
|
||||
public static string $CREATE_FLOAT_COLUMN = 'create_float_column';
|
||||
public static string $CREATE_BOOLEAN_COLUMN = 'create_boolean_column';
|
||||
public static string $CREATE_URL_COLUMN = 'create_url_column';
|
||||
public static string $CREATE_EMAIL_COLUMN = 'create_email_column';
|
||||
public static string $CREATE_IP_COLUMN = 'create_ip_column';
|
||||
public static string $CREATE_ENUM_COLUMN = 'create_enum_column';
|
||||
public static string $CREATE_DATETIME_COLUMN = 'create_datetime_column';
|
||||
|
||||
public static string $CREATE_RELATIONSHIP_COLUMN = 'create_relationship_column';
|
||||
public static string $UPDATE_STRING_COLUMN = 'update_string_column';
|
||||
public static string $UPDATE_INTEGER_COLUMN = 'update_integer_column';
|
||||
public static string $UPDATE_FLOAT_COLUMN = 'update_float_column';
|
||||
public static string $UPDATE_BOOLEAN_COLUMN = 'update_boolean_column';
|
||||
public static string $UPDATE_URL_COLUMN = 'update_url_column';
|
||||
public static string $UPDATE_EMAIL_COLUMN = 'update_email_column';
|
||||
public static string $UPDATE_IP_COLUMN = 'update_ip_column';
|
||||
public static string $UPDATE_ENUM_COLUMN = 'update_enum_column';
|
||||
public static string $UPDATE_DATETIME_COLUMN = 'update_datetime_column';
|
||||
|
||||
public static string $UPDATE_RELATIONSHIP_COLUMN = 'update_relationship_column';
|
||||
public static string $GET_COLUMNS = 'get_columns';
|
||||
public static string $GET_COLUMN = 'get_column';
|
||||
public static string $DELETE_COLUMN = 'delete_column';
|
||||
|
||||
// Attribute Indexes
|
||||
public static string $CREATE_INDEX = 'create_attribute_index';
|
||||
public static string $GET_INDEXES = 'get_attribute_indexes';
|
||||
public static string $GET_INDEX = 'get_attribute_index';
|
||||
public static string $DELETE_INDEX = 'delete_attribute_index';
|
||||
|
||||
// Grid column indexes
|
||||
public static string $CREATE_COLUMN_INDEX = 'create_column_index';
|
||||
public static string $GET_COLUMN_INDEXES = 'get_column_indexes';
|
||||
public static string $GET_COLUMN_INDEX = 'get_column_index';
|
||||
public static string $DELETE_COLUMN_INDEX = 'delete_column_index';
|
||||
|
||||
// Documents
|
||||
public static string $CREATE_DOCUMENT = 'create_document_rest';
|
||||
public static string $GET_DOCUMENTS = 'list_documents';
|
||||
public static string $GET_DOCUMENT = 'get_document';
|
||||
public static string $UPDATE_DOCUMENT = 'update_document';
|
||||
public static string $UPSERT_DOCUMENT = 'upsert_document';
|
||||
public static string $DELETE_DOCUMENT = 'delete_document';
|
||||
|
||||
// Documents - Bulk APIs
|
||||
public static string $CREATE_DOCUMENTS = 'create_documents_rest';
|
||||
public static string $UPDATE_DOCUMENTS = 'update_documents';
|
||||
public static string $UPSERT_DOCUMENTS = 'upsert_documents';
|
||||
public static string $DELETE_DOCUMENTS = 'delete_documents';
|
||||
|
||||
// Grid rows
|
||||
public static string $CREATE_ROW = 'create_row_rest';
|
||||
public static string $GET_ROWS = 'list_rows';
|
||||
public static string $GET_ROW = 'get_row';
|
||||
public static string $UPDATE_ROW = 'update_row';
|
||||
public static string $UPSERT_ROW = 'upsert_row';
|
||||
public static string $DELETE_ROW = 'delete_row';
|
||||
|
||||
// Grid rows - Bulk APIs
|
||||
public static string $CREATE_ROWS = 'create_rows_rest';
|
||||
public static string $UPDATE_ROWS = 'update_rows';
|
||||
public static string $UPSERT_ROWS = 'upsert_rows';
|
||||
public static string $DELETE_ROWS = 'delete_rows';
|
||||
|
||||
// Custom Entities
|
||||
public static string $CREATE_CUSTOM_ENTITY = 'create_custom_entity';
|
||||
public static string $GET_CUSTOM_ENTITIES = 'get_custom_entities';
|
||||
@@ -255,9 +327,10 @@ trait Base
|
||||
public static string $UPDATE_PUSH_NOTIFICATION = 'update_push_notification';
|
||||
|
||||
// Complex queries
|
||||
public static string $COMPLEX_QUERY = 'complex_query';
|
||||
public static string $COMPLEX_QUERY_TABLE = 'complex_query_table';
|
||||
public static string $COMPLEX_QUERY_COLLECTION = 'complex_query_collection';
|
||||
|
||||
// Fragments
|
||||
// Attribute Fragments
|
||||
public static string $FRAGMENT_ATTRIBUTES = '
|
||||
fragment attributeProperties on Attributes {
|
||||
... on AttributeString {
|
||||
@@ -332,6 +405,81 @@ trait Base
|
||||
}
|
||||
';
|
||||
|
||||
// Column Fragments
|
||||
public static string $FRAGMENT_COLUMNS = '
|
||||
fragment columnProperties on Columns {
|
||||
... on ColumnString {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
size
|
||||
}
|
||||
... on ColumnInteger {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
intDefault: default
|
||||
intMin: min
|
||||
intMax: max
|
||||
}
|
||||
... on ColumnFloat {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
floatDefault: default
|
||||
floatMin: min
|
||||
floatMax: max
|
||||
}
|
||||
... on ColumnBoolean {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
boolDefault: default
|
||||
}
|
||||
... on ColumnUrl {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
}
|
||||
... on ColumnEmail {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
}
|
||||
... on ColumnIp {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
}
|
||||
... on ColumnEnum {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
elements
|
||||
}
|
||||
... on ColumnDatetime {
|
||||
key
|
||||
required
|
||||
array
|
||||
status
|
||||
default
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
public static string $FRAGMENT_HASH_OPTIONS = '
|
||||
fragment options on HashOptions {
|
||||
... on AlgoArgon2 {
|
||||
@@ -393,6 +541,43 @@ trait Base
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GRIDS_CREATE_DATABASE:
|
||||
return 'mutation gridsCreateDatabase($databaseId: String!, $name: String!) {
|
||||
gridsCreateDatabase(databaseId: $databaseId, name: $name) {
|
||||
_id
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$GRIDS_GET_DATABASES:
|
||||
return 'query gridsListDatabases {
|
||||
gridsListDatabases {
|
||||
total
|
||||
databases {
|
||||
_id
|
||||
name
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$GRIDS_GET_DATABASE:
|
||||
return 'query gridsGetDatabase($databaseId: String!) {
|
||||
gridsGetDatabase(databaseId: $databaseId) {
|
||||
_id
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$GRIDS_UPDATE_DATABASE:
|
||||
return 'mutation gridsUpdateDatabase($databaseId: String!, $name: String!) {
|
||||
gridsUpdateDatabase(databaseId: $databaseId, name: $name) {
|
||||
_id
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$GRIDS_DELETE_DATABASE:
|
||||
return 'mutation gridsDeleteDatabase($databaseId: String!) {
|
||||
gridsDeleteDatabase(databaseId: $databaseId) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GET_COLLECTION:
|
||||
return 'query getCollection($databaseId: String!, $collectionId: String!) {
|
||||
databasesGetCollection(databaseId: $databaseId, collectionId: $collectionId) {
|
||||
@@ -438,6 +623,51 @@ trait Base
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GET_TABLE:
|
||||
return 'query gridsGetTable($databaseId: String!, $tableId: String!) {
|
||||
gridsGetTable(databaseId: $databaseId, tableId: $tableId) {
|
||||
_id
|
||||
_permissions
|
||||
rowSecurity
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$GET_TABLES:
|
||||
return 'query gridsListTables($databaseId: String!) {
|
||||
gridsListTables(databaseId: $databaseId) {
|
||||
total
|
||||
tables {
|
||||
_id
|
||||
_permissions
|
||||
rowSecurity
|
||||
name
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_TABLE:
|
||||
return 'mutation gridsCreateTable($databaseId: String!, $tableId: String!, $name: String!, $rowSecurity: Boolean!, $permissions: [String!]!) {
|
||||
gridsCreateTable(databaseId: $databaseId, tableId: $tableId, name: $name, rowSecurity: $rowSecurity, permissions: $permissions) {
|
||||
_id
|
||||
_permissions
|
||||
rowSecurity
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_TABLE:
|
||||
return 'mutation gridsUpdateTable($databaseId: String!, $tableId: String!, $name: String!, $rowSecurity: Boolean!, $permissions: [String!], $enabled: Boolean) {
|
||||
gridsUpdateTable(databaseId: $databaseId, tableId: $tableId, name: $name, rowSecurity: $rowSecurity, permissions: $permissions, enabled: $enabled) {
|
||||
_id
|
||||
_permissions
|
||||
rowSecurity
|
||||
name
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_TABLE:
|
||||
return 'mutation gridsDeleteTable($databaseId: String!, $tableId: String!) {
|
||||
gridsDeleteTable(databaseId: $databaseId, tableId: $tableId) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_STRING_ATTRIBUTE:
|
||||
return 'mutation createStringAttribute($databaseId: String!, $collectionId: String!, $key: String!, $size: Int!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
databasesCreateStringAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, size: $size, required: $required, default: $default, array: $array) {
|
||||
@@ -614,6 +844,182 @@ trait Base
|
||||
onDelete
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_STRING_COLUMN:
|
||||
return 'mutation createStringColumn($databaseId: String!, $tableId: String!, $key: String!, $size: Int!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateStringColumn(databaseId: $databaseId, tableId: $tableId, key: $key, size: $size, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_INTEGER_COLUMN:
|
||||
return 'mutation createIntegerColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $min: Int, $max: Int, $default: Int, $array: Boolean){
|
||||
gridsCreateIntegerColumn(databaseId: $databaseId, tableId: $tableId, key: $key, min: $min, max: $max, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
min
|
||||
max
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_FLOAT_COLUMN:
|
||||
return 'mutation createFloatColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $min: Float, $max: Float, $default: Float, $array: Boolean){
|
||||
gridsCreateFloatColumn(databaseId: $databaseId, tableId: $tableId, key: $key, min: $min, max: $max, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
min
|
||||
max
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_BOOLEAN_COLUMN:
|
||||
return 'mutation createBooleanColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: Boolean, $array: Boolean){
|
||||
gridsCreateBooleanColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_URL_COLUMN:
|
||||
return 'mutation createUrlColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateUrlColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_EMAIL_COLUMN:
|
||||
return 'mutation createEmailColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateEmailColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_IP_COLUMN:
|
||||
return 'mutation createIpColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateIpColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_ENUM_COLUMN:
|
||||
return 'mutation createEnumColumn($databaseId: String!, $tableId: String!, $key: String!, $elements: [String!]!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateEnumColumn(databaseId: $databaseId, tableId: $tableId, key: $key, elements: $elements, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
elements
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_DATETIME_COLUMN:
|
||||
return 'mutation createDatetimeColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String, $array: Boolean){
|
||||
gridsCreateDatetimeColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default, array: $array) {
|
||||
key
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_RELATIONSHIP_COLUMN:
|
||||
return 'mutation createRelationshipColumn($databaseId: String!, $tableId: String!, $relatedTableId: String!, $type: String!, $twoWay: Boolean, $key: String, $twoWayKey: String, $onDelete: String){
|
||||
gridsCreateRelationshipColumn(databaseId: $databaseId, tableId: $tableId, relatedTableId: $relatedTableId, type: $type, twoWay: $twoWay, key: $key, twoWayKey: $twoWayKey, onDelete: $onDelete) {
|
||||
relatedTable
|
||||
relationType
|
||||
twoWay
|
||||
key
|
||||
twoWayKey
|
||||
onDelete
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_STRING_COLUMN:
|
||||
return 'mutation updateStringColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||
gridsUpdateStringColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_INTEGER_COLUMN:
|
||||
return 'mutation updateIntegerColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $min: Int!, $max: Int!, $default: Int){
|
||||
gridsUpdateIntegerColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, min: $min, max: $max, default: $default) {
|
||||
required
|
||||
min
|
||||
max
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_FLOAT_COLUMN:
|
||||
return 'mutation updateFloatColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $min: Float!, $max: Float!, $default: Float){
|
||||
gridsUpdateFloatColumn(databaseId: $databaseId, tableId: $tableId, key: $key, min: $min, max: $max, required: $required, default: $default) {
|
||||
required
|
||||
min
|
||||
max
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_BOOLEAN_COLUMN:
|
||||
return 'mutation updateBooleanColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: Boolean){
|
||||
gridsUpdateBooleanColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_URL_COLUMN:
|
||||
return 'mutation updateUrlColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||
gridsUpdateUrlColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_EMAIL_COLUMN:
|
||||
return 'mutation updateEmailColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||
gridsUpdateEmailColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_IP_COLUMN:
|
||||
return 'mutation updateIpColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||
gridsUpdateIpColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_ENUM_COLUMN:
|
||||
return 'mutation updateEnumColumn($databaseId: String!, $tableId: String!, $key: String!, $elements: [String!]!, $required: Boolean!, $default: String){
|
||||
gridsUpdateEnumColumn(databaseId: $databaseId, tableId: $tableId, key: $key, elements: $elements, required: $required, default: $default) {
|
||||
elements
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_DATETIME_COLUMN:
|
||||
return 'mutation updateDatetimeColumn($databaseId: String!, $tableId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||
gridsUpdateDatetimeColumn(databaseId: $databaseId, tableId: $tableId, key: $key, required: $required, default: $default) {
|
||||
required
|
||||
default
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_RELATIONSHIP_COLUMN:
|
||||
return 'mutation updateRelationshipColumn($databaseId: String!, $tableId: String!, $key: String!, $onDelete: String){
|
||||
gridsUpdateRelationshipColumn(databaseId: $databaseId, tableId: $tableId, key: $key, onDelete: $onDelete) {
|
||||
relatedTable
|
||||
relationType
|
||||
twoWay
|
||||
key
|
||||
twoWayKey
|
||||
onDelete
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_INDEX:
|
||||
return 'mutation createIndex($databaseId: String!, $collectionId: String!, $key: String!, $type: String!, $attributes: [String!]!, $orders: [String!]){
|
||||
databasesCreateIndex(databaseId: $databaseId, collectionId: $collectionId, key: $key, type: $type, attributes: $attributes, orders: $orders) {
|
||||
@@ -647,6 +1053,39 @@ trait Base
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_COLUMN_INDEX:
|
||||
return 'mutation createIndex($databaseId: String!, $tableId: String!, $key: String!, $type: String!, $columns: [String!]!, $orders: [String!]){
|
||||
gridsCreateIndex(databaseId: $databaseId, tableId: $tableId, key: $key, type: $type, columns: $columns, orders: $orders) {
|
||||
key
|
||||
type
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GET_COLUMN_INDEXES:
|
||||
return 'query listIndexes($databaseId: String!, $tableId: String!) {
|
||||
gridsListIndexes(databaseId: $databaseId, tableId: $tableId) {
|
||||
total
|
||||
indexes {
|
||||
key
|
||||
type
|
||||
status
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$GET_COLUMN_INDEX:
|
||||
return 'query getIndex($databaseId: String!, $tableId: String!, $key: String!) {
|
||||
gridsGetIndex(databaseId: $databaseId, tableId: $tableId, key: $key) {
|
||||
key
|
||||
type
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_COLUMN_INDEX:
|
||||
return 'mutation deleteIndex($databaseId: String!, $tableId: String!, $key: String!) {
|
||||
gridsDeleteIndex(databaseId: $databaseId, tableId: $tableId, key: $key) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GET_ATTRIBUTES:
|
||||
return 'query listAttributes($databaseId: String!, $collectionId: String!) {
|
||||
databasesListAttributes(databaseId: $databaseId, collectionId: $collectionId) {
|
||||
@@ -668,6 +1107,28 @@ trait Base
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$GET_COLUMNS:
|
||||
return 'query listColumns($databaseId: String!, $tableId: String!) {
|
||||
gridsListColumns(databaseId: $databaseId, tableId: $tableId) {
|
||||
total
|
||||
columns {
|
||||
...columnProperties
|
||||
}
|
||||
}
|
||||
}' . PHP_EOL . self::$FRAGMENT_COLUMNS;
|
||||
case self::$GET_COLUMN:
|
||||
return 'query getColumn($databaseId: String!, $tableId: String!, $key: String!) {
|
||||
gridsGetColumn(databaseId: $databaseId, tableId: $tableId, key: $key) {
|
||||
...columnProperties
|
||||
}
|
||||
}' . PHP_EOL . self::$FRAGMENT_COLUMNS;
|
||||
case self::$DELETE_COLUMN:
|
||||
return 'mutation deleteColumn($databaseId: String!, $tableId: String!, $key: String!) {
|
||||
gridsDeleteColumn(databaseId: $databaseId, tableId: $tableId, key: $key) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
|
||||
case self::$GET_DOCUMENT:
|
||||
return 'query getDocument($databaseId: String!, $collectionId: String!, $documentId: String!) {
|
||||
databasesGetDocument(databaseId: $databaseId, collectionId: $collectionId, documentId: $documentId) {
|
||||
@@ -697,6 +1158,58 @@ trait Base
|
||||
_permissions
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_DOCUMENTS:
|
||||
return 'mutation createDocuments($databaseId: String!, $collectionId: String!, $documents: [Json!]!) {
|
||||
databasesCreateDocuments(databaseId: $databaseId, collectionId: $collectionId, documents: $documents) {
|
||||
documents {
|
||||
_id
|
||||
_collectionId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_ROWS:
|
||||
return 'mutation createRows($databaseId: String!, $tableId: String!, $rows: [Json!]!) {
|
||||
gridsCreateRows(databaseId: $databaseId, tableId: $tableId, rows: $rows) {
|
||||
rows {
|
||||
_id
|
||||
_tableId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$GET_ROW:
|
||||
return 'query getRow($databaseId: String!, $tableId: String!, $rowId: String!) {
|
||||
gridsGetRow(databaseId: $databaseId, tableId: $tableId, rowId: $rowId) {
|
||||
_id
|
||||
_tableId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}';
|
||||
case self::$GET_ROWS:
|
||||
return 'query listRows($databaseId: String!, $tableId: String!, $queries: [String!] = []) {
|
||||
gridsListRows(databaseId: $databaseId, tableId: $tableId, queries: $queries) {
|
||||
total
|
||||
rows {
|
||||
_id
|
||||
_databaseId
|
||||
_tableId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_ROW:
|
||||
return 'mutation createRow($databaseId: String!, $tableId: String!, $rowId: String!, $data: Json!, $permissions: [String!]) {
|
||||
gridsCreateRow(databaseId: $databaseId, tableId: $tableId, rowId: $rowId, data: $data, permissions: $permissions) {
|
||||
_id
|
||||
_tableId
|
||||
_permissions
|
||||
}
|
||||
}';
|
||||
case self::$CREATE_CUSTOM_ENTITY:
|
||||
return 'mutation createActor($name: String!, $age: Int!, $alive: Boolean!, $salary: Float, $email: String!, $role: String!, $dob: String!, $ip: String, $url: String){
|
||||
actorsCreate(name: $name, age: $age, alive: $alive, salary: $salary, email: $email, role: $role, dob: $dob, ip: $ip, url: $url) {
|
||||
@@ -764,13 +1277,120 @@ trait Base
|
||||
data
|
||||
}
|
||||
}';
|
||||
case self::$UPSERT_DOCUMENT:
|
||||
return 'mutation upsertDocument($databaseId: String!, $collectionId: String!, $documentId: String!, $data: Json!, $permissions: [String!] = []) {
|
||||
databasesUpsertDocument(databaseId: $databaseId, collectionId: $collectionId, documentId: $documentId, data: $data, permissions: $permissions) {
|
||||
_id
|
||||
_databaseId
|
||||
_collectionId
|
||||
data
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_DOCUMENTS:
|
||||
return 'mutation updateDocuments($databaseId: String!, $collectionId: String!, $data: Json!, $queries: [String!]) {
|
||||
databasesUpdateDocuments(databaseId: $databaseId, collectionId: $collectionId, data: $data, queries: $queries) {
|
||||
total
|
||||
documents {
|
||||
_id
|
||||
_databaseId
|
||||
_collectionId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$UPSERT_DOCUMENTS:
|
||||
return 'mutation upsertDocuments($databaseId: String!, $collectionId: String!, $documents: [Json!]!) {
|
||||
databasesUpsertDocuments(databaseId: $databaseId, collectionId: $collectionId, documents: $documents) {
|
||||
total
|
||||
documents {
|
||||
_id
|
||||
_databaseId
|
||||
_collectionId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_DOCUMENTS:
|
||||
return 'mutation deleteDocuments($databaseId: String!, $collectionId: String!, $queries: [String!] = []) {
|
||||
databasesDeleteDocuments(databaseId: $databaseId, collectionId: $collectionId, queries: $queries) {
|
||||
total
|
||||
documents {
|
||||
_id
|
||||
_databaseId
|
||||
_collectionId
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_DOCUMENT:
|
||||
return 'mutation deleteDocument($databaseId: String!, $collectionId: String!, $documentId: String!){
|
||||
databasesDeleteDocument(databaseId: $databaseId, collectionId: $collectionId, documentId: $documentId) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
|
||||
case self::$UPDATE_ROW:
|
||||
return 'mutation updateRow($databaseId: String!, $tableId: String!, $rowId: String!, $data: Json!, $permissions: [String!]) {
|
||||
gridsUpdateRow(databaseId: $databaseId, tableId: $tableId, rowId: $rowId, data: $data, permissions: $permissions) {
|
||||
_id
|
||||
_tableId
|
||||
data
|
||||
}
|
||||
}';
|
||||
case self::$UPSERT_ROW:
|
||||
return 'mutation upsertRow($databaseId: String!, $tableId: String!, $rowId: String!, $data: Json!, $permissions: [String!] = []) {
|
||||
gridsUpsertRow(databaseId: $databaseId, tableId: $tableId, rowId: $rowId, data: $data, permissions: $permissions) {
|
||||
_id
|
||||
_databaseId
|
||||
_tableId
|
||||
data
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_ROW:
|
||||
return 'mutation deleteRow($databaseId: String!, $tableId: String!, $rowId: String!) {
|
||||
gridsDeleteRow(databaseId: $databaseId, tableId: $tableId, rowId: $rowId) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$UPDATE_ROWS:
|
||||
return 'mutation updateRows($databaseId: String!, $tableId: String!, $data: Json!, $queries: [String!]) {
|
||||
gridsUpdateRows(databaseId: $databaseId, tableId: $tableId, data: $data, queries: $queries) {
|
||||
total
|
||||
rows {
|
||||
_id
|
||||
_databaseId
|
||||
_tableId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$UPSERT_ROWS:
|
||||
return 'mutation upsertRows($databaseId: String!, $tableId: String!, $rows: [Json!]!) {
|
||||
gridsUpsertRows(databaseId: $databaseId, tableId: $tableId, rows: $rows) {
|
||||
total
|
||||
rows {
|
||||
_id
|
||||
_databaseId
|
||||
_tableId
|
||||
_permissions
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$DELETE_ROWS:
|
||||
return 'mutation deleteRows($databaseId: String!, $tableId: String!, $queries: [String!] = []) {
|
||||
gridsDeleteRows(databaseId: $databaseId, tableId: $tableId, queries: $queries) {
|
||||
total
|
||||
rows {
|
||||
_id
|
||||
_databaseId
|
||||
_tableId
|
||||
data
|
||||
}
|
||||
}
|
||||
}';
|
||||
case self::$GET_USER:
|
||||
return 'query getUser($userId : String!) {
|
||||
usersGet(userId : $userId) {
|
||||
@@ -2245,7 +2865,7 @@ trait Base
|
||||
status
|
||||
}
|
||||
}';
|
||||
case self::$COMPLEX_QUERY:
|
||||
case self::$COMPLEX_QUERY_COLLECTION:
|
||||
return 'mutation complex($databaseId: String!, $databaseName: String!, $collectionId: String!, $collectionName: String!, $documentSecurity: Boolean!, $collectionPermissions: [String!]!) {
|
||||
databasesCreate(databaseId: $databaseId, name: $databaseName) {
|
||||
_id
|
||||
@@ -2256,7 +2876,7 @@ trait Base
|
||||
_createdAt
|
||||
_updatedAt
|
||||
_permissions
|
||||
_databaseId
|
||||
databaseId
|
||||
name
|
||||
documentSecurity
|
||||
attributes {
|
||||
@@ -2488,6 +3108,249 @@ trait Base
|
||||
}
|
||||
}
|
||||
}' . PHP_EOL . self::$FRAGMENT_ATTRIBUTES;
|
||||
case self::$COMPLEX_QUERY_TABLE:
|
||||
return 'mutation complex($databaseId: String!, $databaseName: String!, $tableId: String!, $tableName: String!, $rowSecurity: Boolean!, $tablePermissions: [String!]!) {
|
||||
databasesCreate(databaseId: $databaseId, name: $databaseName) {
|
||||
_id
|
||||
name
|
||||
}
|
||||
gridsCreate(databaseId: $databaseId, tableId: $tableId, name: $tableName, rowSecurity: $rowSecurity, permissions: $tablePermissions) {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
_permissions
|
||||
databaseId
|
||||
name
|
||||
rowSecurity
|
||||
columns {
|
||||
...columnProperties
|
||||
}
|
||||
indexes {
|
||||
key
|
||||
type
|
||||
status
|
||||
}
|
||||
}
|
||||
gridsCreateStringColumn(databaseId: $databaseId, tableId: $tableId, key: "name", size: 255, required: true) {
|
||||
key
|
||||
type
|
||||
status
|
||||
size
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
gridsCreateIntegerColumn(databaseId: $databaseId, tableId: $tableId, key: "age", min: 0, max: 150, required: true) {
|
||||
key
|
||||
type
|
||||
status
|
||||
required
|
||||
min
|
||||
max
|
||||
default
|
||||
array
|
||||
}
|
||||
gridsCreateBooleanColumn(databaseId: $databaseId, tableId: $tableId, key: "alive", required: false, default: true) {
|
||||
key
|
||||
type
|
||||
status
|
||||
required
|
||||
default
|
||||
array
|
||||
}
|
||||
user1: usersCreate(userId: "unique()", email: "test1@appwrite.io", password: "password", name: "Tester 1") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user2: usersCreate(userId: "unique()", email: "test2@appwrite.io", password: "password", name: "Tester 2") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user3: usersCreate(userId: "unique()", email: "test3@appwrite.io", password: "password", name: "Tester 3") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user4: usersCreate(userId: "unique()", email: "test4@appwrite.io", password: "password", name: "Tester 4") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user5: usersCreate(userId: "unique()", email: "test5@appwrite.io", password: "password", name: "Tester 5") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user6: usersCreate(userId: "unique()", email: "test6@appwrite.io", password: "password", name: "Tester 6") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user7: usersCreate(userId: "unique()", email: "test7@appwrite.io", password: "password", name: "Tester 7") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user8: usersCreate(userId: "unique()", email: "test8@appwrite.io", password: "password", name: "Tester 8") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user9: usersCreate(userId: "unique()", email: "test9@appwrite.io", password: "password", name: "Tester 9") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user10: usersCreate(userId: "unique()", email: "test10@appwrite.io", password: "password", name: "Tester 10") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user11: usersCreate(userId: "unique()", email: "test11@appwrite.io", password: "password", name: "Tester 11") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
user12: usersCreate(userId: "unique()", email: "test12@appwrite.io", password: "password", name: "Tester 5") {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
phone
|
||||
email
|
||||
status
|
||||
registration
|
||||
passwordUpdate
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
}
|
||||
}' . PHP_EOL . self::$FRAGMENT_COLUMNS;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Invalid query type');
|
||||
|
||||
@@ -26,8 +26,8 @@ class FunctionsClientTest extends Scope
|
||||
'variables' => [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Function',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'execute' => [Role::any()->toString()],
|
||||
]
|
||||
];
|
||||
@@ -96,7 +96,7 @@ class FunctionsClientTest extends Scope
|
||||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => $this->packageFunction('php')
|
||||
'code' => $this->packageFunction('basic')
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
|
||||
@@ -26,8 +26,8 @@ class FunctionsServerTest extends Scope
|
||||
'variables' => [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Function',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.js',
|
||||
'runtime' => 'node-22',
|
||||
'execute' => [Role::any()->toString()],
|
||||
]
|
||||
];
|
||||
@@ -95,7 +95,7 @@ class FunctionsServerTest extends Scope
|
||||
'map' => \json_encode([
|
||||
'code' => ["variables.code"]
|
||||
]),
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
];
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\System\System;
|
||||
|
||||
class AbuseTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
use Base;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (System::getEnv('_APP_OPTIONS_ABUSE') === 'disabled') {
|
||||
$this->markTestSkipped('Abuse is not enabled.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testRateLimitEnforced()
|
||||
{
|
||||
$data = $this->createTable();
|
||||
$databaseId = $data['databaseId'];
|
||||
$tableId = $data['tableId'];
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_ROW);
|
||||
$max = 120;
|
||||
|
||||
for ($i = 0; $i <= $max + 1; $i++) {
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'John Doe',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $gqlPayload);
|
||||
|
||||
if ($i < $max) {
|
||||
$this->assertArrayNotHasKey('errors', $response['body']);
|
||||
} else {
|
||||
$this->assertArrayHasKey('errors', $response['body']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function testComplexQueryBlocked()
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$COMPLEX_QUERY_TABLE);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'userId' => 'user',
|
||||
'email' => 'user@appwrite.io',
|
||||
'password' => 'password',
|
||||
'databaseId' => 'database',
|
||||
'databaseName' => 'database',
|
||||
'tableId' => 'table',
|
||||
'tableName' => 'table',
|
||||
'tablePermissions' => [
|
||||
Permission::read(Role::users()),
|
||||
Permission::create(Role::users()),
|
||||
Permission::update(Role::users()),
|
||||
Permission::delete(Role::users()),
|
||||
],
|
||||
'rowSecurity' => false,
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $graphQLPayload);
|
||||
|
||||
$max = System::getEnv('_APP_GRAPHQL_MAX_QUERY_COMPLEXITY', 250);
|
||||
|
||||
$this->assertEquals('Max query complexity should be ' . $max . ' but got 259.', $response['body']['errors'][0]['message']);
|
||||
}
|
||||
|
||||
public function testTooManyQueriesBlocked()
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$maxQueries = System::getEnv('_APP_GRAPHQL_MAX_QUERIES', 10);
|
||||
|
||||
$query = [];
|
||||
for ($i = 0; $i <= $maxQueries + 1; $i++) {
|
||||
$query[] = ['query' => $this->getQuery(self::$LIST_COUNTRIES)];
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $query);
|
||||
|
||||
$this->assertEquals('Too many queries.', $response['body']['message']);
|
||||
}
|
||||
|
||||
private function createTable(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_DATABASE);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => 'actors',
|
||||
'name' => 'AbuseDatabase',
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$databaseId = $response['body']['data']['databasesCreate']['_id'];
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_TABLE);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => 'actors',
|
||||
'name' => 'Actors',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$tableId = $response['body']['data']['gridsCreateTable']['_id'];
|
||||
|
||||
$query = $this->getQuery(self::$CREATE_STRING_COLUMN);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]
|
||||
];
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
sleep(2);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class AuthTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
use Base;
|
||||
|
||||
private array $account1;
|
||||
private array $account2;
|
||||
|
||||
private string $token1;
|
||||
private string $token2;
|
||||
|
||||
private array $database;
|
||||
private array $table;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_ACCOUNT);
|
||||
|
||||
$email1 = 'test' . \rand() . '@test.com';
|
||||
$email2 = 'test' . \rand() . '@test.com';
|
||||
|
||||
// Create account 1
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'userId' => ID::unique(),
|
||||
'name' => 'User Name',
|
||||
'email' => $email1,
|
||||
'password' => 'password',
|
||||
],
|
||||
];
|
||||
$this->account1 = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $graphQLPayload);
|
||||
|
||||
// Create account 2
|
||||
$graphQLPayload['variables']['userId'] = ID::unique();
|
||||
$graphQLPayload['variables']['email'] = $email2;
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $graphQLPayload);
|
||||
|
||||
// Create session 1
|
||||
$query = $this->getQuery(self::$CREATE_ACCOUNT_SESSION);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'email' => $email1,
|
||||
'password' => 'password',
|
||||
]
|
||||
];
|
||||
$session1 = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $graphQLPayload);
|
||||
|
||||
$this->token1 = $session1['cookies']['a_session_' . $projectId];
|
||||
|
||||
// Create session 2
|
||||
$graphQLPayload['variables']['email'] = $email2;
|
||||
|
||||
$session2 = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $graphQLPayload);
|
||||
|
||||
$this->token2 = $session2['cookies']['a_session_' . $projectId];
|
||||
|
||||
// Create database
|
||||
$query = $this->getQuery(self::$CREATE_DATABASE);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
]
|
||||
];
|
||||
$this->database = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
// Create table
|
||||
$query = $this->getQuery(self::$CREATE_TABLE);
|
||||
$userId = $this->account1['body']['data']['accountCreate']['_id'];
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($userId))
|
||||
]
|
||||
]
|
||||
];
|
||||
$this->table = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
// Create string attribute
|
||||
$query = $this->getQuery(self::$CREATE_STRING_COLUMN);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => $this->table['body']['data']['gridsCreateTable']['_id'],
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]
|
||||
];
|
||||
$this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
public function testInvalidAuth()
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
// Create row as account 1
|
||||
$query = $this->getQuery(self::$CREATE_ROW);
|
||||
$userId = $this->account1['body']['data']['accountCreate']['_id'];
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => $this->table['body']['data']['gridsCreateTable']['_id'],
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'John Doe',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
]
|
||||
]
|
||||
];
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $this->token1,
|
||||
], $gqlPayload);
|
||||
|
||||
// Try to read as account 1
|
||||
$query = $this->getQuery(self::$GET_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => $this->table['body']['data']['gridsCreateTable']['_id'],
|
||||
'rowId' => $row['body']['data']['gridsCreateRow']['_id'],
|
||||
]
|
||||
];
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $this->token1,
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertIsArray($row['body']['data']['gridsGetRow']);
|
||||
$this->assertArrayNotHasKey('errors', $row['body']);
|
||||
|
||||
// Try to read as account 2
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $this->token2,
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertArrayHasKey('errors', $row['body']);
|
||||
$this->assertEquals('Row with the requested ID could not be found.', $row['body']['errors'][0]['message']);
|
||||
}
|
||||
|
||||
public function testValidAuth()
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
// Create row as account 1
|
||||
$query = $this->getQuery(self::$CREATE_ROW);
|
||||
$userId = $this->account1['body']['data']['accountCreate']['_id'];
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => $this->table['body']['data']['gridsCreateTable']['_id'],
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'John Doe',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
],
|
||||
]
|
||||
];
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $this->token1,
|
||||
], $gqlPayload);
|
||||
|
||||
// Try to delete as account 1
|
||||
$query = $this->getQuery(self::$DELETE_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $this->database['body']['data']['databasesCreate']['_id'],
|
||||
'tableId' => $this->table['body']['data']['gridsCreateTable']['_id'],
|
||||
'rowId' => $row['body']['data']['gridsCreateRow']['_id'],
|
||||
]
|
||||
];
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $this->token1,
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertIsNotArray($row['body']);
|
||||
$this->assertEquals(204, $row['headers']['status-code']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,589 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL\Grids;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class DatabaseClientTest extends Scope
|
||||
{
|
||||
use ProjectCustom;
|
||||
use SideClient;
|
||||
use Base;
|
||||
|
||||
public function testCreateDatabase(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$GRIDS_CREATE_DATABASE);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
]
|
||||
];
|
||||
|
||||
$database = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertIsArray($database['body']['data']);
|
||||
$this->assertArrayNotHasKey('errors', $database['body']);
|
||||
$database = $database['body']['data']['gridsCreateDatabase'];
|
||||
$this->assertEquals('Actors', $database['name']);
|
||||
|
||||
return $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateDatabase
|
||||
*/
|
||||
public function testCreateTable($database): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_TABLE);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $database['_id'],
|
||||
'tableId' => 'actors',
|
||||
'name' => 'Actors',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::users()),
|
||||
Permission::update(Role::users()),
|
||||
Permission::delete(Role::users()),
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$table = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertIsArray($table['body']['data']);
|
||||
$this->assertArrayNotHasKey('errors', $table['body']);
|
||||
$table = $table['body']['data']['gridsCreateTable'];
|
||||
$this->assertEquals('Actors', $table['name']);
|
||||
|
||||
return [
|
||||
'table' => $table,
|
||||
'database' => $database,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
public function testCreateStringColumn($data): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_STRING_COLUMN);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]
|
||||
];
|
||||
|
||||
$column = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $column['body']);
|
||||
$this->assertIsArray($column['body']['data']);
|
||||
$this->assertIsArray($column['body']['data']['gridsCreateStringColumn']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
public function testCreateIntegerColumn($data): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_INTEGER_COLUMN);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'key' => 'age',
|
||||
'min' => 18,
|
||||
'max' => 150,
|
||||
'required' => true,
|
||||
]
|
||||
];
|
||||
|
||||
$column = $this->client->call(Client::METHOD_POST, '/graphql', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $column['body']);
|
||||
$this->assertIsArray($column['body']['data']);
|
||||
$this->assertIsArray($column['body']['data']['gridsCreateIntegerColumn']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateStringColumn
|
||||
* @depends testCreateIntegerColumn
|
||||
*/
|
||||
public function testCreateRow($data): array
|
||||
{
|
||||
sleep(1);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'John Doe',
|
||||
'age' => 35,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $row['body']);
|
||||
$this->assertIsArray($row['body']['data']);
|
||||
|
||||
$row = $row['body']['data']['gridsCreateRow'];
|
||||
$this->assertIsArray($row);
|
||||
|
||||
return [
|
||||
'database' => $data['database'],
|
||||
'table' => $data['table'],
|
||||
'row' => $row,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testGetRows($data): void
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$GET_ROWS);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
]
|
||||
];
|
||||
|
||||
$rows = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $rows['body']);
|
||||
$this->assertIsArray($rows['body']['data']);
|
||||
$this->assertIsArray($rows['body']['data']['gridsListRows']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateRow
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testGetDocument($data): void
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$GET_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'rowId' => $data['row']['_id'],
|
||||
]
|
||||
];
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $row['body']);
|
||||
$this->assertIsArray($row['body']['data']);
|
||||
$this->assertIsArray($row['body']['data']['gridsGetRow']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateRow
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testUpdateRow($data): void
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$UPDATE_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'rowId' => $data['row']['_id'],
|
||||
'data' => [
|
||||
'name' => 'New Row Name',
|
||||
],
|
||||
]
|
||||
];
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertArrayNotHasKey('errors', $row['body']);
|
||||
$this->assertIsArray($row['body']['data']);
|
||||
$row = $row['body']['data']['gridsUpdateRow'];
|
||||
$this->assertIsArray($row);
|
||||
|
||||
$this->assertStringContainsString('New Row Name', $row['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateRow
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testDeleteRow($data): void
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$DELETE_ROW);
|
||||
$gqlPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['database']['_id'],
|
||||
'tableId' => $data['table']['_id'],
|
||||
'rowId' => $data['row']['_id'],
|
||||
]
|
||||
];
|
||||
|
||||
$row = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertIsNotArray($row['body']);
|
||||
$this->assertEquals(204, $row['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testBulkCreate(): array
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$projectId = $project['$id'];
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $project['apiKey'],
|
||||
];
|
||||
|
||||
// Step 1: Create database
|
||||
$query = $this->getQuery(self::$GRIDS_CREATE_DATABASE);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => 'bulk',
|
||||
'name' => 'Bulk',
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$databaseId = $res['body']['data']['gridsCreateDatabase']['_id'];
|
||||
|
||||
// Step 2: Create table
|
||||
$query = $this->getQuery(self::$CREATE_TABLE);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => 'operations',
|
||||
'name' => 'Operations',
|
||||
'rowSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$tableId = $res['body']['data']['gridsCreateTable']['_id'];
|
||||
|
||||
// Step 3: Create column
|
||||
$query = $this->getQuery(self::$CREATE_STRING_COLUMN);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
sleep(1);
|
||||
|
||||
// Step 4: Create rows
|
||||
$query = $this->getQuery(self::$CREATE_ROWS);
|
||||
$rows = [];
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$rows[] = ['$id' => 'row' . $i, 'name' => 'Row #' . $i];
|
||||
}
|
||||
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
'rows' => $rows,
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['gridsCreateRows']['rows']);
|
||||
|
||||
return compact('databaseId', 'tableId', 'projectId');
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkCreate
|
||||
*/
|
||||
public function testBulkUpdate(array $data): array
|
||||
{
|
||||
$userId = $this->getUser()['$id'];
|
||||
$permissions = [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
];
|
||||
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
// Step 1: Bulk update rows
|
||||
$query = $this->getQuery(self::$UPDATE_ROWS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
'data' => [
|
||||
'name' => 'Rows Updated',
|
||||
'$permissions' => $permissions,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['gridsUpdateRows']['rows']);
|
||||
|
||||
// Step 2: Fetch and validate updated rows
|
||||
$query = $this->getQuery(self::$GET_ROWS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
'queries' => [Query::equal('name', ['Rows Updated'])->toString()],
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertEquals(200, $res['headers']['status-code']);
|
||||
|
||||
$fetched = $res['body']['data']['gridsListRows'];
|
||||
$this->assertEquals(10, $fetched['total']);
|
||||
|
||||
foreach ($fetched['rows'] as $row) {
|
||||
$this->assertEquals($permissions, $row['_permissions']);
|
||||
$this->assertEquals($data['tableId'], $row['_tableId']);
|
||||
$this->assertEquals($data['databaseId'], $row['_databaseId']);
|
||||
$this->assertEquals('Rows Updated', json_decode($row['data'], true)['name']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkCreate
|
||||
*/
|
||||
public function testBulkUpsert(array $data): array
|
||||
{
|
||||
$userId = $this->getUser()['$id'];
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
$permissions = [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
];
|
||||
|
||||
// Step 1: Mutate row 10 and add row 11
|
||||
$query = $this->getQuery(self::$UPSERT_ROWS);
|
||||
$upsertPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
'rows' => [
|
||||
[
|
||||
'$id' => 'row10',
|
||||
'name' => 'Row #1000',
|
||||
],
|
||||
[
|
||||
'name' => 'Row #11',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $upsertPayload);
|
||||
$this->assertArrayNotHasKey('errors', $response['body']);
|
||||
|
||||
$rows = $response['body']['data']['gridsUpsertRows']['rows'];
|
||||
$this->assertCount(2, $rows);
|
||||
|
||||
$rowMap = [];
|
||||
foreach ($rows as $row) {
|
||||
$decoded = json_decode($row['data'], true);
|
||||
$rowMap[$decoded['name']] = $decoded;
|
||||
}
|
||||
|
||||
$this->assertArrayHasKey('Row #1000', $rowMap);
|
||||
$this->assertArrayHasKey('Row #11', $rowMap);
|
||||
|
||||
// Step 2: Fetch all rows and confirm count is now 11
|
||||
$query = $this->getQuery(self::$GET_ROWS);
|
||||
$fetchPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $fetchPayload);
|
||||
$this->assertEquals(200, $res['headers']['status-code']);
|
||||
|
||||
$fetched = $res['body']['data']['gridsListRows'];
|
||||
$this->assertEquals(11, $fetched['total']);
|
||||
|
||||
// Step 3: Upsert row with new permissions using `tablesUpsertRow`
|
||||
$query = $this->getQuery(self::$UPSERT_ROW);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
'rowId' => 'row10',
|
||||
'data' => ['name' => 'Row #10 Patched'],
|
||||
'permissions' => $permissions,
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
|
||||
$updated = $res['body']['data']['gridsUpsertRow'];
|
||||
$this->assertEquals('Row #10 Patched', json_decode($updated['data'], true)['name']);
|
||||
$this->assertEquals($data['databaseId'], $updated['_databaseId']);
|
||||
$this->assertEquals($data['tableId'], $updated['_tableId']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkUpsert
|
||||
*/
|
||||
public function testBulkDelete(array $data): array
|
||||
{
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
// Step 1: Perform bulk delete
|
||||
$query = $this->getQuery(self::$DELETE_ROWS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
|
||||
$deleted = $res['body']['data']['gridsDeleteRows']['rows'];
|
||||
$this->assertIsArray($deleted);
|
||||
$this->assertCount(11, $deleted);
|
||||
|
||||
// Step 2: Confirm deletion via refetch
|
||||
$query = $this->getQuery(self::$GET_ROWS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'tableId' => $data['tableId'],
|
||||
],
|
||||
];
|
||||
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertEquals(200, $res['headers']['status-code']);
|
||||
$this->assertEquals(0, $res['body']['data']['gridsListRows']['total']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
namespace Tests\E2E\Services\GraphQL\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
@@ -64,7 +65,7 @@ class AbuseTest extends Scope
|
||||
public function testComplexQueryBlocked()
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$COMPLEX_QUERY);
|
||||
$query = $this->getQuery(self::$COMPLEX_QUERY_COLLECTION);
|
||||
$graphQLPayload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
@@ -113,7 +114,7 @@ class AbuseTest extends Scope
|
||||
$this->assertEquals('Too many queries.', $response['body']['message']);
|
||||
}
|
||||
|
||||
private function createCollection()
|
||||
private function createCollection(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$query = $this->getQuery(self::$CREATE_DATABASE);
|
||||
+2
-1
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
namespace Tests\E2E\Services\GraphQL\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
+178
-1
@@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
namespace Tests\E2E\Services\GraphQL\Legacy;
|
||||
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
@@ -302,4 +303,180 @@ class DatabaseClientTest extends Scope
|
||||
$this->assertIsNotArray($document['body']);
|
||||
$this->assertEquals(204, $document['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testBulkCreateDocuments(): array
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$projectId = $project['$id'];
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
'x-appwrite-key' => $project['apiKey'],
|
||||
];
|
||||
|
||||
// Step 1: Create database
|
||||
$query = $this->getQuery(self::$CREATE_DATABASE);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => 'bulk',
|
||||
'name' => 'Bulk',
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$databaseId = $res['body']['data']['databasesCreate']['_id'];
|
||||
|
||||
// Step 2: Create collection
|
||||
$query = $this->getQuery(self::$CREATE_COLLECTION);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => 'operations',
|
||||
'name' => 'Operations',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$collectionId = $res['body']['data']['databasesCreateCollection']['_id'];
|
||||
|
||||
// Step 3: Create attribute
|
||||
$query = $this->getQuery(self::$CREATE_STRING_ATTRIBUTE);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
sleep(1);
|
||||
|
||||
// Step 4: Create documents
|
||||
$query = $this->getQuery(self::$CREATE_DOCUMENTS);
|
||||
$documents = [];
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$documents[] = ['$id' => 'doc' . $i, 'name' => 'Doc #' . $i];
|
||||
}
|
||||
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'documents' => $documents,
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['databasesCreateDocuments']['documents']);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'projectId' => $projectId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkCreateDocuments
|
||||
*/
|
||||
public function testBulkUpdateDocuments(array $data): array
|
||||
{
|
||||
$userId = $this->getUser()['$id'];
|
||||
$permissions = [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
];
|
||||
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
$query = $this->getQuery(self::$UPDATE_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
'data' => [
|
||||
'name' => 'Docs Updated',
|
||||
'$permissions' => $permissions,
|
||||
],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['databasesUpdateDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkUpdateDocuments
|
||||
*/
|
||||
public function testBulkUpsertDocuments(array $data): array
|
||||
{
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
// Upsert: Update one, insert one
|
||||
$query = $this->getQuery(self::$UPSERT_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
'documents' => [
|
||||
['$id' => 'doc10', 'name' => 'Doc #1000'],
|
||||
['name' => 'Doc #11'],
|
||||
],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(2, $res['body']['data']['databasesUpsertDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkUpsertDocuments
|
||||
*/
|
||||
public function testBulkDeleteDocuments(array $data): array
|
||||
{
|
||||
$headers = [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
];
|
||||
|
||||
$query = $this->getQuery(self::$DELETE_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(11, $res['body']['data']['databasesDeleteDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
+175
-1
@@ -1,12 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\GraphQL;
|
||||
namespace Tests\E2E\Services\GraphQL\Legacy;
|
||||
|
||||
use Exception;
|
||||
use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Tests\E2E\Services\GraphQL\Base;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
@@ -133,6 +134,7 @@ class DatabaseServerTest extends Scope
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
// TODO: @itznotabug - check for `encrypt` attribute in string column's response body as well!
|
||||
$this->assertArrayNotHasKey('errors', $attribute['body']);
|
||||
$this->assertIsArray($attribute['body']['data']);
|
||||
$this->assertIsArray($attribute['body']['data']['databasesCreateStringAttribute']);
|
||||
@@ -1463,4 +1465,176 @@ class DatabaseServerTest extends Scope
|
||||
$this->assertIsNotArray($database['body']);
|
||||
$this->assertEquals(204, $database['headers']['status-code']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testBulkCreateDocuments(): array
|
||||
{
|
||||
$project = $this->getProject();
|
||||
$projectId = $project['$id'];
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders());
|
||||
|
||||
// Step 1: Create database
|
||||
$query = $this->getQuery(self::$CREATE_DATABASE);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => 'bulk',
|
||||
'name' => 'Bulk',
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$databaseId = $res['body']['data']['databasesCreate']['_id'];
|
||||
|
||||
// Step 2: Create collection
|
||||
$query = $this->getQuery(self::$CREATE_COLLECTION);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => 'operations',
|
||||
'name' => 'Operations',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$collectionId = $res['body']['data']['databasesCreateCollection']['_id'];
|
||||
|
||||
// Step 3: Create attribute
|
||||
$query = $this->getQuery(self::$CREATE_STRING_ATTRIBUTE);
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
sleep(1);
|
||||
|
||||
// Step 4: Create documents
|
||||
$query = $this->getQuery(self::$CREATE_DOCUMENTS);
|
||||
$documents = [];
|
||||
for ($i = 1; $i <= 10; $i++) {
|
||||
$documents[] = ['$id' => 'doc' . $i, 'name' => 'Doc #' . $i];
|
||||
}
|
||||
|
||||
$payload['query'] = $query;
|
||||
$payload['variables'] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'documents' => $documents,
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['databasesCreateDocuments']['documents']);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'projectId' => $projectId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkCreateDocuments
|
||||
*/
|
||||
public function testBulkUpdateDocuments(array $data): array
|
||||
{
|
||||
$userId = $this->getUser()['$id'];
|
||||
$permissions = [
|
||||
Permission::read(Role::user($userId)),
|
||||
Permission::update(Role::user($userId)),
|
||||
Permission::delete(Role::user($userId)),
|
||||
];
|
||||
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
], $this->getHeaders());
|
||||
|
||||
$query = $this->getQuery(self::$UPDATE_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
'data' => [
|
||||
'name' => 'Docs Updated',
|
||||
'$permissions' => $permissions,
|
||||
],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(10, $res['body']['data']['databasesUpdateDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkUpdateDocuments
|
||||
*/
|
||||
public function testBulkUpsertDocuments(array $data): array
|
||||
{
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
], $this->getHeaders());
|
||||
|
||||
// Upsert: Update one, insert one
|
||||
$query = $this->getQuery(self::$UPSERT_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
'documents' => [
|
||||
['$id' => 'doc10', 'name' => 'Doc #1000'],
|
||||
['name' => 'Doc #11'],
|
||||
],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(2, $res['body']['data']['databasesUpsertDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testBulkUpsertDocuments
|
||||
*/
|
||||
public function testBulkDeleteDocuments(array $data): array
|
||||
{
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
], $this->getHeaders());
|
||||
|
||||
$query = $this->getQuery(self::$DELETE_DOCUMENTS);
|
||||
$payload = [
|
||||
'query' => $query,
|
||||
'variables' => [
|
||||
'databaseId' => $data['databaseId'],
|
||||
'collectionId' => $data['collectionId'],
|
||||
],
|
||||
];
|
||||
$res = $this->client->call(Client::METHOD_POST, '/graphql', $headers, $payload);
|
||||
$this->assertArrayNotHasKey('errors', $res['body']);
|
||||
$this->assertCount(11, $res['body']['data']['databasesDeleteDocuments']['documents']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Migration\Resource;
|
||||
use Utopia\Migration\Sources\Appwrite;
|
||||
use Utopia\Migration\Sources\CSV;
|
||||
|
||||
trait MigrationsBase
|
||||
{
|
||||
@@ -436,25 +435,25 @@ trait MigrationsBase
|
||||
/**
|
||||
* @depends testAppwriteMigrationDatabase
|
||||
*/
|
||||
public function testAppwriteMigrationDatabasesCollection(array $data): array
|
||||
public function testAppwriteMigrationDatabasesTable(array $data): array
|
||||
{
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [
|
||||
$table = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Test Collection',
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Test Table',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
|
||||
$collectionId = $collection['body']['$id'];
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
// Create Attribute
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [
|
||||
// Create Column
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
@@ -467,9 +466,9 @@ trait MigrationsBase
|
||||
|
||||
$this->assertEquals(202, $response['headers']['status-code']);
|
||||
|
||||
// Wait for attribute to be ready
|
||||
$this->assertEventually(function () use ($databaseId, $collectionId) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/name', [
|
||||
// Wait for column to be ready
|
||||
$this->assertEventually(function () use ($databaseId, $tableId) {
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns/name', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
@@ -482,8 +481,8 @@ trait MigrationsBase
|
||||
$result = $this->performMigrationSync([
|
||||
'resources' => [
|
||||
Resource::TYPE_DATABASE,
|
||||
Resource::TYPE_COLLECTION,
|
||||
Resource::TYPE_ATTRIBUTE,
|
||||
Resource::TYPE_TABLE,
|
||||
Resource::TYPE_COLUMN,
|
||||
],
|
||||
'endpoint' => 'http://localhost/v1',
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
@@ -491,9 +490,9 @@ trait MigrationsBase
|
||||
]);
|
||||
|
||||
$this->assertEquals('completed', $result['status']);
|
||||
$this->assertEquals([Resource::TYPE_DATABASE, Resource::TYPE_COLLECTION, Resource::TYPE_ATTRIBUTE], $result['resources']);
|
||||
$this->assertEquals([Resource::TYPE_DATABASE, Resource::TYPE_TABLE, Resource::TYPE_COLUMN], $result['resources']);
|
||||
|
||||
foreach ([Resource::TYPE_DATABASE, Resource::TYPE_COLLECTION, Resource::TYPE_ATTRIBUTE] as $resource) {
|
||||
foreach ([Resource::TYPE_DATABASE, Resource::TYPE_TABLE, Resource::TYPE_COLUMN] as $resource) {
|
||||
$this->assertArrayHasKey($resource, $result['statusCounters']);
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['error']);
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['pending']);
|
||||
@@ -502,7 +501,7 @@ trait MigrationsBase
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['warning']);
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tableId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getDestinationProject()['$id'],
|
||||
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
|
||||
@@ -511,10 +510,10 @@ trait MigrationsBase
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
|
||||
$this->assertEquals($collectionId, $response['body']['$id']);
|
||||
$this->assertEquals('Test Collection', $response['body']['name']);
|
||||
$this->assertEquals($tableId, $response['body']['$id']);
|
||||
$this->assertEquals('Test Table', $response['body']['name']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/name', [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns/name', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getDestinationProject()['$id'],
|
||||
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
|
||||
@@ -536,41 +535,41 @@ trait MigrationsBase
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAppwriteMigrationDatabasesCollection
|
||||
* @depends testAppwriteMigrationDatabasesTable
|
||||
*/
|
||||
public function testAppwriteMigrationDatabasesDocument(array $data): void
|
||||
public function testAppwriteMigrationDatabasesRow(array $data): void
|
||||
{
|
||||
$table = $data['tableId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
$collectionId = $data['collectionId'];
|
||||
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [
|
||||
$row = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $table . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'documentId' => ID::unique(),
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Test Document',
|
||||
'name' => 'Test Row',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $document['headers']['status-code']);
|
||||
$this->assertNotEmpty($document['body']);
|
||||
$this->assertNotEmpty($document['body']['$id']);
|
||||
$this->assertEquals(201, $row['headers']['status-code']);
|
||||
$this->assertNotEmpty($row['body']);
|
||||
$this->assertNotEmpty($row['body']['$id']);
|
||||
|
||||
$documentId = $document['body']['$id'];
|
||||
$rowId = $row['body']['$id'];
|
||||
|
||||
$result = $this->performMigrationSync([
|
||||
'resources' => [
|
||||
Resource::TYPE_DATABASE,
|
||||
Resource::TYPE_COLLECTION,
|
||||
Resource::TYPE_ATTRIBUTE,
|
||||
Resource::TYPE_DOCUMENT,
|
||||
Resource::TYPE_TABLE,
|
||||
Resource::TYPE_COLUMN,
|
||||
Resource::TYPE_ROW,
|
||||
],
|
||||
'endpoint' => 'http://localhost/v1',
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
@@ -586,10 +585,10 @@ trait MigrationsBase
|
||||
]);
|
||||
|
||||
$this->assertEquals('completed', $result['status']);
|
||||
$this->assertEquals([Resource::TYPE_DATABASE, Resource::TYPE_COLLECTION, Resource::TYPE_ATTRIBUTE, Resource::TYPE_DOCUMENT], $result['resources']);
|
||||
$this->assertEquals([Resource::TYPE_DATABASE, Resource::TYPE_TABLE, Resource::TYPE_COLUMN, Resource::TYPE_ROW], $result['resources']);
|
||||
|
||||
//TODO: Add TYPE_DOCUMENT to the migration status counters once pending issue is resolved
|
||||
foreach ([Resource::TYPE_DATABASE, Resource::TYPE_COLLECTION, Resource::TYPE_ATTRIBUTE] as $resource) {
|
||||
// TODO: Add TYPE_ROW to the migration status counters once pending issue is resolved
|
||||
foreach ([Resource::TYPE_DATABASE, Resource::TYPE_TABLE, Resource::TYPE_COLUMN] as $resource) {
|
||||
$this->assertArrayHasKey($resource, $result['statusCounters']);
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['error']);
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['pending']);
|
||||
@@ -598,7 +597,7 @@ trait MigrationsBase
|
||||
$this->assertEquals(0, $result['statusCounters'][$resource]['warning']);
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [
|
||||
$response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/grids/tables/' . $table . '/rows/' . $rowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getDestinationProject()['$id'],
|
||||
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
|
||||
@@ -607,8 +606,8 @@ trait MigrationsBase
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
|
||||
$this->assertEquals($documentId, $response['body']['$id']);
|
||||
$this->assertEquals('Test Document', $response['body']['name']);
|
||||
$this->assertEquals($rowId, $response['body']['$id']);
|
||||
$this->assertEquals('Test Row', $response['body']['name']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [
|
||||
@@ -805,13 +804,12 @@ trait MigrationsBase
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php'
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js'
|
||||
]);
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -855,8 +853,8 @@ trait MigrationsBase
|
||||
|
||||
$this->assertEquals($functionId, $response['body']['$id']);
|
||||
$this->assertEquals('Test', $response['body']['name']);
|
||||
$this->assertEquals('php-8.0', $response['body']['runtime']);
|
||||
$this->assertEquals('index.php', $response['body']['entrypoint']);
|
||||
$this->assertEquals('node-22', $response['body']['runtime']);
|
||||
$this->assertEquals('index.js', $response['body']['entrypoint']);
|
||||
|
||||
|
||||
$this->assertEventually(function () use ($functionId) {
|
||||
@@ -920,23 +918,23 @@ trait MigrationsBase
|
||||
|
||||
$databaseId = $response['body']['$id'];
|
||||
|
||||
// make a collection
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
// make a table
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Test collection',
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Test table',
|
||||
'tableId' => ID::unique(),
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertEquals($response['body']['name'], 'Test collection');
|
||||
$this->assertEquals($response['body']['name'], 'Test table');
|
||||
|
||||
$collectionId = $response['body']['$id'];
|
||||
$tableId = $response['body']['$id'];
|
||||
|
||||
// make attributes
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
// make columns
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
@@ -952,7 +950,7 @@ trait MigrationsBase
|
||||
$this->assertEquals($response['body']['size'], 256);
|
||||
$this->assertEquals($response['body']['required'], true);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $tableId . '/columns/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
@@ -1026,16 +1024,16 @@ trait MigrationsBase
|
||||
$fileIds[$label] = $response['body']['$id'];
|
||||
}
|
||||
|
||||
// missing attribute, fail in worker.
|
||||
// missing column, fail in worker.
|
||||
$missingColumn = $this->performCsvMigration(
|
||||
[
|
||||
'fileId' => $fileIds['missing-column'],
|
||||
'bucketId' => $bucketIds['missing-column'],
|
||||
'resourceId' => $databaseId . ':' . $collectionId,
|
||||
'resourceId' => $databaseId . ':' . $tableId,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $collectionId) {
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
|
||||
$migrationId = $missingColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1047,11 +1045,15 @@ trait MigrationsBase
|
||||
$this->assertEquals('failed', $migration['body']['status']);
|
||||
$this->assertEquals('CSV', $migration['body']['source']);
|
||||
$this->assertEquals('Appwrite', $migration['body']['destination']);
|
||||
$this->assertContains(Resource::TYPE_DOCUMENT, $migration['body']['resources']);
|
||||
$this->assertContains(Resource::TYPE_ROW, $migration['body']['resources']);
|
||||
$this->assertEmpty($migration['body']['statusCounters']);
|
||||
|
||||
$errorJson = $migration['body']['errors'][0];
|
||||
$errorData = json_decode($errorJson, true);
|
||||
|
||||
$this->assertThat(
|
||||
implode("\n", $migration['body']['errors']),
|
||||
$this->stringContains("CSV header mismatch. Missing attribute: 'age'")
|
||||
$errorData['message'],
|
||||
$this->stringContains("CSV header mismatch. Missing column: 'age'")
|
||||
);
|
||||
}, 60000, 500);
|
||||
|
||||
@@ -1060,11 +1062,11 @@ trait MigrationsBase
|
||||
[
|
||||
'fileId' => $fileIds['missing-row'],
|
||||
'bucketId' => $bucketIds['missing-row'],
|
||||
'resourceId' => $databaseId . ':' . $collectionId,
|
||||
'resourceId' => $databaseId . ':' . $tableId,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $collectionId) {
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
|
||||
$migrationId = $missingColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1076,10 +1078,14 @@ trait MigrationsBase
|
||||
$this->assertEquals('failed', $migration['body']['status']);
|
||||
$this->assertEquals('CSV', $migration['body']['source']);
|
||||
$this->assertEquals('Appwrite', $migration['body']['destination']);
|
||||
$this->assertContains(Resource::TYPE_DOCUMENT, $migration['body']['resources']);
|
||||
$this->assertContains(Resource::TYPE_ROW, $migration['body']['resources']);
|
||||
$this->assertEmpty($migration['body']['statusCounters']);
|
||||
|
||||
$errorJson = $migration['body']['errors'][0];
|
||||
$errorData = json_decode($errorJson, true);
|
||||
|
||||
$this->assertThat(
|
||||
implode("\n", $migration['body']['errors']),
|
||||
$errorData['message'],
|
||||
$this->stringContains('CSV row does not match the number of header columns')
|
||||
);
|
||||
}, 60000, 500);
|
||||
@@ -1089,11 +1095,11 @@ trait MigrationsBase
|
||||
[
|
||||
'fileId' => $fileIds['irrelevant-column'],
|
||||
'bucketId' => $bucketIds['irrelevant-column'],
|
||||
'resourceId' => $databaseId . ':' . $collectionId,
|
||||
'resourceId' => $databaseId . ':' . $tableId,
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($irrelevantColumn, $databaseId, $collectionId) {
|
||||
$this->assertEventually(function () use ($irrelevantColumn, $databaseId, $tableId) {
|
||||
$migrationId = $irrelevantColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1105,11 +1111,15 @@ trait MigrationsBase
|
||||
$this->assertEquals('failed', $migration['body']['status']);
|
||||
$this->assertEquals('CSV', $migration['body']['source']);
|
||||
$this->assertEquals('Appwrite', $migration['body']['destination']);
|
||||
$this->assertContains(Resource::TYPE_DOCUMENT, $migration['body']['resources']);
|
||||
$this->assertContains(Resource::TYPE_ROW, $migration['body']['resources']);
|
||||
$this->assertEmpty($migration['body']['statusCounters']);
|
||||
|
||||
$errorJson = $migration['body']['errors'][0];
|
||||
$errorData = json_decode($errorJson, true);
|
||||
|
||||
$this->assertThat(
|
||||
implode("\n", $migration['body']['errors']),
|
||||
$this->stringContains("CSV header mismatch. Unexpected attribute: 'email'")
|
||||
$errorData['message'],
|
||||
$this->stringContains("CSV header mismatch. Unexpected column: 'email'")
|
||||
);
|
||||
}, 60000, 500);
|
||||
|
||||
@@ -1119,7 +1129,7 @@ trait MigrationsBase
|
||||
'endpoint' => 'http://localhost/v1',
|
||||
'fileId' => $fileIds['default'],
|
||||
'bucketId' => $bucketIds['default'],
|
||||
'resourceId' => $databaseId . ':' . $collectionId,
|
||||
'resourceId' => $databaseId . ':' . $tableId,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1127,11 +1137,11 @@ trait MigrationsBase
|
||||
$this->assertEquals('CSV', $migration['body']['source']);
|
||||
$this->assertEquals('pending', $migration['body']['status']);
|
||||
$this->assertEquals('Appwrite', $migration['body']['destination']);
|
||||
$this->assertContains(Resource::TYPE_DOCUMENT, $migration['body']['resources']);
|
||||
$this->assertContains(Resource::TYPE_ROW, $migration['body']['resources']);
|
||||
|
||||
return [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
'tableId' => $tableId,
|
||||
'migrationId' => $migration['body']['$id'],
|
||||
];
|
||||
}
|
||||
@@ -1141,14 +1151,14 @@ trait MigrationsBase
|
||||
*/
|
||||
public function testImportSuccessful(array $response): void
|
||||
{
|
||||
$tableId = $response['tableId'];
|
||||
$databaseId = $response['databaseId'];
|
||||
$collectionId = $response['collectionId'];
|
||||
$migrationId = $response['migrationId'];
|
||||
|
||||
$documentsCountInCSV = 100;
|
||||
$rowsCountInCSV = 100;
|
||||
|
||||
// get migration stats
|
||||
$this->assertEventually(function () use ($migrationId, $databaseId, $collectionId, $documentsCountInCSV) {
|
||||
$this->assertEventually(function () use ($migrationId, $databaseId, $tableId, $rowsCountInCSV) {
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -1159,13 +1169,13 @@ trait MigrationsBase
|
||||
$this->assertEquals('completed', $migration['body']['status']);
|
||||
$this->assertEquals('CSV', $migration['body']['source']);
|
||||
$this->assertEquals('Appwrite', $migration['body']['destination']);
|
||||
$this->assertContains(Resource::TYPE_DOCUMENT, $migration['body']['resources']);
|
||||
$this->assertArrayHasKey(Resource::TYPE_DOCUMENT, $migration['body']['statusCounters']);
|
||||
$this->assertEquals($documentsCountInCSV, $migration['body']['statusCounters'][Resource::TYPE_DOCUMENT]['success']);
|
||||
}, 60000, 500);
|
||||
$this->assertContains(Resource::TYPE_ROW, $migration['body']['resources']);
|
||||
$this->assertArrayHasKey(Resource::TYPE_ROW, $migration['body']['statusCounters']);
|
||||
$this->assertEquals($rowsCountInCSV, $migration['body']['statusCounters'][Resource::TYPE_ROW]['success']);
|
||||
}, 1000, 500);
|
||||
|
||||
// get documents count
|
||||
$documents = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/collections/'.$collectionId.'/documents', array_merge([
|
||||
// get rows count
|
||||
$rows = $this->client->call(Client::METHOD_GET, '/databases/'.$databaseId.'/grids/tables/'.$tableId.'/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
@@ -1175,10 +1185,10 @@ trait MigrationsBase
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $documents['headers']['status-code']);
|
||||
$this->assertIsArray($documents['body']['documents']);
|
||||
$this->assertIsNumeric($documents['body']['total']);
|
||||
$this->assertEquals($documentsCountInCSV, $documents['body']['total']);
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertIsArray($rows['body']['rows']);
|
||||
$this->assertIsNumeric($rows['body']['total']);
|
||||
$this->assertEquals($rowsCountInCSV, $rows['body']['total']);
|
||||
}
|
||||
|
||||
private function performCsvMigration(array $body): array
|
||||
|
||||
@@ -483,7 +483,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
$this->assertIsArray($response['body']['requests']);
|
||||
$this->assertIsArray($response['body']['network']);
|
||||
$this->assertIsNumeric($response['body']['executionsTotal']);
|
||||
$this->assertIsNumeric($response['body']['documentsTotal']);
|
||||
$this->assertIsNumeric($response['body']['rowsTotal']);
|
||||
$this->assertIsNumeric($response['body']['databasesTotal']);
|
||||
$this->assertIsNumeric($response['body']['bucketsTotal']);
|
||||
$this->assertIsNumeric($response['body']['usersTotal']);
|
||||
@@ -951,6 +951,55 @@ class ProjectsConsoleClientTest extends Scope
|
||||
return ['projectId' => $projectId];
|
||||
}
|
||||
|
||||
/** @depends testCreateProject */
|
||||
public function testUpdateProjectInvalidateSessions($data): array
|
||||
{
|
||||
$id = $data['projectId'];
|
||||
|
||||
// Check defaults
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertTrue($response['body']['authInvalidateSessions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/session-invalidation', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'enabled' => false,
|
||||
]);
|
||||
$this->assertFalse($response['body']['authInvalidateSessions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertFalse($response['body']['authInvalidateSessions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/auth/session-invalidation', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'enabled' => true,
|
||||
]);
|
||||
$this->assertTrue($response['body']['authInvalidateSessions']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => 'console',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertTrue($response['body']['authInvalidateSessions']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateProject
|
||||
*/
|
||||
@@ -2942,7 +2991,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Key Test Update',
|
||||
'scopes' => ['users.read', 'users.write', 'collections.read'],
|
||||
'scopes' => ['users.read', 'users.write', 'collections.read', 'tables.read'],
|
||||
'expire' => DateTime::addSeconds(new \DateTime(), 360),
|
||||
]);
|
||||
|
||||
@@ -2953,6 +3002,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
$this->assertContains('users.read', $response['body']['scopes']);
|
||||
$this->assertContains('users.write', $response['body']['scopes']);
|
||||
$this->assertContains('collections.read', $response['body']['scopes']);
|
||||
$this->assertContains('tables.read', $response['body']['scopes']);
|
||||
$this->assertCount(3, $response['body']['scopes']);
|
||||
$this->assertArrayHasKey('sdks', $response['body']);
|
||||
$this->assertEmpty($response['body']['sdks']);
|
||||
@@ -2971,6 +3021,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
$this->assertContains('users.read', $response['body']['scopes']);
|
||||
$this->assertContains('users.write', $response['body']['scopes']);
|
||||
$this->assertContains('collections.read', $response['body']['scopes']);
|
||||
$this->assertContains('tables.read', $response['body']['scopes']);
|
||||
$this->assertCount(3, $response['body']['scopes']);
|
||||
$this->assertArrayHasKey('sdks', $response['body']);
|
||||
$this->assertEmpty($response['body']['sdks']);
|
||||
@@ -4637,7 +4688,6 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'failure' => 'https://example.com'
|
||||
]);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Invalid `success` param: URL host must be one of: localhost, appwrite.io, *.appwrite.io', $response['body']);
|
||||
|
||||
/** Test oauth2 with devKey and now get oauth2 is disabled */
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, [
|
||||
@@ -4660,7 +4710,6 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'url' => 'https://example.com',
|
||||
]);
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `url` param: URL host must be one of: localhost, appwrite.io, *.appwrite.io', $response['body']['message']);
|
||||
|
||||
/** Test hostname in Magic URL with devKey */
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/magic-url', [
|
||||
|
||||
@@ -30,8 +30,6 @@ class ProjectsCustomServerTest extends Scope
|
||||
'domain' => $testId . '-api.appwrite.test',
|
||||
]);
|
||||
|
||||
\var_dump($response);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/proxy/rules/api', $headers, [
|
||||
|
||||
@@ -227,7 +227,7 @@ trait ProxyBase
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'functionId' => ID::unique(),
|
||||
'runtime' => 'node-18.0',
|
||||
'runtime' => 'node-22',
|
||||
'name' => 'Proxy Function',
|
||||
'entrypoint' => 'index.js',
|
||||
'commands' => '',
|
||||
@@ -244,7 +244,7 @@ trait ProxyBase
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]), [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
|
||||
|
||||
@@ -16,13 +16,6 @@ trait RealtimeBase
|
||||
$projectId = $this->getProject()['$id'];
|
||||
}
|
||||
|
||||
$headers = array_merge(
|
||||
[
|
||||
"Origin" => "appwrite.test",
|
||||
],
|
||||
$headers
|
||||
);
|
||||
|
||||
$query = [
|
||||
"project" => $projectId,
|
||||
"channels" => $channels,
|
||||
@@ -42,14 +35,14 @@ trait RealtimeBase
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$client = $this->getWebsocket(["documents"]);
|
||||
$client = $this->getWebsocket(["rows"]);
|
||||
$this->assertNotEmpty($client->receive());
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testConnectionFailureMissingChannels(): void
|
||||
{
|
||||
$client = $this->getWebsocket();
|
||||
$client = $this->getWebsocket([]);
|
||||
$payload = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey("type", $payload);
|
||||
@@ -58,20 +51,13 @@ trait RealtimeBase
|
||||
$this->assertEquals(1008, $payload["data"]["code"]);
|
||||
$this->assertEquals("Missing channels", $payload["data"]["message"]);
|
||||
\usleep(250000); // 250ms
|
||||
$this->expectException(ConnectionException::class); // Check if server disconnnected client
|
||||
$this->expectException(ConnectionException::class); // Check if server disconnected client
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testConnectionFailureUnknownProject(): void
|
||||
{
|
||||
$client = new WebSocketClient(
|
||||
"ws://appwrite-traefik/v1/realtime?project=123",
|
||||
[
|
||||
"headers" => [
|
||||
"Origin" => "appwrite.test",
|
||||
],
|
||||
]
|
||||
);
|
||||
$client = $this->getWebsocket(projectId: '123');
|
||||
$payload = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey("type", $payload);
|
||||
@@ -83,7 +69,7 @@ trait RealtimeBase
|
||||
$payload["data"]["message"]
|
||||
);
|
||||
\usleep(250000); // 250ms
|
||||
$this->expectException(ConnectionException::class); // Check if server disconnnected client
|
||||
$this->expectException(ConnectionException::class); // Check if server disconnected client
|
||||
$client->close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +123,8 @@ class RealtimeConsoleClientTest extends Scope
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testAttributes(): array
|
||||
public function testAttributesCollectionsAPI(): array
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$projectId = 'console';
|
||||
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
@@ -184,13 +183,13 @@ class RealtimeConsoleClientTest extends Scope
|
||||
]);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$attributeKey = $name['body']['key'];
|
||||
|
||||
$this->assertEquals($name['headers']['status-code'], 202);
|
||||
$this->assertEquals($name['body']['key'], 'name');
|
||||
$this->assertEquals($name['body']['type'], 'string');
|
||||
$this->assertEquals($name['body']['size'], 256);
|
||||
$this->assertEquals($name['body']['required'], true);
|
||||
$this->assertEquals(202, $name['headers']['status-code']);
|
||||
$this->assertEquals('name', $name['body']['key']);
|
||||
$this->assertEquals('string', $name['body']['type']);
|
||||
$this->assertEquals(256, $name['body']['size']);
|
||||
$this->assertTrue($name['body']['required']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
@@ -235,15 +234,128 @@ class RealtimeConsoleClientTest extends Scope
|
||||
|
||||
$client->close();
|
||||
|
||||
$data = ['actorsId' => $actorsId, 'databaseId' => $databaseId];
|
||||
return ['actorsId' => $actorsId, 'databaseId' => $databaseId];
|
||||
}
|
||||
|
||||
return $data;
|
||||
public function testAttributesTablesAPI(): array
|
||||
{
|
||||
$projectId = 'console';
|
||||
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
], $projectId);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertCount(1, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
|
||||
/**
|
||||
* Create database
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors DB',
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
/**
|
||||
* Test Attributes
|
||||
*/
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$actorsId = $actors['body']['$id'];
|
||||
|
||||
$name = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
$this->assertEquals(202, $name['headers']['status-code']);
|
||||
$this->assertEquals('name', $name['body']['key']);
|
||||
$this->assertEquals('string', $name['body']['type']);
|
||||
$this->assertEquals(256, $name['body']['size']);
|
||||
$this->assertTrue($name['body']['required']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*.create", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*.create", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals('processing', $response['data']['payload']['status']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals('available', $response['data']['payload']['status']);
|
||||
|
||||
$client->close();
|
||||
|
||||
return ['actorsId' => $actorsId, 'databaseId' => $databaseId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testAttributes
|
||||
* @depends testAttributesCollectionsAPI
|
||||
*/
|
||||
public function testIndexes(array $data)
|
||||
public function testIndexesCollectionAPI(array $data)
|
||||
{
|
||||
$projectId = 'console';
|
||||
$actorsId = $data['actorsId'];
|
||||
@@ -277,10 +389,9 @@ class RealtimeConsoleClientTest extends Scope
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($index['headers']['status-code'], 202);
|
||||
$this->assertEquals(202, $index['headers']['status-code']);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
$indexKey = $index['body']['key'];
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
@@ -326,9 +437,93 @@ class RealtimeConsoleClientTest extends Scope
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testIndexes
|
||||
* @depends testAttributesTablesAPI
|
||||
*/
|
||||
public function testDeleteIndex(array $data)
|
||||
public function testIndexesTablesAPI(array $data)
|
||||
{
|
||||
$projectId = 'console';
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
], $projectId);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertCount(1, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
|
||||
/**
|
||||
* Test Indexes
|
||||
*/
|
||||
$index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'key' => 'key_name',
|
||||
'type' => 'key',
|
||||
'columns' => [
|
||||
'name',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $index['headers']['status-code']);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*.create", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*.create", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals('processing', $response['data']['payload']['status']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals('available', $response['data']['payload']['status']);
|
||||
|
||||
$client->close();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testIndexesCollectionAPI
|
||||
*/
|
||||
public function testDeleteIndexCollectionsAPI(array $data)
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$projectId = 'console';
|
||||
@@ -360,7 +555,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($attribute['headers']['status-code'], 204);
|
||||
$this->assertEquals(204, $attribute['headers']['status-code']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
@@ -382,6 +577,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
|
||||
/** Delete index generates two events. One from the API and one from the database worker */
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
@@ -404,12 +600,91 @@ class RealtimeConsoleClientTest extends Scope
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testDeleteIndex
|
||||
* @depends testIndexesTablesAPI
|
||||
*/
|
||||
public function testDeleteAttribute(array $data)
|
||||
public function testDeleteIndexTablesAPI(array $data)
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$projectId = 'console';
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
], $projectId);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertCount(1, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
/**
|
||||
* Test Delete Index
|
||||
*/
|
||||
$indexKey = 'key_name';
|
||||
$attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/indexes/' . $indexKey, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $attribute['headers']['status-code']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
/** Delete index generates two events. One from the API and one from the database worker */
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*.delete", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*.delete", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.indexes.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
$client->close();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testDeleteIndexCollectionsAPI
|
||||
*/
|
||||
public function testDeleteAttributeCollectionsAPI(array $data)
|
||||
{
|
||||
$projectId = 'console';
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
@@ -438,7 +713,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($attribute['headers']['status-code'], 204);
|
||||
$this->assertEquals(204, $attribute['headers']['status-code']);
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
@@ -478,6 +753,81 @@ class RealtimeConsoleClientTest extends Scope
|
||||
$client->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testDeleteIndexTablesAPI
|
||||
*/
|
||||
public function testDeleteAttributeTablesAPI(array $data)
|
||||
{
|
||||
$projectId = 'console';
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
|
||||
], $projectId);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertCount(1, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
|
||||
$attributeKey = 'name';
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
/**
|
||||
* Test Delete Attribute
|
||||
*/
|
||||
$attribute = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $data['actorsId'] . '/columns/' . $attributeKey, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $attribute['headers']['status-code']);
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*.update", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*.delete", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.{$actorsId}", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*.delete", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*.columns.*", $response['data']['events']);
|
||||
$this->assertContains("databases.{$databaseId}.tables.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testPing()
|
||||
{
|
||||
$client = $this->getWebsocket(['console'], [
|
||||
@@ -524,8 +874,8 @@ class RealtimeConsoleClientTest extends Scope
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'events' => [
|
||||
'users.*.create',
|
||||
'users.*.delete',
|
||||
@@ -564,8 +914,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('php'),
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
@@ -607,10 +956,8 @@ class RealtimeConsoleClientTest extends Scope
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertArrayHasKey('buildLogs', $response['data']['payload']);
|
||||
|
||||
if (!empty($response['data']['payload']['buildEndedAt'])) {
|
||||
$this->assertNotEmpty($response['data']['payload']['buildEndedAt']);
|
||||
if (!empty($response['data']['payload']['buildSize'])) {
|
||||
$this->assertNotEmpty($response['data']['payload']['buildStartedAt']);
|
||||
$this->assertNotEmpty($response['data']['payload']['buildDuration']);
|
||||
$this->assertNotEmpty($response['data']['payload']['buildPath']);
|
||||
$this->assertNotEmpty($response['data']['payload']['buildSize']);
|
||||
$this->assertNotEmpty($response['data']['payload']['totalSize']);
|
||||
@@ -618,7 +965,7 @@ class RealtimeConsoleClientTest extends Scope
|
||||
break;
|
||||
}
|
||||
|
||||
// Ignore comparasion for first payload
|
||||
// Ignore comparison for first payload
|
||||
if ($previousBuildLogs !== null) {
|
||||
$this->assertNotEquals($previousBuildLogs, $response['data']['payload']['buildLogs']);
|
||||
}
|
||||
@@ -634,6 +981,13 @@ class RealtimeConsoleClientTest extends Scope
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertEquals("ready", $response['data']['payload']['status']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
$this->assertContains("functions.{$functionId}.deployments.{$deploymentId}.update", $response['data']['events']);
|
||||
$this->assertContains('console', $response['data']['channels']);
|
||||
$this->assertContains("projects.{$projectId}", $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['payload']['buildDuration']);
|
||||
$this->assertNotEmpty($response['data']['payload']['buildEndedAt']);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,11 +81,17 @@ class RealtimeCustomClientTest extends Scope
|
||||
'files',
|
||||
'files.1',
|
||||
'collections',
|
||||
'tables',
|
||||
'collections.1.documents',
|
||||
'collections.2.documents',
|
||||
'tables.1.rows',
|
||||
'tables.2.rows',
|
||||
'documents',
|
||||
'rows',
|
||||
'collections.1.documents.1',
|
||||
'collections.2.documents.2',
|
||||
'tables.1.rows.1',
|
||||
'tables.2.rows.2',
|
||||
], $headers);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
@@ -95,17 +101,22 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
$this->assertCount(10, $response['data']['channels']);
|
||||
$this->assertCount(16, $response['data']['channels']);
|
||||
$this->assertContains('account', $response['data']['channels']);
|
||||
$this->assertContains('account.' . $userId, $response['data']['channels']);
|
||||
$this->assertContains('files', $response['data']['channels']);
|
||||
$this->assertContains('files.1', $response['data']['channels']);
|
||||
$this->assertContains('collections', $response['data']['channels']);
|
||||
$this->assertContains('tables', $response['data']['channels']);
|
||||
$this->assertContains('collections.1.documents', $response['data']['channels']);
|
||||
$this->assertContains('collections.2.documents', $response['data']['channels']);
|
||||
$this->assertContains('tables.1.rows', $response['data']['channels']);
|
||||
$this->assertContains('tables.2.rows', $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains('collections.1.documents.1', $response['data']['channels']);
|
||||
$this->assertContains('collections.2.documents.2', $response['data']['channels']);
|
||||
$this->assertContains('tables.1.rows.1', $response['data']['channels']);
|
||||
$this->assertContains('tables.2.rows.2', $response['data']['channels']);
|
||||
$this->assertEquals($userId, $response['data']['user']['$id']);
|
||||
|
||||
$client->close();
|
||||
@@ -415,7 +426,8 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("users.*", $response['data']['events']);
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$verification = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$verification = $tokens['secret'];
|
||||
|
||||
/**
|
||||
* Test Account Verification Complete
|
||||
@@ -612,7 +624,8 @@ class RealtimeCustomClientTest extends Scope
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$recovery = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$recovery = $tokens['secret'];
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
@@ -734,11 +747,11 @@ class RealtimeCustomClientTest extends Scope
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals($name['headers']['status-code'], 202);
|
||||
$this->assertEquals($name['body']['key'], 'name');
|
||||
$this->assertEquals($name['body']['type'], 'string');
|
||||
$this->assertEquals($name['body']['size'], 256);
|
||||
$this->assertEquals($name['body']['required'], true);
|
||||
$this->assertEquals(202, $name['headers']['status-code']);
|
||||
$this->assertEquals('name', $name['body']['key']);
|
||||
$this->assertEquals('string', $name['body']['type']);
|
||||
$this->assertEquals(256, $name['body']['size']);
|
||||
$this->assertTrue($name['body']['required']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
@@ -768,7 +781,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']);
|
||||
$this->assertContains('databases.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']);
|
||||
@@ -785,7 +798,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans');
|
||||
$this->assertEquals('Chris Evans', $response['data']['payload']['name']);
|
||||
|
||||
/**
|
||||
* Test Document Update
|
||||
@@ -812,7 +825,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents", $response['data']['channels']);
|
||||
@@ -830,7 +843,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2');
|
||||
$this->assertEquals('Chris Evans 2', $response['data']['payload']['name']);
|
||||
|
||||
/**
|
||||
* Test Document Delete
|
||||
@@ -866,7 +879,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents", $response['data']['channels']);
|
||||
@@ -883,7 +896,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper');
|
||||
$this->assertEquals('Bradley Cooper', $response['data']['payload']['name']);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
@@ -955,11 +968,11 @@ class RealtimeCustomClientTest extends Scope
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals($name['headers']['status-code'], 202);
|
||||
$this->assertEquals($name['body']['key'], 'name');
|
||||
$this->assertEquals($name['body']['type'], 'string');
|
||||
$this->assertEquals($name['body']['size'], 256);
|
||||
$this->assertEquals($name['body']['required'], true);
|
||||
$this->assertEquals(202, $name['headers']['status-code']);
|
||||
$this->assertEquals('name', $name['body']['key']);
|
||||
$this->assertEquals('string', $name['body']['type']);
|
||||
$this->assertEquals(256, $name['body']['size']);
|
||||
$this->assertTrue($name['body']['required']);
|
||||
|
||||
sleep(2);
|
||||
|
||||
@@ -986,7 +999,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents", $response['data']['channels']);
|
||||
@@ -1003,7 +1016,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans');
|
||||
$this->assertEquals('Chris Evans', $response['data']['payload']['name']);
|
||||
|
||||
/**
|
||||
* Test Document Update
|
||||
@@ -1025,7 +1038,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents", $response['data']['channels']);
|
||||
@@ -1043,7 +1056,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2');
|
||||
$this->assertEquals('Chris Evans 2', $response['data']['payload']['name']);
|
||||
|
||||
/**
|
||||
* Test Document Delete
|
||||
@@ -1075,7 +1088,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertCount(6, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents.{$documentId}", $response['data']['channels']);
|
||||
$this->assertContains("databases.{$databaseId}.collections.{$actorsId}.documents", $response['data']['channels']);
|
||||
@@ -1092,7 +1105,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("databases.{$databaseId}", $response['data']['events']);
|
||||
$this->assertContains("databases.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper');
|
||||
$this->assertEquals('Bradley Cooper', $response['data']['payload']['name']);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
@@ -1283,16 +1296,16 @@ class RealtimeCustomClientTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'name' => 'Test timeout execution',
|
||||
'execute' => ['users'],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 201);
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
|
||||
@@ -1300,14 +1313,13 @@ class RealtimeCustomClientTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'entrypoint' => 'index.php',
|
||||
'code' => $this->packageFunction('timeout'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202);
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
|
||||
// Poll until deployment is built
|
||||
@@ -1467,7 +1479,7 @@ class RealtimeCustomClientTest extends Scope
|
||||
'name' => 'Manchester'
|
||||
]);
|
||||
|
||||
$this->assertEquals($team['headers']['status-code'], 200);
|
||||
$this->assertEquals(200, $team['headers']['status-code']);
|
||||
$this->assertNotEmpty($team['body']['$id']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
@@ -1499,9 +1511,9 @@ class RealtimeCustomClientTest extends Scope
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals($team['headers']['status-code'], 200);
|
||||
$this->assertEquals($team['body']['funcKey1'], 'funcValue1');
|
||||
$this->assertEquals($team['body']['funcKey2'], 'funcValue2');
|
||||
$this->assertEquals(200, $team['headers']['status-code']);
|
||||
$this->assertEquals('funcValue1', $team['body']['funcKey1']);
|
||||
$this->assertEquals('funcValue2', $team['body']['funcKey2']);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
@@ -1520,8 +1532,8 @@ class RealtimeCustomClientTest extends Scope
|
||||
$this->assertContains("teams.*.update", $response['data']['events']);
|
||||
$this->assertContains("teams.*", $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertEquals($response['data']['payload']['funcKey1'], 'funcValue1');
|
||||
$this->assertEquals($response['data']['payload']['funcKey2'], 'funcValue2');
|
||||
$this->assertEquals('funcValue1', $response['data']['payload']['funcKey1']);
|
||||
$this->assertEquals('funcValue2', $response['data']['payload']['funcKey2']);
|
||||
|
||||
$client->close();
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ class SitesConsoleClientTest extends Scope
|
||||
use SideConsole;
|
||||
use SitesBase;
|
||||
|
||||
/**
|
||||
* @group screenshots
|
||||
*/
|
||||
public function testSiteScreenshot(): void
|
||||
{
|
||||
$siteId = $this->setupSite([
|
||||
@@ -89,12 +92,51 @@ class SitesConsoleClientTest extends Scope
|
||||
|
||||
$this->assertNotEquals($screenshotDarkHash, $screenshotHash);
|
||||
|
||||
$screenshotId = $deployment['body']['screenshotLight'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/view?project=console");
|
||||
$this->assertEquals(404, $file['headers']['status-code']);
|
||||
|
||||
$screenshotId = $deployment['body']['screenshotDark'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/view?project=console");
|
||||
$this->assertEquals(404, $file['headers']['status-code']);
|
||||
|
||||
// Verify previews
|
||||
$screenshotId = $deployment['body']['screenshotLight'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console", array_merge($this->getHeaders(), [
|
||||
'x-appwrite-mode' => 'default' // NOT ADMIN!
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
$this->assertNotEmpty(200, $file['body']);
|
||||
$this->assertGreaterThan(1, $file['headers']['content-length']);
|
||||
$this->assertEquals('image/png', $file['headers']['content-type']);
|
||||
|
||||
$screenshotHash = \md5($file['body']);
|
||||
$this->assertNotEmpty($screenshotHash);
|
||||
|
||||
$screenshotId = $deployment['body']['screenshotDark'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console", array_merge($this->getHeaders(), [
|
||||
'x-appwrite-mode' => 'default' // NOT ADMIN!
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
$this->assertNotEmpty(200, $file['body']);
|
||||
$this->assertGreaterThan(1, $file['headers']['content-length']);
|
||||
$this->assertEquals('image/png', $file['headers']['content-type']);
|
||||
|
||||
$screenshotDarkHash = \md5($file['body']);
|
||||
$this->assertNotEmpty($screenshotDarkHash);
|
||||
|
||||
$this->assertNotEquals($screenshotDarkHash, $screenshotHash);
|
||||
|
||||
$screenshotId = $deployment['body']['screenshotLight'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console");
|
||||
$this->assertEquals(404, $file['headers']['status-code']);
|
||||
|
||||
$screenshotId = $deployment['body']['screenshotDark'];
|
||||
$file = $this->client->call(Client::METHOD_GET, "/storage/buckets/screenshots/files/$screenshotId/preview?project=console");
|
||||
$this->assertEquals(404, $file['headers']['status-code']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\System\System;
|
||||
|
||||
class SitesCustomClientTest extends Scope
|
||||
{
|
||||
@@ -121,6 +122,7 @@ class SitesCustomClientTest extends Scope
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$template = $this->getTemplate('starter-for-react');
|
||||
$hostname = System::getEnv('_APP_DOMAIN') ?: '';
|
||||
$this->assertEquals(200, $template['headers']['status-code']);
|
||||
$this->assertIsArray($template['body']);
|
||||
$this->assertEquals('starter-for-react', $template['body']['key']);
|
||||
@@ -129,8 +131,8 @@ class SitesCustomClientTest extends Scope
|
||||
$this->assertEquals('github', $template['body']['vcsProvider']);
|
||||
$this->assertEquals('Simple React application integrated with Appwrite SDK.', $template['body']['tagline']);
|
||||
$this->assertIsArray($template['body']['frameworks']);
|
||||
$this->assertEquals('http://localhost/images/sites/templates/starter-for-react-dark.png', $template['body']['screenshotDark']);
|
||||
$this->assertEquals('http://localhost/images/sites/templates/starter-for-react-light.png', $template['body']['screenshotLight']);
|
||||
$this->assertEquals('http://'. $hostname . '/images/sites/templates/starter-for-react-dark.png', $template['body']['screenshotDark']);
|
||||
$this->assertEquals('http://' . $hostname . '/images/sites/templates/starter-for-react-light.png', $template['body']['screenshotLight']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
||||
@@ -937,12 +937,12 @@ class SitesCustomServerTest extends Scope
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('canceled', $deployment['body']['status']);
|
||||
|
||||
/**
|
||||
* Build worker still runs the build.
|
||||
* 30s sleep gives worker enough time to finish build.
|
||||
* After build finished, it should still be canceled, not ready.
|
||||
*/
|
||||
\sleep(30);
|
||||
// Ensures worker got eventually aware of cancellation and reacted properly
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertStringContainsString('Build has been canceled.', $deployment['body']['buildLogs']);
|
||||
});
|
||||
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId);
|
||||
|
||||
|
||||
@@ -223,8 +223,10 @@ trait TeamsBaseClient
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals($name, $lastEmail['to'][0]['name']);
|
||||
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
|
||||
$this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
|
||||
$this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
|
||||
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$this->assertEquals($teamName, $tokens['teamName']);
|
||||
$this->assertEquals($response['body']['teamId'], $tokens['teamId']);
|
||||
|
||||
/**
|
||||
* Test with UserId
|
||||
@@ -288,8 +290,10 @@ trait TeamsBaseClient
|
||||
$this->assertEquals($secondEmail, $lastEmail['to'][0]['address']);
|
||||
$this->assertEquals($secondName, $lastEmail['to'][0]['name']);
|
||||
$this->assertEquals('Invitation to ' . $teamName . ' Team at ' . $this->getProject()['name'], $lastEmail['subject']);
|
||||
$this->assertEquals($response['body']['teamId'], substr($lastEmail['text'], strpos($lastEmail['text'], '&teamId=', 0) + 8, 20));
|
||||
$this->assertEquals($teamName, substr($lastEmail['text'], strpos($lastEmail['text'], '&teamName=', 0) + 10, 7));
|
||||
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$this->assertEquals($teamName, $tokens['teamName']);
|
||||
$this->assertEquals($response['body']['teamId'], $tokens['teamId']);
|
||||
|
||||
// test for resending invitation
|
||||
$response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([
|
||||
@@ -305,9 +309,10 @@ trait TeamsBaseClient
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
|
||||
$userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20);
|
||||
$secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
$membershipUid = $tokens['membershipId'];
|
||||
$userUid = $tokens['userId'];
|
||||
$secret = $tokens['secret'];
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -338,11 +343,11 @@ trait TeamsBaseClient
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
return [
|
||||
'teamUid' => $teamUid,
|
||||
'teamName' => $teamName,
|
||||
'secret' => $secret,
|
||||
'membershipUid' => $membershipUid,
|
||||
'userUid' => $userUid,
|
||||
'teamUid' => $tokens['teamId'],
|
||||
'teamName' => $tokens['teamName'],
|
||||
'secret' => $tokens['secret'],
|
||||
'membershipUid' => $tokens['membershipId'],
|
||||
'userUid' => $tokens['userId'],
|
||||
'email' => $email,
|
||||
'name' => $name
|
||||
];
|
||||
@@ -600,10 +605,11 @@ trait TeamsBaseClient
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html']);
|
||||
|
||||
$secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
$membershipUid = substr($lastEmail['text'], strpos($lastEmail['text'], '?membershipId=', 0) + 14, 20);
|
||||
$userUid = substr($lastEmail['text'], strpos($lastEmail['text'], '&userId=', 0) + 8, 20);
|
||||
$secret = $tokens['secret'];
|
||||
$membershipUid = $tokens['membershipId'];
|
||||
$userUid = $tokens['userId'];
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid . '/status', [
|
||||
'origin' => 'http://localhost',
|
||||
|
||||
@@ -6,6 +6,7 @@ use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\CLI\Console;
|
||||
|
||||
class TeamsCustomClientTest extends Scope
|
||||
{
|
||||
@@ -152,11 +153,14 @@ class TeamsCustomClientTest extends Scope
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
$email = $this->getLastEmail();
|
||||
Console::log(json_encode([
|
||||
'testTeamsInviteHTMLInjection' => $email
|
||||
], JSON_PRETTY_PRINT));
|
||||
|
||||
$encoded = 'http://localhost:5000/join-us\"></a><h1>INJECTED</h1>?';
|
||||
|
||||
$this->assertStringNotContainsString('<h1>INJECTED</h1>', $email['html']);
|
||||
$this->assertStringContainsString($encoded, $email['html']);
|
||||
$this->assertStringContainsString($encoded, $email['text']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/'.$response['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Tests\E2E\Services\Tokens;
|
||||
use CURLFile;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
trait TokensBase
|
||||
{
|
||||
@@ -275,4 +277,88 @@ trait TokensBase
|
||||
$this->assertEquals($image->getImageHeight(), $original->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
|
||||
public function testFileAccessWithFileSecurity(): void
|
||||
{
|
||||
$bucket = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets',
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'name' => 'Test Bucket',
|
||||
'bucketId' => ID::unique(),
|
||||
'fileSecurity' => true,
|
||||
'allowedFileExtensions' => ['jpg', 'png', 'jfif'],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucket['body']['$id']);
|
||||
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
|
||||
$file = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/storage/buckets/' . $bucketId . '/files',
|
||||
[
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
],
|
||||
[
|
||||
'fileId' => ID::unique(),
|
||||
'permissions' => [ Permission::read(Role::label('devrel')) ],
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
]
|
||||
);
|
||||
|
||||
$fileId = $file['body']['$id'];
|
||||
|
||||
$token = $this->client->call(
|
||||
Client::METHOD_POST,
|
||||
'/tokens/buckets/' . $bucketId . '/files/' . $fileId,
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]
|
||||
);
|
||||
|
||||
$jwtToken = $token['body']['secret'];
|
||||
|
||||
$endpoints = ['preview', 'view', 'download'];
|
||||
|
||||
foreach ($endpoints as $endpoint) {
|
||||
$response = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
"/storage/buckets/$bucketId/files/$fileId/$endpoint",
|
||||
[
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
],
|
||||
[
|
||||
'token' => $jwtToken
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $response['headers']['content-type']);
|
||||
|
||||
if ($endpoint === 'download') {
|
||||
$image = new \Imagick();
|
||||
$image->readImageBlob($response['body']);
|
||||
$original = new \Imagick(__DIR__ . '/../../../resources/logo.png');
|
||||
|
||||
$this->assertEquals($original->getImageWidth(), $image->getImageWidth());
|
||||
$this->assertEquals($original->getImageHeight(), $image->getImageHeight());
|
||||
$this->assertEquals('PNG', $image->getImageFormat());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1117,7 +1117,7 @@ trait UsersBase
|
||||
]);
|
||||
|
||||
$this->assertEquals(401, $session['headers']['status-code']);
|
||||
|
||||
$this->updateProjectinvalidateSessionsProperty(true);
|
||||
$user = $this->client->call(Client::METHOD_PATCH, '/users/' . $data['userId'] . '/password', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -1129,6 +1129,15 @@ trait UsersBase
|
||||
$this->assertNotEmpty($user['body']['$id']);
|
||||
$this->assertNotEmpty($user['body']['password']);
|
||||
|
||||
$sessions = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/sessions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($sessions['headers']['status-code'], 200);
|
||||
$this->assertIsArray($sessions['body']);
|
||||
$this->assertEmpty($sessions['body']['sessions']);
|
||||
|
||||
$session = $this->client->call(Client::METHOD_POST, '/account/sessions/email', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
@@ -1138,7 +1147,7 @@ trait UsersBase
|
||||
]);
|
||||
|
||||
$this->assertEquals($session['headers']['status-code'], 201);
|
||||
|
||||
$this->updateProjectinvalidateSessionsProperty(false);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ trait WebhooksBase
|
||||
return base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true));
|
||||
}
|
||||
|
||||
|
||||
// Collection APIs
|
||||
public function testCreateCollection(): array
|
||||
{
|
||||
/**
|
||||
@@ -389,6 +389,356 @@ trait WebhooksBase
|
||||
return $data;
|
||||
}
|
||||
|
||||
// Table APIs
|
||||
public function testCreateTable(): array
|
||||
{
|
||||
/**
|
||||
* Create database
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors DB',
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
$actorsId = $actors['body']['$id'];
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($actors['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Actors');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(4, $webhook['data']['$permissions']);
|
||||
|
||||
return array_merge(['actorsId' => $actorsId, 'databaseId' => $databaseId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
public function testCreateColumns(array $data): array
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$firstName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'firstName',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$lastName = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'lastName',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$extra = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'extra',
|
||||
'size' => 64,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals($firstName['headers']['status-code'], 202);
|
||||
$this->assertEquals($firstName['body']['key'], 'firstName');
|
||||
$this->assertEquals($lastName['headers']['status-code'], 202);
|
||||
$this->assertEquals($lastName['body']['key'], 'lastName');
|
||||
$this->assertEquals($extra['headers']['status-code'], 202);
|
||||
$this->assertEquals($extra['body']['key'], 'extra');
|
||||
|
||||
// wait for database worker to kick in
|
||||
sleep(10);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertNotEmpty($webhook['data']['key']);
|
||||
$this->assertEquals($webhook['data']['key'], 'extra');
|
||||
|
||||
$removed = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $data['actorsId'] . '/columns/' . $extra['body']['key'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $removed['headers']['status-code']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
// $this->assertEquals($webhook['method'], 'DELETE');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.columns.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.columns.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertNotEmpty($webhook['data']['key']);
|
||||
$this->assertEquals($webhook['data']['key'], 'extra');
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateColumns
|
||||
*/
|
||||
public function testCreateRow(array $data): array
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$row = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'firstName' => 'Chris',
|
||||
'lastName' => 'Evans',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$documentId = $row['body']['$id'];
|
||||
|
||||
$this->assertEquals($row['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($row['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$documentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$documentId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Chris');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Evans');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(3, $webhook['data']['$permissions']);
|
||||
|
||||
$data['rowId'] = $row['body']['$id'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateRow
|
||||
*/
|
||||
public function testUpdateRow(array $data): array
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/rows/' . $data['rowId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'firstName' => 'Chris1',
|
||||
'lastName' => 'Evans2',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$rowId = $document['body']['$id'];
|
||||
|
||||
$this->assertEquals($document['headers']['status-code'], 200);
|
||||
$this->assertNotEmpty($document['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$rowId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$rowId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$rowId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$rowId}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Chris1');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Evans2');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(3, $webhook['data']['$permissions']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateTable
|
||||
*/
|
||||
#[Retry(count: 1)]
|
||||
public function testDeleteRow(array $data): array
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$row = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'firstName' => 'Bradly',
|
||||
'lastName' => 'Cooper',
|
||||
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$rowId = $row['body']['$id'];
|
||||
|
||||
$this->assertEquals($row['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($row['body']['$id']);
|
||||
|
||||
$row = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $actorsId . '/rows/' . $row['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($row['headers']['status-code'], 204);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.rows.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$rowId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.*.rows.{$rowId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$rowId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.rows.{$rowId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['firstName'], 'Bradly');
|
||||
$this->assertEquals($webhook['data']['lastName'], 'Cooper');
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(3, $webhook['data']['$permissions']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testCreateStorageBucket(): array
|
||||
{
|
||||
@@ -921,7 +1271,10 @@ trait WebhooksBase
|
||||
|
||||
$lastEmail = $this->getLastEmail();
|
||||
|
||||
$secret = substr($lastEmail['text'], strpos($lastEmail['text'], '&secret=', 0) + 8, 256);
|
||||
// `$isAppUser` — no email expected;
|
||||
$tokens = $this->extractQueryParamsFromEmailLink($lastEmail['html'] ?? '');
|
||||
|
||||
$secret = $tokens['secret'] ?? '';
|
||||
$membershipId = $team['body']['$id'];
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
|
||||
@@ -894,9 +894,9 @@ class WebhooksCustomClientTest extends Scope
|
||||
$url = $webhook['url'];
|
||||
$signatureExpected = base64_encode(hash_hmac('sha1', $url . $payload, $signatureKey, true));
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('teams.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('teams.*.memberships.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('teams.*.memberships.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -919,8 +919,8 @@ class WebhooksCustomClientTest extends Scope
|
||||
$this->assertNotEmpty($webhook['data']['userId']);
|
||||
$this->assertNotEmpty($webhook['data']['teamId']);
|
||||
$this->assertCount(2, $webhook['data']['roles']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($webhook['data']['joined']));
|
||||
$this->assertEquals(true, $webhook['data']['confirm']);
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($webhook['data']['joined']));
|
||||
$this->assertTrue($webhook['data']['confirm']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
|
||||
@@ -19,6 +19,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
|
||||
// Collection APIs
|
||||
/**
|
||||
* @depends testCreateAttributes
|
||||
*/
|
||||
@@ -39,15 +40,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
'documentSecurity' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 200);
|
||||
$this->assertEquals(200, $actors['headers']['status-code']);
|
||||
$this->assertNotEmpty($actors['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -55,9 +56,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Actors1');
|
||||
$this->assertEquals('Actors1', $webhook['data']['name']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(4, $webhook['data']['$permissions']);
|
||||
|
||||
@@ -84,8 +85,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
]);
|
||||
|
||||
$indexKey = $index['body']['key'];
|
||||
$this->assertEquals($index['headers']['status-code'], 202);
|
||||
$this->assertEquals($index['body']['key'], 'fullname');
|
||||
$this->assertEquals(202, $index['headers']['status-code']);
|
||||
$this->assertEquals('fullname', $index['body']['key']);
|
||||
|
||||
// wait for database worker to create index
|
||||
sleep(5);
|
||||
@@ -93,9 +94,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -105,7 +106,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
|
||||
// Remove index
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([
|
||||
@@ -119,8 +120,8 @@ class WebhooksCustomServerTest extends Scope
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
// $this->assertEquals($webhook['method'], 'DELETE');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.indexes.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -130,7 +131,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -172,7 +173,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
|
||||
$id = $actors['body']['$id'];
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 201);
|
||||
$this->assertEquals(201, $actors['headers']['status-code']);
|
||||
$this->assertNotEmpty($actors['body']['$id']);
|
||||
|
||||
$actors = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([
|
||||
@@ -181,14 +182,14 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
|
||||
$this->assertEquals($actors['headers']['status-code'], 204);
|
||||
$this->assertEquals(204, $actors['headers']['status-code']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.collections.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.collections.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -196,9 +197,195 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), true);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], 'Demo');
|
||||
$this->assertEquals('Demo', $webhook['data']['name']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(4, $webhook['data']['$permissions']);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// Table APIs
|
||||
/**
|
||||
* @depends testCreateColumns
|
||||
*/
|
||||
public function testUpdateTable($data): array
|
||||
{
|
||||
$id = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$actors = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/grids/tables/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'name' => 'Actors1',
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $actors['headers']['status-code']);
|
||||
$this->assertNotEmpty($actors['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$id}.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEmpty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? '');
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals('Actors1', $webhook['data']['name']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(4, $webhook['data']['$permissions']);
|
||||
|
||||
return array_merge(['actorsId' => $actors['body']['$id']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateColumns
|
||||
*/
|
||||
public function testCreateDeleteColumnIndexes($data): array
|
||||
{
|
||||
$actorsId = $data['actorsId'];
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
$index = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables/' . $data['actorsId'] . '/indexes', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'fullname',
|
||||
'type' => 'key',
|
||||
'columns' => ['lastName', 'firstName'],
|
||||
'orders' => ['ASC', 'ASC'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(202, $index['headers']['status-code']);
|
||||
$this->assertEquals('fullname', $index['body']['key']);
|
||||
|
||||
// wait for database worker to create index
|
||||
sleep(5);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
|
||||
// Remove index
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $data['actorsId'] . '/indexes/' . $index['body']['key'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
// // wait for database worker to remove index
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
// $this->assertEquals($webhook['method'], 'DELETE');
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.indexes.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$actorsId}.indexes.*.update", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertTrue(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testDeleteTable(): array
|
||||
{
|
||||
/**
|
||||
* Create database
|
||||
*/
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], $this->getHeaders()), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors DB',
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/grids/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Demo',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'rowSecurity' => true,
|
||||
]);
|
||||
|
||||
$id = $actors['body']['$id'];
|
||||
|
||||
$this->assertEquals(201, $actors['headers']['status-code']);
|
||||
$this->assertNotEmpty($actors['body']['$id']);
|
||||
|
||||
$actors = $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/grids/tables/' . $actors['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(204, $actors['headers']['status-code']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('databases.' . $databaseId . '.tables.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("databases.{$databaseId}.tables.{$id}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEmpty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? '');
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals('Demo', $webhook['data']['name']);
|
||||
$this->assertIsArray($webhook['data']['$permissions']);
|
||||
$this->assertCount(4, $webhook['data']['$permissions']);
|
||||
|
||||
@@ -224,7 +411,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
'name' => $name,
|
||||
]);
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 201);
|
||||
$this->assertEquals(201, $user['headers']['status-code']);
|
||||
$this->assertNotEmpty($user['body']['$id']);
|
||||
|
||||
$id = $user['body']['$id'];
|
||||
@@ -232,9 +419,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -245,11 +432,11 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], $name);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertEquals($webhook['data']['status'], true);
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertTrue($webhook['data']['status']);
|
||||
$this->assertEquals($webhook['data']['email'], $email);
|
||||
$this->assertEquals($webhook['data']['emailVerification'], false);
|
||||
$this->assertEquals($webhook['data']['prefs'], []);
|
||||
$this->assertFalse($webhook['data']['emailVerification']);
|
||||
$this->assertEquals([], $webhook['data']['prefs']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -274,15 +461,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
'prefs' => ['a' => 'b']
|
||||
]);
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 200);
|
||||
$this->assertEquals($user['body']['a'], 'b');
|
||||
$this->assertEquals(200, $user['headers']['status-code']);
|
||||
$this->assertEquals('b', $user['body']['a']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.update.prefs', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -293,7 +480,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertEquals($webhook['data']['a'], 'b');
|
||||
$this->assertEquals('b', $webhook['data']['a']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -315,15 +502,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
'status' => false,
|
||||
]);
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 200);
|
||||
$this->assertEquals(200, $user['headers']['status-code']);
|
||||
$this->assertNotEmpty($user['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.update.status', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -336,11 +523,11 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], $data['name']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertEquals($webhook['data']['status'], false);
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertFalse($webhook['data']['status']);
|
||||
$this->assertEquals($webhook['data']['email'], $data['email']);
|
||||
$this->assertEquals($webhook['data']['emailVerification'], false);
|
||||
$this->assertEquals($webhook['data']['prefs']['a'], 'b');
|
||||
$this->assertFalse($webhook['data']['emailVerification']);
|
||||
$this->assertEquals('b', $webhook['data']['prefs']['a']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -360,14 +547,14 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($user['headers']['status-code'], 204);
|
||||
$this->assertEquals(204, $user['headers']['status-code']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertStringContainsString('users.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString('users.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
$this->assertStringContainsString("users.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -378,11 +565,11 @@ class WebhooksCustomServerTest extends Scope
|
||||
$this->assertEquals(empty($webhook['headers']['X-Appwrite-Webhook-User-Id'] ?? ''), ('server' === $this->getSide()));
|
||||
$this->assertNotEmpty($webhook['data']['$id']);
|
||||
$this->assertEquals($webhook['data']['name'], $data['name']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertEquals($webhook['data']['status'], false);
|
||||
$this->assertTrue((new DatetimeValidator())->isValid($webhook['data']['registration']));
|
||||
$this->assertFalse($webhook['data']['status']);
|
||||
$this->assertEquals($webhook['data']['email'], $data['email']);
|
||||
$this->assertEquals($webhook['data']['emailVerification'], false);
|
||||
$this->assertEquals($webhook['data']['prefs']['a'], 'b');
|
||||
$this->assertFalse($webhook['data']['emailVerification']);
|
||||
$this->assertEquals('b', $webhook['data']['prefs']['a']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -399,22 +586,22 @@ class WebhooksCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
$id = $function['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 201);
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
|
||||
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
|
||||
@@ -439,15 +626,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test',
|
||||
'runtime' => 'php-8.0',
|
||||
'entrypoint' => 'index.php',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'execute' => [Role::any()->toString()],
|
||||
'vars' => [
|
||||
'key1' => 'value1',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals($function['headers']['status-code'], 200);
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals($function['body']['$id'], $data['functionId']);
|
||||
|
||||
// Create variable
|
||||
@@ -464,9 +651,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -496,7 +683,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'entrypoint' => 'index.php',
|
||||
'entrypoint' => 'index.js',
|
||||
'code' => new CURLFile($code, 'application/x-gzip', \basename($code)),
|
||||
'activate' => true
|
||||
]);
|
||||
@@ -504,15 +691,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
$functionId = $data['functionId'] ?? '';
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 202);
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString("functions.*.deployments.{$deploymentId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -544,7 +731,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
// Wait for deployment to be built.
|
||||
@@ -553,9 +740,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.deployments.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -596,14 +783,14 @@ class WebhooksCustomServerTest extends Scope
|
||||
|
||||
$executionId = $execution['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEquals($execution['headers']['status-code'], 202);
|
||||
$this->assertEquals(202, $execution['headers']['status-code']);
|
||||
$this->assertNotEmpty($execution['body']['$id']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.executions.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -624,9 +811,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.executions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.executions.*.update', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -663,15 +850,15 @@ class WebhooksCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals($deployment['headers']['status-code'], 204);
|
||||
$this->assertEquals(204, $deployment['headers']['status-code']);
|
||||
$this->assertEmpty($deployment['body']);
|
||||
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.deployments.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.deployments.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
@@ -714,9 +901,9 @@ class WebhooksCustomServerTest extends Scope
|
||||
$webhook = $this->getLastRequest();
|
||||
$signatureExpected = self::getWebhookSignature($webhook, $this->getProject()['signatureKey']);
|
||||
|
||||
$this->assertEquals($webhook['method'], 'POST');
|
||||
$this->assertEquals($webhook['headers']['Content-Type'], 'application/json');
|
||||
$this->assertEquals($webhook['headers']['User-Agent'], 'Appwrite-Server vdev. Please report abuse at security@appwrite.io');
|
||||
$this->assertEquals('POST', $webhook['method']);
|
||||
$this->assertEquals('application/json', $webhook['headers']['Content-Type']);
|
||||
$this->assertEquals('Appwrite-Server vdev. Please report abuse at security@appwrite.io', $webhook['headers']['User-Agent']);
|
||||
// $this->assertStringContainsString('functions.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString('functions.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
// $this->assertStringContainsString("functions.{$id}", $webhook['headers']['X-Appwrite-Webhook-Events']);
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
module.exports = async(context) => {
|
||||
context.log('log-works');
|
||||
context.error('error-log-works');
|
||||
|
||||
if(context.req.headers['x-appwrite-user-jwt']) {
|
||||
context.log('jwt-is-valid');
|
||||
} else {
|
||||
context.log('jwt-is-invalid');
|
||||
}
|
||||
|
||||
if(context.req.path === '/custom-response') {
|
||||
const code = +(context.req.query['code'] || '200');
|
||||
const body = context.req.query['body'] || '';
|
||||
return context.res.send(body, code);
|
||||
}
|
||||
|
||||
context.log('body-is-' + (context.req.body ?? ''));
|
||||
context.log('custom-header-is-' + (context.req.headers['x-custom-header'] ?? ''));
|
||||
context.log('method-is-' + (context.req.method ?? '').toLowerCase());
|
||||
context.log('path-is-' + (context.req.path ?? ''));
|
||||
context.log('user-is-' + (context.req.headers['x-appwrite-user-id'] ?? ''));
|
||||
|
||||
const statusCode = context.req.query['code'] || '200';
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : process.env.APPWRITE_FUNCTION_NAME ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : process.env.APPWRITE_FUNCTION_DEPLOYMENT ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME,
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION,
|
||||
'APPWRITE_VERSION' : process.env.APPWRITE_VERSION ?? '',
|
||||
'APPWRITE_REGION' : process.env.APPWRITE_REGION ?? '',
|
||||
'UNICODE_TEST' : "êä",
|
||||
'GLOBAL_VARIABLE' : process.env.GLOBAL_VARIABLE ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
|
||||
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
|
||||
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
|
||||
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
|
||||
}, +statusCode);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
const crypto = require('crypto')
|
||||
|
||||
module.exports = async(context) => {
|
||||
const hash = crypto.createHash('md5').update(context.req.bodyBinary).digest("hex")
|
||||
return context.res.send(hash);
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = async(context) => {
|
||||
const bytes = Buffer.from(Uint8Array.from([0, 10, 255]));
|
||||
return context.res.binary(bytes);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
return context.res.send(context.req.headers['cookie'] ?? '');
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
Future<dynamic> main(final context) async {
|
||||
context.log('Amazing Function Log');
|
||||
|
||||
response.json({
|
||||
'APPWRITE_FUNCTION_ID' : Platform.environment['APPWRITE_FUNCTION_ID'] ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : Platform.environment['APPWRITE_FUNCTION_NAME'] ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : Platform.environment['APPWRITE_FUNCTION_DEPLOYMENT'] ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_NAME'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : Platform.environment['APPWRITE_FUNCTION_RUNTIME_VERSION'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : Platform.environment['APPWRITE_FUNCTION_PROJECT_ID'] ?? '',
|
||||
'CUSTOM_VARIABLE' : request.variables['CUSTOM_VARIABLE']
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
module.exports = async(context) => {
|
||||
const client = new sdk.Client();
|
||||
client.setEndpoint(process.env.APPWRITE_FUNCTION_API_ENDPOINT);
|
||||
client.setProject(process.env.APPWRITE_FUNCTION_PROJECT_ID);
|
||||
client.setKey(context.req.headers['x-appwrite-key']);
|
||||
|
||||
const users = new sdk.Users(client);
|
||||
|
||||
const response = await users.list();
|
||||
context.log(JSON.stringify(response));
|
||||
|
||||
return context.res.json(response);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-appwrite": "^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-appwrite": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-appwrite/-/node-appwrite-17.0.0.tgz",
|
||||
"integrity": "sha512-5Moi5ENPnoAfU1/6CZP9K2NTuB6Nm3dSyhokno+24RDuP7czjXCdwzfeyjmyHieggbrLkN89AYSOv9W1XkCL9w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"node-fetch-native-with-agent": "1.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch-native-with-agent": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch-native-with-agent/-/node-fetch-native-with-agent-1.7.2.tgz",
|
||||
"integrity": "sha512-5MaOOCuJEvcckoz7/tjdx1M6OusOY6Xc5f459IaruGStWnKzlI1qpNgaAwmn4LmFYcsSlj+jBMk84wmmRxfk5g==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "dynamic-api-key",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"node-appwrite": "^17.0.0"
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
|
||||
ENDPOINT="$APPWRITE_FUNCTION_API_ENDPOINT/users"
|
||||
PROJECT_ID="$APPWRITE_FUNCTION_PROJECT_ID"
|
||||
API_KEY="$APPWRITE_FUNCTION_API_KEY"
|
||||
|
||||
apk add curl
|
||||
|
||||
curl -v -X GET $ENDPOINT -H "x-appwrite-project: $PROJECT_ID" -H "x-appwrite-key: $API_KEY"
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = async(context) => {
|
||||
context.log(context.req.body.$id);
|
||||
context.log(context.req.body.name);
|
||||
return context.res.empty();
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
return context.res.empty();
|
||||
};
|
||||
@@ -1,21 +1,3 @@
|
||||
module.exports = async(context) => {
|
||||
context.log('Amazing Function Log');
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : process.env.APPWRITE_FUNCTION_ID ?? '',
|
||||
'APPWRITE_FUNCTION_NAME' : process.env.APPWRITE_FUNCTION_NAME ?? '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : process.env.APPWRITE_FUNCTION_DEPLOYMENT ?? '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : process.env.APPWRITE_FUNCTION_RUNTIME_NAME,
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : process.env.APPWRITE_FUNCTION_RUNTIME_VERSION,
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : process.env.APPWRITE_FUNCTION_PROJECT_ID,
|
||||
'APPWRITE_FUNCTION_MEMORY' : process.env.APPWRITE_FUNCTION_MEMORY,
|
||||
'APPWRITE_FUNCTION_CPUS' : process.env.APPWRITE_FUNCTION_CPUS,
|
||||
'CUSTOM_VARIABLE' : process.env.CUSTOM_VARIABLE
|
||||
});
|
||||
return context.res.send('OK');
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$hash = md5($context->req->bodyBinary);
|
||||
return $context->res->send($hash);
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$bytes = pack('C*', ...[0, 10, 255]);
|
||||
return $context->res->binary($bytes);
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
return $context->res->send($context->req->headers['cookie'] ?? '');
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$context->log($context->req->body['$id']);
|
||||
$context->log($context->req->body['name']);
|
||||
|
||||
return $context->res->empty();
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
$context->log('Amazing Function Log');
|
||||
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_VERSION' => \getenv('APPWRITE_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'APPWRITE_FUNCTION_EVENT' => $context->req->headers['x-appwrite-event'] ?? '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => $context->req->bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_DATA' => $context->req->bodyRaw ?? '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => $context->req->headers['x-appwrite-user-id'] ?? '',
|
||||
'APPWRITE_FUNCTION_JWT' => $context->req->headers['x-appwrite-user-jwt'] ?? '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => \getenv('APPWRITE_FUNCTION_PROJECT_ID') ?: '',
|
||||
'CUSTOM_VARIABLE' => \getenv('CUSTOM_VARIABLE') ?: '',
|
||||
]);
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "appwrite/cloud-function-demo",
|
||||
"description": "Demo cloud function script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "1.1.*"
|
||||
}
|
||||
}
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "afdff6a172e6c44aee11f1562175f81a",
|
||||
"packages": [
|
||||
{
|
||||
"name": "appwrite/appwrite",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-for-php.git",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-for-php/zipball/98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"reference": "98b327d3fd18a72f4582019916afd735a0e9e0e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"php": ">=7.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "3.7.35"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Appwrite\\": "src/Appwrite"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "Appwrite is an open-source backend as a service server that abstract and simplify complex and repetitive development tasks",
|
||||
"support": {
|
||||
"email": "team@localhost.test",
|
||||
"issues": "https://github.com/appwrite/sdk-for-php/issues",
|
||||
"source": "https://github.com/appwrite/sdk-for-php/tree/1.1.2",
|
||||
"url": "https://appwrite.io/support"
|
||||
},
|
||||
"time": "2020-08-15T18:24:32+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '',
|
||||
'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '',
|
||||
'UNICODE_TEST' => "êä"
|
||||
]);
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "appwrite/php-scopes",
|
||||
"description": "PHP scopes test script",
|
||||
"type": "library",
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Team Appwrite",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"appwrite/appwrite": "11.0.*"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use Appwrite\Client;
|
||||
use Appwrite\Services\Users;
|
||||
|
||||
return function ($context) {
|
||||
$client = new Client();
|
||||
$client
|
||||
->setEndpoint(getenv('APPWRITE_FUNCTION_API_ENDPOINT'))
|
||||
->setProject(getenv('APPWRITE_FUNCTION_PROJECT_ID'))
|
||||
->setKey($context->req->headers['x-appwrite-key']);
|
||||
$users = new Users($client);
|
||||
$response = $users->list();
|
||||
$context->log($response);
|
||||
return $context->res->json($response);
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($req, $res) {
|
||||
$res->json([
|
||||
'v2Woks' => true
|
||||
]);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
if ($context->req->path === '/custom-response') {
|
||||
$code = (int) ($context->req->query['code'] ?? '200');
|
||||
$body = $context->req->query['body'] ?? '';
|
||||
return $context->res->send($body, $code);
|
||||
}
|
||||
|
||||
$context->log('body-is-' . ($context->req->body ?? ''));
|
||||
$context->log('custom-header-is-' . ($context->req->headers['x-custom-header'] ?? ''));
|
||||
$context->log('method-is-' . \strtolower($context->req->method ?? ''));
|
||||
$context->log('path-is-' . ($context->req->path ?? ''));
|
||||
$context->log('user-is-' . $context->req->headers['x-appwrite-user-id'] ?? '');
|
||||
|
||||
if (empty($context->req->headers['x-appwrite-user-jwt'] ?? '')) {
|
||||
$context->log('jwt-is-invalid');
|
||||
} else {
|
||||
$context->log('jwt-is-valid');
|
||||
}
|
||||
|
||||
$context->error('error-log-works');
|
||||
|
||||
$statusCode = $context->req->query['code'] ?? '200';
|
||||
|
||||
return $context->res->json([
|
||||
'APPWRITE_FUNCTION_ID' => \getenv('APPWRITE_FUNCTION_ID') ?: '',
|
||||
'APPWRITE_FUNCTION_NAME' => \getenv('APPWRITE_FUNCTION_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => \getenv('APPWRITE_FUNCTION_DEPLOYMENT') ?: '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => $context->req->headers['x-appwrite-trigger'] ?? '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => \getenv('APPWRITE_FUNCTION_RUNTIME_NAME') ?: '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => \getenv('APPWRITE_FUNCTION_RUNTIME_VERSION') ?: '',
|
||||
'APPWRITE_REGION' => \getenv('APPWRITE_REGION') ?: '',
|
||||
'UNICODE_TEST' => "êä",
|
||||
'GLOBAL_VARIABLE' => \getenv('GLOBAL_VARIABLE') ?: '',
|
||||
'APPWRITE_FUNCTION_CPUS' => \getenv('APPWRITE_FUNCTION_CPUS') ?: '',
|
||||
'APPWRITE_FUNCTION_MEMORY' => \getenv('APPWRITE_FUNCTION_MEMORY') ?: '',
|
||||
], \intval($statusCode));
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
def main(context):
|
||||
context.log('Amazing Function Log')
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' : os.environ.get('APPWRITE_FUNCTION_ID',''),
|
||||
'APPWRITE_FUNCTION_NAME' : os.environ.get('APPWRITE_FUNCTION_NAME',''),
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' : os.environ.get('APPWRITE_FUNCTION_DEPLOYMENT',''),
|
||||
'APPWRITE_FUNCTION_TRIGGER' : context.req.headers.get('x-appwrite-trigger', ''),
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_NAME',''),
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' : os.environ.get('APPWRITE_FUNCTION_RUNTIME_VERSION',''),
|
||||
'APPWRITE_FUNCTION_EVENT' : context.req.headers.get('x-appwrite-event', ''),
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' : context.req.body_raw,
|
||||
'APPWRITE_FUNCTION_DATA' : context.req.body_raw,
|
||||
'APPWRITE_FUNCTION_USER_ID' : context.req.headers.get('x-appwrite-user-id', ''),
|
||||
'APPWRITE_FUNCTION_JWT' : context.req.headers.get('x-appwrite-user-jwt', ''),
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' : os.environ.get('APPWRITE_FUNCTION_PROJECT_ID',''),
|
||||
'CUSTOM_VARIABLE' : os.environ.get('CUSTOM_VARIABLE',''),
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
def main(context)
|
||||
context.log('Amazing Function Log')
|
||||
|
||||
return context.res.json({
|
||||
'APPWRITE_FUNCTION_ID' => ENV['APPWRITE_FUNCTION_ID'] || '',
|
||||
'APPWRITE_FUNCTION_NAME' => ENV['APPWRITE_FUNCTION_NAME'] || '',
|
||||
'APPWRITE_FUNCTION_DEPLOYMENT' => ENV['APPWRITE_FUNCTION_DEPLOYMENT'] || '',
|
||||
'APPWRITE_FUNCTION_TRIGGER' => context.req.headers['x-appwrite-trigger'] || '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_NAME' => ENV['APPWRITE_FUNCTION_RUNTIME_NAME'] || '',
|
||||
'APPWRITE_FUNCTION_RUNTIME_VERSION' => ENV['APPWRITE_FUNCTION_RUNTIME_VERSION'] || '',
|
||||
'APPWRITE_FUNCTION_EVENT' => context.req.headers['x-appwrite-event'] || '',
|
||||
'APPWRITE_FUNCTION_EVENT_DATA' => context.req.body_raw || '',
|
||||
'APPWRITE_FUNCTION_DATA' => context.req.body_raw || '',
|
||||
'APPWRITE_FUNCTION_USER_ID' => context.req.headers['x-appwrite-user-id'] || '',
|
||||
'APPWRITE_FUNCTION_JWT' => context.req.headers['x-appwrite-user-jwt'] || '',
|
||||
'APPWRITE_FUNCTION_PROJECT_ID' => ENV['APPWRITE_FUNCTION_PROJECT_ID'] || '',
|
||||
'CUSTOM_VARIABLE' => ENV['CUSTOM_VARIABLE'] || ''
|
||||
})
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
func main(req: RequestValue, res: RequestResponse) throws -> RequestResponse {
|
||||
return res.json(data: [
|
||||
"APPWRITE_FUNCTION_ID": req.variables["APPWRITE_FUNCTION_ID"],
|
||||
"APPWRITE_FUNCTION_NAME": req.variables["APPWRITE_FUNCTION_NAME"],
|
||||
"APPWRITE_FUNCTION_DEPLOYMENT": req.variables["APPWRITE_FUNCTION_DEPLOYMENT"],
|
||||
"APPWRITE_FUNCTION_TRIGGER": req.variables["APPWRITE_FUNCTION_TRIGGER"],
|
||||
"APPWRITE_FUNCTION_RUNTIME_NAME": req.variables["APPWRITE_FUNCTION_RUNTIME_NAME"],
|
||||
"APPWRITE_FUNCTION_RUNTIME_VERSION": req.variables["APPWRITE_FUNCTION_RUNTIME_VERSION"],
|
||||
"APPWRITE_FUNCTION_EVENT": req.variables["APPWRITE_FUNCTION_EVENT"],
|
||||
"APPWRITE_FUNCTION_EVENT_DATA": req.variables["APPWRITE_FUNCTION_EVENT_DATA"],
|
||||
"APPWRITE_FUNCTION_DATA": req.variables["APPWRITE_FUNCTION_DATA"],
|
||||
"APPWRITE_FUNCTION_USER_ID": req.variables["APPWRITE_FUNCTION_USER_ID"],
|
||||
"APPWRITE_FUNCTION_JWT": req.variables["APPWRITE_FUNCTION_JWT"],
|
||||
"APPWRITE_FUNCTION_PROJECT_ID": req.variables["APPWRITE_FUNCTION_PROJECT_ID"],
|
||||
"CUSTOM_VARIABLE": req.variables["CUSTOM_VARIABLE"]
|
||||
])
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = async(context) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000 * 60));
|
||||
return context.res.send('OK');
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
return function ($context) {
|
||||
sleep(60);
|
||||
return $context->res->send('OK');
|
||||
};
|
||||
@@ -93,57 +93,57 @@ class EventTest extends TestCase
|
||||
$this->assertContains('users.*.update', $event);
|
||||
$this->assertContains('users.*', $event);
|
||||
|
||||
$event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [
|
||||
'collectionId' => 'chapters',
|
||||
'documentId' => 'prolog',
|
||||
$event = Event::generateEvents('tables.[tableId].rows.[rowId].create', [
|
||||
'tableId' => 'chapters',
|
||||
'rowId' => 'prolog',
|
||||
]);
|
||||
$this->assertCount(10, $event);
|
||||
|
||||
$this->assertContains('collections.chapters.documents.prolog.create', $event);
|
||||
$this->assertContains('collections.chapters.documents.prolog', $event);
|
||||
$this->assertContains('collections.chapters.documents.*.create', $event);
|
||||
$this->assertContains('collections.chapters.documents.*', $event);
|
||||
$this->assertContains('collections.chapters', $event);
|
||||
$this->assertContains('collections.*.documents.prolog.create', $event);
|
||||
$this->assertContains('collections.*.documents.prolog', $event);
|
||||
$this->assertContains('collections.*.documents.*.create', $event);
|
||||
$this->assertContains('collections.*.documents.*', $event);
|
||||
$this->assertContains('collections.*', $event);
|
||||
$this->assertContains('tables.chapters.rows.prolog.create', $event);
|
||||
$this->assertContains('tables.chapters.rows.prolog', $event);
|
||||
$this->assertContains('tables.chapters.rows.*.create', $event);
|
||||
$this->assertContains('tables.chapters.rows.*', $event);
|
||||
$this->assertContains('tables.chapters', $event);
|
||||
$this->assertContains('tables.*.rows.prolog.create', $event);
|
||||
$this->assertContains('tables.*.rows.prolog', $event);
|
||||
$this->assertContains('tables.*.rows.*.create', $event);
|
||||
$this->assertContains('tables.*.rows.*', $event);
|
||||
$this->assertContains('tables.*', $event);
|
||||
|
||||
$event = Event::generateEvents('databases.[databaseId].collections.[collectionId].documents.[documentId].create', [
|
||||
$event = Event::generateEvents('databases.[databaseId].tables.[tableId].rows.[rowId].create', [
|
||||
'databaseId' => 'chaptersDB',
|
||||
'collectionId' => 'chapters',
|
||||
'documentId' => 'prolog',
|
||||
'tableId' => 'chapters',
|
||||
'rowId' => 'prolog',
|
||||
]);
|
||||
|
||||
$this->assertCount(22, $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.chapters.documents.prolog.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.chapters.documents.prolog', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.chapters.documents.*.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.chapters.documents.*', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.chapters', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.*.documents.prolog.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.*.documents.prolog', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.*', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.chapters.rows.prolog.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.chapters.rows.prolog', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.chapters.rows.*.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.chapters.rows.*', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.chapters', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.*.rows.prolog.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.*.rows.prolog', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.*', $event);
|
||||
$this->assertContains('databases.chaptersDB', $event);
|
||||
$this->assertContains('databases.*.collections.chapters.documents.prolog.create', $event);
|
||||
$this->assertContains('databases.*.collections.chapters.documents.prolog', $event);
|
||||
$this->assertContains('databases.*.collections.chapters', $event);
|
||||
$this->assertContains('databases.*.collections.*.documents.*.create', $event);
|
||||
$this->assertContains('databases.*.collections.*.documents.*', $event);
|
||||
$this->assertContains('databases.*.collections.*', $event);
|
||||
$this->assertContains('databases.*.tables.chapters.rows.prolog.create', $event);
|
||||
$this->assertContains('databases.*.tables.chapters.rows.prolog', $event);
|
||||
$this->assertContains('databases.*.tables.chapters', $event);
|
||||
$this->assertContains('databases.*.tables.*.rows.*.create', $event);
|
||||
$this->assertContains('databases.*.tables.*.rows.*', $event);
|
||||
$this->assertContains('databases.*.tables.*', $event);
|
||||
$this->assertContains('databases.*', $event);
|
||||
$this->assertContains('databases.*.collections.*.documents.prolog', $event);
|
||||
$this->assertContains('databases.*.collections.*.documents.prolog.create', $event);
|
||||
$this->assertContains('databases.*.collections.chapters.documents.*', $event);
|
||||
$this->assertContains('databases.*.collections.chapters.documents.*.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.*.documents.*', $event);
|
||||
$this->assertContains('databases.chaptersDB.collections.*.documents.*.create', $event);
|
||||
$this->assertContains('databases.*.tables.*.rows.prolog', $event);
|
||||
$this->assertContains('databases.*.tables.*.rows.prolog.create', $event);
|
||||
$this->assertContains('databases.*.tables.chapters.rows.*', $event);
|
||||
$this->assertContains('databases.*.tables.chapters.rows.*.create', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.*.rows.*', $event);
|
||||
$this->assertContains('databases.chaptersDB.tables.*.rows.*.create', $event);
|
||||
|
||||
|
||||
try {
|
||||
$event = Event::generateEvents('collections.[collectionId].documents.[documentId].create', [
|
||||
'collectionId' => 'chapters'
|
||||
$event = Event::generateEvents('tables.[tableId].rows.[rowId].create', [
|
||||
'tableId' => 'chapters'
|
||||
]);
|
||||
$this->fail();
|
||||
} catch (\Throwable $th) {
|
||||
@@ -151,7 +151,7 @@ class EventTest extends TestCase
|
||||
}
|
||||
|
||||
try {
|
||||
$event = Event::generateEvents('collections.[collectionId].documents.[documentId].create');
|
||||
$event = Event::generateEvents('tables.[tableId].rows.[rowId].create');
|
||||
$this->fail();
|
||||
} catch (\Throwable $th) {
|
||||
$this->assertInstanceOf(InvalidArgumentException::class, $th, 'An invalid exception was thrown');
|
||||
|
||||
@@ -7,7 +7,7 @@ use Utopia\Queue\Queue;
|
||||
|
||||
class MockPublisher implements Publisher
|
||||
{
|
||||
private $events = [];
|
||||
private array $events = [];
|
||||
|
||||
public function enqueue(Queue $queue, array $payload): bool
|
||||
{
|
||||
|
||||
@@ -29,27 +29,27 @@ class EventValidatorTest extends TestCase
|
||||
$this->assertTrue($this->object->isValid('users.*.update.email'));
|
||||
$this->assertTrue($this->object->isValid('users.*.update'));
|
||||
$this->assertTrue($this->object->isValid('users.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*'));
|
||||
$this->assertTrue($this->object->isValid('functions.*'));
|
||||
$this->assertTrue($this->object->isValid('buckets.*'));
|
||||
$this->assertTrue($this->object->isValid('teams.*'));
|
||||
@@ -63,9 +63,9 @@ class EventValidatorTest extends TestCase
|
||||
$this->assertFalse($this->object->isValid(null));
|
||||
$this->assertFalse($this->object->isValid(''));
|
||||
$this->assertFalse($this->object->isValid('unknown.*'));
|
||||
$this->assertFalse($this->object->isValid('collections'));
|
||||
$this->assertFalse($this->object->isValid('collections.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('collections.*.documents.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('tables'));
|
||||
$this->assertFalse($this->object->isValid('tables.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('tables.*.rows.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('users.torsten.unknown'));
|
||||
$this->assertFalse($this->object->isValid('users.torsten.delete.email'));
|
||||
$this->assertFalse($this->object->isValid('teams.*.memberships.*.update.unknown'));
|
||||
|
||||
@@ -29,27 +29,27 @@ class FunctionEventValidatorTest extends TestCase
|
||||
$this->assertTrue($this->object->isValid('users.*.update.email'));
|
||||
$this->assertTrue($this->object->isValid('users.*.update'));
|
||||
$this->assertTrue($this->object->isValid('users.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.chapters.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*.documents.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.collections.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.chapters.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.prolog.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.prolog'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.*.create'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*.rows.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*.tables.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.chapters'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.collections.*'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.chapters'));
|
||||
$this->assertTrue($this->object->isValid('databases.books.tables.*'));
|
||||
$this->assertTrue($this->object->isValid('buckets.*'));
|
||||
$this->assertTrue($this->object->isValid('teams.*'));
|
||||
$this->assertTrue($this->object->isValid('users.*'));
|
||||
@@ -62,9 +62,9 @@ class FunctionEventValidatorTest extends TestCase
|
||||
$this->assertFalse($this->object->isValid(null));
|
||||
$this->assertFalse($this->object->isValid(''));
|
||||
$this->assertFalse($this->object->isValid('unknown.*'));
|
||||
$this->assertFalse($this->object->isValid('collections'));
|
||||
$this->assertFalse($this->object->isValid('collections.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('collections.*.documents.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('tables'));
|
||||
$this->assertFalse($this->object->isValid('tables.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('tables.*.rows.*.unknown'));
|
||||
$this->assertFalse($this->object->isValid('users.torsten.unknown'));
|
||||
$this->assertFalse($this->object->isValid('users.torsten.delete.email'));
|
||||
$this->assertFalse($this->object->isValid('teams.*.memberships.*.update.unknown'));
|
||||
|
||||
@@ -22,8 +22,8 @@ class BuilderTest extends TestCase
|
||||
*/
|
||||
public function testCreateTypeMapping()
|
||||
{
|
||||
$model = $this->response->getModel(Response::MODEL_COLLECTION);
|
||||
$model = $this->response->getModel(Response::MODEL_TABLE);
|
||||
$type = Mapper::model(\ucfirst($model->getType()));
|
||||
$this->assertEquals('Collection', $type->name);
|
||||
$this->assertEquals('Table', $type->name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ abstract class MigrationTest extends TestCase
|
||||
foreach (Migration::$versions as $class) {
|
||||
$this->assertTrue(class_exists('Appwrite\\Migration\\Version\\' . $class));
|
||||
}
|
||||
|
||||
// Test if current version exists
|
||||
// Only test official releases - skip if latest is release candidate
|
||||
if (!(\str_contains(APP_VERSION_STABLE, 'RC'))) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Tests\Unit\Network\Validators;
|
||||
|
||||
use Appwrite\Network\Platform;
|
||||
use Appwrite\Network\Validator\Origin;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
@@ -14,62 +15,99 @@ class OriginTest extends TestCase
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Production',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'appwrite.io',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Development',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'appwrite.test',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Localhost',
|
||||
'type' => Origin::CLIENT_TYPE_WEB,
|
||||
'type' => Platform::TYPE_WEB,
|
||||
'hostname' => 'localhost',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Flutter',
|
||||
'type' => Origin::CLIENT_TYPE_FLUTTER_WEB,
|
||||
'type' => Platform::TYPE_FLUTTER_WEB,
|
||||
'hostname' => 'appwrite.flutter',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Expo',
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'key' => 'exp',
|
||||
],
|
||||
[
|
||||
'$collection' => ID::custom('platforms'),
|
||||
'name' => 'Appwrite Callback',
|
||||
'type' => Platform::TYPE_SCHEME,
|
||||
'key' => 'appwrite-callback-123',
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals($validator->isValid('https://localhost'), true);
|
||||
$this->assertEquals($validator->isValid('http://localhost'), true);
|
||||
$this->assertEquals($validator->isValid('http://localhost:80'), true);
|
||||
$this->assertEquals(false, $validator->isValid(''));
|
||||
$this->assertEquals(false, $validator->isValid('/'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.io'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.io'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.io:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://localhost'));
|
||||
$this->assertEquals(true, $validator->isValid('http://localhost'));
|
||||
$this->assertEquals(true, $validator->isValid('http://localhost:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.test'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.test'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.test:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.io'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.io'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.io:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://appwrite.flutter'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.flutter'), true);
|
||||
$this->assertEquals($validator->isValid('http://appwrite.flutter:80'), true);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.test'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.test'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.test:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('https://example.com'), false);
|
||||
$this->assertEquals($validator->isValid('http://example.com'), false);
|
||||
$this->assertEquals($validator->isValid('http://example.com:80'), false);
|
||||
$this->assertEquals(true, $validator->isValid('https://appwrite.flutter'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.flutter'));
|
||||
$this->assertEquals(true, $validator->isValid('http://appwrite.flutter:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-ios://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new iOS platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('https://example.com'));
|
||||
$this->assertEquals(false, $validator->isValid('http://example.com'));
|
||||
$this->assertEquals(false, $validator->isValid('http://example.com:80'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-android://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Android platform on your project console dashboard');
|
||||
$this->assertEquals(true, $validator->isValid('exp://'));
|
||||
$this->assertEquals(true, $validator->isValid('exp:///'));
|
||||
$this->assertEquals(true, $validator->isValid('exp://index'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-macos://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new macOS platform on your project console dashboard');
|
||||
$this->assertEquals(true, $validator->isValid('appwrite-callback-123://'));
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-callback-456://'));
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-linux://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Linux platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-ios://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new iOS platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals($validator->isValid('appwrite-windows://com.company.appname'), false);
|
||||
$this->assertEquals($validator->getDescription(), 'Invalid Origin. Register your new client (com.company.appname) as a new Windows platform on your project console dashboard');
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-android://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Android platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-macos://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new macOS platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-linux://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Linux platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('appwrite-windows://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Windows platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('chrome-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Chrome Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('moz-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Firefox Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('safari-web-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Safari Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('ms-browser-extension://com.company.appname'));
|
||||
$this->assertEquals('Invalid Origin. Register your new client (com.company.appname) as a new Web (Edge Extension) platform on your project console dashboard', $validator->getDescription());
|
||||
|
||||
$this->assertEquals(false, $validator->isValid('random-scheme://localhost'));
|
||||
$this->assertEquals('Invalid Scheme. The scheme used (random-scheme) in the Origin (random-scheme://localhost) is not supported. If you are using a custom scheme, please change it to `appwrite-callback-<PROJECT_ID>`', $validator->getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,15 @@ class URLTest extends TestCase
|
||||
$this->assertEquals(null, $url['port']);
|
||||
$this->assertEquals('', $url['path']);
|
||||
$this->assertEquals('', $url['query']);
|
||||
|
||||
$url = URL::parse('appwrite-callback-project://');
|
||||
|
||||
$this->assertIsArray($url);
|
||||
$this->assertEquals('appwrite-callback-project', $url['scheme']);
|
||||
$this->assertEquals('', $url['host']);
|
||||
$this->assertEquals(null, $url['port']);
|
||||
$this->assertEquals('', $url['path']);
|
||||
$this->assertEquals('', $url['query']);
|
||||
}
|
||||
|
||||
public function testUnparse(): void
|
||||
@@ -86,6 +95,19 @@ class URLTest extends TestCase
|
||||
|
||||
$this->assertIsString($url);
|
||||
$this->assertEquals('https://eldad:fux@appwrite.io/#bottom', $url);
|
||||
|
||||
$url = URL::unparse([
|
||||
'scheme' => 'https',
|
||||
'user' => '',
|
||||
'pass' => '',
|
||||
'host' => 'appwrite.io',
|
||||
'port' => null,
|
||||
'path' => '',
|
||||
'fragment' => '',
|
||||
]);
|
||||
|
||||
$this->assertIsString($url);
|
||||
$this->assertEquals('https://appwrite.io/#', $url);
|
||||
}
|
||||
|
||||
public function testParseQuery(): void
|
||||
|
||||
Reference in New Issue
Block a user