Merge branch '1.7.x' into pla-2677

This commit is contained in:
Chirag Aggarwal
2025-04-02 08:34:08 +00:00
18 changed files with 454 additions and 24 deletions
+7
View File
@@ -1417,6 +1417,13 @@ return [
'lengths' => [],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_roles'),
'type' => Database::INDEX_KEY,
'attributes' => ['roles'],
'lengths' => [128],
'orders' => [],
],
],
],
+11
View File
@@ -1665,6 +1665,17 @@ return [
'array' => false,
'filters' => ['encrypt']
],
[
'$id' => ID::custom('secret'),
'type' => Database::VAR_BOOLEAN,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => false,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('search'),
'type' => Database::VAR_STRING,
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -6859,7 +6859,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
+26 -2
View File
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -25889,7 +25889,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
@@ -27982,6 +27982,30 @@
"x-example": "<USER_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"schema": {
"type": "string",
"x-example": "<SEARCH>",
"default": ""
},
"in": "query"
}
]
}
+26 -2
View File
@@ -1,7 +1,7 @@
{
"openapi": "3.0.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -18099,7 +18099,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
@@ -20153,6 +20153,30 @@
"x-example": "<USER_ID>"
},
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"schema": {
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"schema": {
"type": "string",
"x-example": "<SEARCH>",
"default": ""
},
"in": "query"
}
]
}
+2 -2
View File
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -7069,7 +7069,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
+23 -2
View File
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -26371,7 +26371,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
@@ -28514,6 +28514,27 @@
"type": "string",
"x-example": "<USER_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"type": "string",
"x-example": "<SEARCH>",
"default": "",
"in": "query"
}
]
}
+23 -2
View File
@@ -1,7 +1,7 @@
{
"swagger": "2.0",
"info": {
"version": "1.6.1",
"version": "1.6.2",
"title": "Appwrite",
"description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)",
"termsOfService": "https:\/\/appwrite.io\/policy\/terms",
@@ -18565,7 +18565,7 @@
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
@@ -20669,6 +20669,27 @@
"type": "string",
"x-example": "<USER_ID>",
"in": "path"
},
{
"name": "queries",
"description": "Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https:\/\/appwrite.io\/docs\/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles",
"required": false,
"type": "array",
"collectionFormat": "multi",
"items": {
"type": "string"
},
"default": [],
"in": "query"
},
{
"name": "search",
"description": "Search term to filter your list results. Max length: 256 chars.",
"required": false,
"type": "string",
"x-example": "<SEARCH>",
"default": "",
"in": "query"
}
]
}
+3 -1
View File
@@ -2516,10 +2516,11 @@ App::post('/v1/functions/:functionId/variables')
->param('functionId', '', new UID(), 'Function unique ID.', false)
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true)
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject, Database $dbForPlatform) {
->action(function (string $functionId, string $key, string $value, bool $secret, Response $response, Database $dbForProject, Database $dbForPlatform) {
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
@@ -2540,6 +2541,7 @@ App::post('/v1/functions/:functionId/variables')
'resourceType' => 'function',
'key' => $key,
'value' => $value,
'secret' => $secret,
'search' => implode(' ', [$variableId, $function->getId(), $key, 'function']),
]);
+4 -1
View File
@@ -17,6 +17,7 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Datetime as DateTimeValidator;
use Utopia\Database\Validator\UID;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
@@ -399,11 +400,12 @@ App::post('/v1/project/variables')
))
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true)
->inject('project')
->inject('response')
->inject('dbForProject')
->inject('dbForPlatform')
->action(function (string $key, string $value, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
->action(function (string $key, string $value, bool $secret, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
$variableId = ID::unique();
$variable = new Document([
@@ -418,6 +420,7 @@ App::post('/v1/project/variables')
'resourceType' => 'project',
'key' => $key,
'value' => $value,
'secret' => $secret,
'search' => implode(' ', [$variableId, $key, 'project']),
]);
+18 -2
View File
@@ -21,6 +21,7 @@ use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries\Identities;
use Appwrite\Utopia\Database\Validator\Queries\Memberships;
use Appwrite\Utopia\Database\Validator\Queries\Targets;
use Appwrite\Utopia\Database\Validator\Queries\Users;
use Appwrite\Utopia\Request;
@@ -799,9 +800,11 @@ App::get('/v1/users/:userId/memberships')
]
))
->param('userId', '', new UID(), 'User ID.')
->param('queries', [], new Memberships(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Memberships::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('response')
->inject('dbForProject')
->action(function (string $userId, Response $response, Database $dbForProject) {
->action(function (string $userId, array $queries, string $search, Response $response, Database $dbForProject) {
$user = $dbForProject->getDocument('users', $userId);
@@ -809,6 +812,19 @@ App::get('/v1/users/:userId/memberships')
throw new Exception(Exception::USER_NOT_FOUND);
}
try {
$queries = Query::parseQueries($queries);
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
if (!empty($search)) {
$queries[] = Query::search('search', $search);
}
// Set internal queries
$queries[] = Query::equal('userInternalId', [$user->getInternalId()]);
$memberships = array_map(function ($membership) use ($dbForProject, $user) {
$team = $dbForProject->getDocument('teams', $membership->getAttribute('teamId'));
@@ -818,7 +834,7 @@ App::get('/v1/users/:userId/memberships')
->setAttribute('userEmail', $user->getAttribute('email'));
return $membership;
}, $user->getAttribute('memberships', []));
}, $dbForProject->find('memberships', $queries));
$response->dynamic(new Document([
'memberships' => $memberships,
+1
View File
@@ -93,6 +93,7 @@ abstract class Migration
'1.6.0' => 'V21',
'1.6.1' => 'V21',
'1.6.2' => 'V22',
'1.7.0' => 'V23',
];
/**
+69
View File
@@ -0,0 +1,69 @@
<?php
namespace Appwrite\Migration\Version;
use Appwrite\Migration\Migration;
use Exception;
use Throwable;
use Utopia\CLI\Console;
use Utopia\Database\Database;
class V23 extends Migration
{
/**
* @throws Throwable
*/
public function execute(): void
{
/**
* Disable SubQueries for Performance.
*/
foreach (['subQueryIndexes', 'subQueryPlatforms', 'subQueryDomains', 'subQueryKeys', 'subQueryWebhooks', 'subQuerySessions', 'subQueryTokens', 'subQueryMemberships', 'subQueryVariables', 'subQueryChallenges', 'subQueryProjectVariables', 'subQueryTargets', 'subQueryTopicTargets'] as $name) {
Database::addFilter(
$name,
fn () => null,
fn () => []
);
}
Console::info('Migrating Collections');
$this->migrateCollections();
}
/**
* Migrate Collections.
*
* @return void
* @throws Exception|Throwable
*/
private function migrateCollections(): void
{
$internalProjectId = $this->project->getInternalId();
$collectionType = match ($internalProjectId) {
'console' => 'console',
default => 'projects',
};
$collections = $this->collections[$collectionType];
foreach ($collections as $collection) {
$id = $collection['$id'];
Console::log("Migrating Collection \"{$id}\"");
$this->projectDB->setNamespace("_$internalProjectId");
switch ($id) {
case 'memberships':
// Create roles index
try {
$this->createIndexFromCollection($this->projectDB, $id, '_key_roles');
} catch (Throwable $th) {
Console::warning("'_key_roles' from {$id}: {$th->getMessage()}");
}
break;
}
usleep(50000);
}
}
}
@@ -9,12 +9,12 @@ class Memberships extends Base
'teamId',
'invited',
'joined',
'confirm'
'confirm',
'roles',
];
/**
* Expression constructor
*
*/
public function __construct()
{
@@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
use Utopia\Database\Document;
class Variable extends Model
{
@@ -41,6 +42,12 @@ class Variable extends Model
'default' => '',
'example' => 'myPa$$word1',
])
->addRule('secret', [
'type' => self::TYPE_BOOLEAN,
'description' => 'Variable secret flag. Secret variables can only be updated or deleted, but never read.',
'default' => false,
'example' => false,
])
->addRule('resourceType', [
'type' => self::TYPE_STRING,
'description' => 'Service to which the variable belongs. Possible values are "project", "function"',
@@ -56,6 +63,21 @@ class Variable extends Model
;
}
/**
* Filter
*
* @param Document $document
* @return Document
*/
public function filter(Document $document): Document
{
$secret = $document->getAttribute('secret');
if ($secret === true) {
$document->setAttribute('value', null);
}
return $document;
}
/**
* Get Name
*
@@ -118,6 +118,22 @@ class FunctionsConsoleClientTest extends Scope
$variableId = $variable['body']['$id'];
// test for secret variable
$variable = $this->createVariable(
$data['functionId'],
[
'key' => 'APP_TEST_1',
'value' => 'TESTINGVALUE_1',
'secret' => true
]
);
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertEquals('APP_TEST_1', $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$secretVariableId = $variable['body']['$id'];
/**
* Test for FAILURE
*/
@@ -157,7 +173,8 @@ class FunctionsConsoleClientTest extends Scope
return array_merge(
$data,
[
'variableId' => $variableId
'variableId' => $variableId,
'secretVariableId' => $secretVariableId
]
);
}
@@ -177,10 +194,12 @@ class FunctionsConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, sizeof($response['body']['variables']));
$this->assertEquals(1, $response['body']['total']);
$this->assertEquals(2, sizeof($response['body']['variables']));
$this->assertEquals(2, $response['body']['total']);
$this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']);
$this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']);
$this->assertEquals("APP_TEST_1", $response['body']['variables'][1]['key']);
$this->assertEmpty($response['body']['variables'][1]['value']);
/**
* Test for FAILURE
@@ -207,6 +226,15 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST", $response['body']['key']);
$this->assertEquals("TESTINGVALUE", $response['body']['value']);
$response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_1", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
/**
* Test for FAILURE
*/
@@ -251,6 +279,27 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']);
$this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']);
$response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'key' => 'APP_TEST_UPDATE_1',
'value' => 'TESTINGVALUEUPDATED_1'
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_1", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
$variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_1", $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -332,6 +381,13 @@ class FunctionsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -3930,6 +3930,23 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(201, $variable['headers']['status-code']);
$variableId = $variable['body']['$id'];
// test for secret variable
$variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()), [
'key' => 'APP_TEST_1',
'value' => 'TESTINGVALUE_1',
'secret' => true
]);
$this->assertEquals(201, $variable['headers']['status-code']);
$this->assertEquals('APP_TEST_1', $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$secretVariableId = $variable['body']['$id'];
/**
* Test for FAILURE
*/
@@ -3973,6 +3990,7 @@ class ProjectsConsoleClientTest extends Scope
$data,
[
'variableId' => $variableId,
'secretVariableId' => $secretVariableId
]
);
}
@@ -3993,10 +4011,12 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertCount(1, $response['body']['variables']);
$this->assertEquals(1, $response['body']['total']);
$this->assertCount(2, $response['body']['variables']);
$this->assertEquals(2, $response['body']['total']);
$this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']);
$this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']);
$this->assertEquals("APP_TEST_1", $response['body']['variables'][1]['key']);
$this->assertEmpty($response['body']['variables'][1]['value']);
return $data;
}
@@ -4019,6 +4039,16 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST", $response['body']['key']);
$this->assertEquals("TESTINGVALUE", $response['body']['value']);
$response = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_1", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
/**
* Test for FAILURE
*/
@@ -4066,6 +4096,29 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']);
$this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']);
$response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()), [
'key' => 'APP_TEST_UPDATE_1',
'value' => 'TESTINGVALUEUPDATED_1'
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_1", $response['body']['key']);
$this->assertEmpty($response['body']['value']);
$variable = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()));
$this->assertEquals(200, $variable['headers']['status-code']);
$this->assertEquals("APP_TEST_UPDATE_1", $variable['body']['key']);
$this->assertEmpty($variable['body']['value']);
$response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
@@ -4073,8 +4126,9 @@ class ProjectsConsoleClientTest extends Scope
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertCount(1, $response['body']['variables']);
$this->assertCount(2, $response['body']['variables']);
$this->assertEquals("APP_TEST_UPDATE", $response['body']['variables'][0]['key']);
$this->assertEquals("APP_TEST_UPDATE_1", $response['body']['variables'][1]['key']);
/**
* Test for FAILURE
@@ -4153,6 +4207,14 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals(204, $response['headers']['status-code']);
$this->assertEquals(204, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_DELETE, '/project/variables/' . $data['secretVariableId'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
'x-appwrite-mode' => 'admin',
], $this->getHeaders()));
$response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $data['projectId'],
+91
View File
@@ -801,6 +801,97 @@ trait UsersBase
return $data;
}
/**
* @depends testGetUser
*/
public function testListUserMemberships(array $data): array
{
/**
* Test for SUCCESS
*/
// create a new team
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => 'unique()',
'name' => 'Test Team',
]);
// create a new membership
$membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team['body']['$id'] . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'userId' => $data['userId'],
'roles' => ['new-role'],
]);
// list the memberships
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['memberships'][0]['$id'], $membership['body']['$id']);
$this->assertEquals($response['body']['memberships'][0]['roles'], ['new-role']);
$this->assertEquals($response['body']['total'], 1);
// create another membership with a new role
$team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'teamId' => 'unique()',
'name' => 'Test Team 2',
]);
$membership = $this->client->call(Client::METHOD_POST, '/teams/' . $team['body']['$id'] . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'userId' => $data['userId'],
'roles' => ['new-role-2'],
]);
// list out memberships and query by role
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'queries' => [
Query::contains('roles', ['new-role-2'])->toString()
]
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['memberships'][0]['$id'], $membership['body']['$id']);
$this->assertEquals($response['body']['memberships'][0]['roles'], ['new-role-2']);
$this->assertEquals($response['body']['total'], 1);
/**
* Test for FAILURE
*/
// query using equal on array field
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'queries' => [
Query::equal('roles', ['new-role-2'])->toString()
]
]);
$this->assertEquals($response['body']['code'], 400);
$this->assertEquals($response['body']['message'], 'Invalid `queries` param: Invalid query: Cannot query equal on attribute "roles" because it is an array.');
$this->assertEquals($response['body']['type'], 'general_argument_invalid');
return $data;
}
/**
* @depends testGetUser
*/