mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.4.x' of https://github.com/appwrite/appwrite into disallow-personal-data
This commit is contained in:
@@ -51,6 +51,7 @@ class Exception extends \Exception
|
||||
public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found';
|
||||
public const GENERAL_SERVER_ERROR = 'general_server_error';
|
||||
public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported';
|
||||
public const GENERAL_USAGE_DISABLED = 'general_usage_disabled';
|
||||
|
||||
/** Users */
|
||||
public const USER_COUNT_EXCEEDED = 'user_count_exceeded';
|
||||
@@ -154,12 +155,14 @@ class Exception extends \Exception
|
||||
public const INDEX_NOT_FOUND = 'index_not_found';
|
||||
public const INDEX_LIMIT_EXCEEDED = 'index_limit_exceeded';
|
||||
public const INDEX_ALREADY_EXISTS = 'index_already_exists';
|
||||
public const INDEX_INVALID = 'index_invalid';
|
||||
|
||||
/** Projects */
|
||||
public const PROJECT_NOT_FOUND = 'project_not_found';
|
||||
public const PROJECT_UNKNOWN = 'project_unknown';
|
||||
public const PROJECT_PROVIDER_DISABLED = 'project_provider_disabled';
|
||||
public const PROJECT_PROVIDER_UNSUPPORTED = 'project_provider_unsupported';
|
||||
public const PROJECT_ALREADY_EXISTS = 'project_already_exists';
|
||||
public const PROJECT_INVALID_SUCCESS_URL = 'project_invalid_success_url';
|
||||
public const PROJECT_INVALID_FAILURE_URL = 'project_invalid_failure_url';
|
||||
public const PROJECT_RESERVED_PROJECT = 'project_reserved_project';
|
||||
|
||||
@@ -254,14 +254,14 @@ class Mapper
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Collections':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Databases':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Deployments':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Executions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Files':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Functions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Memberships':
|
||||
case 'Utopia\Database\Validator\Permissions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Projects':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Roles':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Teams':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Users':
|
||||
|
||||
@@ -37,6 +37,9 @@ abstract class Migration
|
||||
*/
|
||||
protected Database $consoleDB;
|
||||
|
||||
/**
|
||||
* @var \PDO
|
||||
*/
|
||||
protected \PDO $pdo;
|
||||
|
||||
/**
|
||||
@@ -54,6 +57,12 @@ abstract class Migration
|
||||
'1.2.1' => 'V17',
|
||||
'1.3.0' => 'V18',
|
||||
'1.3.1' => 'V18',
|
||||
'1.3.2' => 'V18',
|
||||
'1.3.3' => 'V18',
|
||||
'1.3.4' => 'V18',
|
||||
'1.3.5' => 'V18',
|
||||
'1.3.6' => 'V18',
|
||||
'1.3.7' => 'V18',
|
||||
'1.4.0' => 'V19',
|
||||
];
|
||||
|
||||
@@ -103,6 +112,12 @@ abstract class Migration
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PDO for Migration.
|
||||
*
|
||||
* @param \PDO $pdo
|
||||
* @return \Appwrite\Migration\Migration
|
||||
*/
|
||||
public function setPDO(\PDO $pdo): self
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
|
||||
@@ -6,6 +6,8 @@ use Appwrite\Migration\Migration;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
class V18 extends Migration
|
||||
{
|
||||
@@ -25,6 +27,7 @@ class V18 extends Migration
|
||||
|
||||
Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
|
||||
$this->projectDB->setNamespace("_{$this->project->getInternalId()}");
|
||||
$this->addDocumentSecurityToProject();
|
||||
|
||||
Console::info('Migrating Databases');
|
||||
$this->migrateDatabases();
|
||||
@@ -58,6 +61,15 @@ class V18 extends Migration
|
||||
}
|
||||
$this->changeAttributeInternalType($collectionTable, $attribute['key'], 'DOUBLE');
|
||||
}
|
||||
|
||||
try {
|
||||
$documentSecurity = $collection->getAttribute('documentSecurity', false);
|
||||
$permissions = $collection->getPermissions();
|
||||
|
||||
$this->projectDB->updateCollection($collectionTable, $permissions, $documentSecurity);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +93,12 @@ class V18 extends Migration
|
||||
$this->changeAttributeInternalType($id, $attribute['$id'], 'DOUBLE');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->projectDB->updateCollection($id, [Permission::create(Role::any())], true);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
|
||||
switch ($id) {
|
||||
case 'users':
|
||||
try {
|
||||
@@ -141,31 +159,65 @@ class V18 extends Migration
|
||||
/**
|
||||
* Set default passwordHistory
|
||||
*/
|
||||
$document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [
|
||||
$document->setAttribute('auths', array_merge([
|
||||
'passwordHistory' => 0,
|
||||
'passwordDictionary' => false,
|
||||
]));
|
||||
], $document->getAttribute('auths', [])));
|
||||
break;
|
||||
case 'users':
|
||||
/**
|
||||
* Default Password history
|
||||
*/
|
||||
$document->setAttribute('passwordHistory', []);
|
||||
$document->setAttribute('passwordHistory', $document->getAttribute('passwordHistory', []));
|
||||
break;
|
||||
case 'teams':
|
||||
/**
|
||||
* Default prefs
|
||||
*/
|
||||
$document->setAttribute('prefs', new \stdClass());
|
||||
$document->setAttribute('prefs', $document->getAttribute('prefs', new \stdClass()));
|
||||
break;
|
||||
case 'attributes':
|
||||
/**
|
||||
* Default options
|
||||
*/
|
||||
$document->setAttribute('options', new \stdClass());
|
||||
$document->setAttribute('options', $document->getAttribute('options', new \stdClass()));
|
||||
break;
|
||||
case 'buckets':
|
||||
/**
|
||||
* Set the bucket permission in the metadata table
|
||||
*/
|
||||
try {
|
||||
$internalBucketId = "bucket_{$this->project->getInternalId()}";
|
||||
$permissions = $document->getPermissions();
|
||||
$fileSecurity = $document->getAttribute('fileSecurity', false);
|
||||
$this->projectDB->updateCollection($internalBucketId, $permissions, $fileSecurity);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
protected function addDocumentSecurityToProject(): void
|
||||
{
|
||||
try {
|
||||
/**
|
||||
* Create 'documentSecurity' column
|
||||
*/
|
||||
$this->pdo->prepare("ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` ADD COLUMN IF NOT EXISTS documentSecurity TINYINT(1);")->execute();
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
/**
|
||||
* Set 'documentSecurity' column to 1 if NULL
|
||||
*/
|
||||
$this->pdo->prepare("UPDATE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` SET documentSecurity = 1 WHERE documentSecurity IS NULL")->execute();
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,64 @@ class V19 extends Migration
|
||||
Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')');
|
||||
$this->projectDB->setNamespace("_{$this->project->getInternalId()}");
|
||||
|
||||
$this->alterPermissionIndex('_metadata');
|
||||
|
||||
Console::info('Migrating Databases');
|
||||
$this->migrateDatabases();
|
||||
|
||||
Console::info('Migrating Collections');
|
||||
$this->migrateCollections();
|
||||
|
||||
Console::info('Migrating Buckets');
|
||||
$this->migrateBuckets();
|
||||
|
||||
Console::info('Migrating Documents');
|
||||
$this->forEachDocument([$this, 'fixDocument']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all Databases.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function migrateDatabases(): void
|
||||
{
|
||||
foreach ($this->documentsIterator('databases') as $database) {
|
||||
Console::log("Migrating Collections of {$database->getId()} ({$database->getAttribute('name')})");
|
||||
|
||||
$databaseTable = "database_{$database->getInternalId()}";
|
||||
|
||||
$this->alterPermissionIndex($databaseTable);
|
||||
|
||||
foreach ($this->documentsIterator($databaseTable) as $collection) {
|
||||
$collectionTable = "{$databaseTable}_collection_{$collection->getInternalId()}";
|
||||
Console::log("Migrating Collections of {$collectionTable} {$collection->getId()} ({$collection->getAttribute('name')})");
|
||||
$this->alterPermissionIndex($collectionTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all Collections.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function migrateCollections(): void
|
||||
{
|
||||
foreach ($this->collections as $collection) {
|
||||
$id = $collection['$id'];
|
||||
|
||||
Console::log("Migrating Collection \"{$id}\"");
|
||||
|
||||
if (!in_array($id, ['files', 'collections'])) {
|
||||
$this->alterPermissionIndex($id);
|
||||
}
|
||||
|
||||
usleep(50000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix run on each document
|
||||
*
|
||||
@@ -44,16 +98,39 @@ class V19 extends Migration
|
||||
* Bump version number.
|
||||
*/
|
||||
$document->setAttribute('version', '1.4.0');
|
||||
|
||||
/**
|
||||
* Set default disallowPersonalData to false.
|
||||
*/
|
||||
$document->setAttribute('auths', array_merge($document->getAttribute('auths', []), [
|
||||
'disallowPersonalData' => false
|
||||
]));
|
||||
break;
|
||||
}
|
||||
|
||||
return $document;
|
||||
}
|
||||
|
||||
protected function alterPermissionIndex($collectionName): void
|
||||
{
|
||||
try {
|
||||
$table = "`{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collectionName}_perms";
|
||||
$this->pdo->prepare("
|
||||
ALTER TABLE {$table}
|
||||
DROP INDEX `_permission`,
|
||||
ADD INDEX `_permission` (`_permission`, `_type`, `_document`);
|
||||
")->execute();
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrating all Bucket tables.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
* @throws \PDOException
|
||||
*/
|
||||
protected function migrateBuckets(): void
|
||||
{
|
||||
foreach ($this->documentsIterator('buckets') as $bucket) {
|
||||
$id = "bucket_{$bucket->getInternalId()}";
|
||||
Console::log("Migrating Bucket {$id} {$bucket->getId()} ({$bucket->getAttribute('name')})");
|
||||
$this->alterPermissionIndex($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ class OpenAPI3 extends Format
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Collections':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Databases':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Deployments':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Executions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Files':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Functions':
|
||||
@@ -354,7 +354,7 @@ class OpenAPI3 extends Format
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Teams':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Users':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Variables':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Queries':
|
||||
$node['schema']['type'] = 'array';
|
||||
$node['schema']['items'] = [
|
||||
'type' => 'string',
|
||||
|
||||
@@ -344,7 +344,7 @@ class Swagger2 extends Format
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Collections':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Databases':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Deployments':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Utopia\Database\Validator\Queries\Documents':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Executions':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Files':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Functions':
|
||||
@@ -353,7 +353,7 @@ class Swagger2 extends Format
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Teams':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Users':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries\Variables':
|
||||
case 'Appwrite\Utopia\Database\Validator\Queries':
|
||||
case 'Utopia\Database\Validator\Queries':
|
||||
$node['type'] = 'array';
|
||||
$node['collectionFormat'] = 'multi';
|
||||
$node['items'] = [
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class IndexedQueries extends Queries
|
||||
{
|
||||
/**
|
||||
* @var array<Document>
|
||||
*/
|
||||
protected array $attributes = [];
|
||||
|
||||
/**
|
||||
* @var array<Document>
|
||||
*/
|
||||
protected array $indexes = [];
|
||||
|
||||
/**
|
||||
* Expression constructor
|
||||
*
|
||||
* This Queries Validator filters indexes for only available indexes
|
||||
*
|
||||
* @param array<Document> $attributes
|
||||
* @param array<Document> $indexes
|
||||
* @param Base ...$validators
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(array $attributes = [], array $indexes = [], Base ...$validators)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
|
||||
$this->indexes[] = new Document([
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['$id']
|
||||
]);
|
||||
|
||||
$this->indexes[] = new Document([
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['$createdAt']
|
||||
]);
|
||||
|
||||
$this->indexes[] = new Document([
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['$updatedAt']
|
||||
]);
|
||||
|
||||
foreach ($indexes ?? [] as $index) {
|
||||
$this->indexes[] = $index;
|
||||
}
|
||||
|
||||
parent::__construct(...$validators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns false if:
|
||||
* 1. any query in $value is invalid based on $validator
|
||||
* 2. there is no index with an exact match of the filters
|
||||
* 3. there is no index with an exact match of the order attributes
|
||||
*
|
||||
* Otherwise, returns true.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
if (!parent::isValid($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$queries = [];
|
||||
foreach ($value as $query) {
|
||||
if (!$query instanceof Query) {
|
||||
$query = Query::parse($query);
|
||||
}
|
||||
|
||||
$queries[] = $query;
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$filters = $grouped['filters'];
|
||||
|
||||
foreach ($filters as $filter) {
|
||||
if ($filter->getMethod() === Query::TYPE_SEARCH) {
|
||||
$matched = false;
|
||||
|
||||
foreach ($this->indexes as $index) {
|
||||
if (
|
||||
$index->getAttribute('type') === Database::INDEX_FULLTEXT
|
||||
&& $index->getAttribute('attributes') === [$filter->getAttribute()]
|
||||
) {
|
||||
$matched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matched) {
|
||||
$this->message = "Searching by attribute \"{$filter->getAttribute()}\" requires a fulltext index.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\OrderAttributes as ValidatorOrderAttributes;
|
||||
|
||||
class OrderAttributes extends ValidatorOrderAttributes
|
||||
{
|
||||
/**
|
||||
* Expression constructor
|
||||
*
|
||||
* @param Document[] $attributes
|
||||
* @param Document[] $indexes
|
||||
* @param bool $strict
|
||||
*/
|
||||
public function __construct($attributes, $indexes, $strict)
|
||||
{
|
||||
// Remove failed/stuck/processing indexes
|
||||
$indexes = \array_filter($indexes, function ($index) {
|
||||
return $index->getAttribute('status') === 'available';
|
||||
});
|
||||
|
||||
parent::__construct($attributes, $indexes, $strict);
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Queries extends Validator
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $message = 'Invalid queries';
|
||||
|
||||
/**
|
||||
* @var array<Base>
|
||||
*/
|
||||
protected array $validators;
|
||||
|
||||
/**
|
||||
* Queries constructor
|
||||
*
|
||||
* @param Base ...$validators a list of validators
|
||||
*/
|
||||
public function __construct(Base ...$validators)
|
||||
{
|
||||
$this->validators = $validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Description.
|
||||
*
|
||||
* Returns validator description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns false if:
|
||||
* 1. any query in $value is invalid based on $validator
|
||||
*
|
||||
* Otherwise, returns true.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($value): bool
|
||||
{
|
||||
foreach ($value as $query) {
|
||||
if (!$query instanceof Query) {
|
||||
try {
|
||||
$query = Query::parse($query);
|
||||
} catch (\Throwable) {
|
||||
$this->message = "Invalid query: {$query}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$method = $query->getMethod();
|
||||
$methodType = match ($method) {
|
||||
Query::TYPE_SELECT => Base::METHOD_TYPE_SELECT,
|
||||
Query::TYPE_LIMIT => Base::METHOD_TYPE_LIMIT,
|
||||
Query::TYPE_OFFSET => Base::METHOD_TYPE_OFFSET,
|
||||
Query::TYPE_CURSORAFTER,
|
||||
Query::TYPE_CURSORBEFORE => Base::METHOD_TYPE_CURSOR,
|
||||
Query::TYPE_ORDERASC,
|
||||
Query::TYPE_ORDERDESC => Base::METHOD_TYPE_ORDER,
|
||||
Query::TYPE_EQUAL,
|
||||
Query::TYPE_NOTEQUAL,
|
||||
Query::TYPE_LESSER,
|
||||
Query::TYPE_LESSEREQUAL,
|
||||
Query::TYPE_GREATER,
|
||||
Query::TYPE_GREATEREQUAL,
|
||||
Query::TYPE_SEARCH,
|
||||
Query::TYPE_IS_NULL,
|
||||
Query::TYPE_IS_NOT_NULL,
|
||||
Query::TYPE_BETWEEN,
|
||||
Query::TYPE_STARTS_WITH,
|
||||
Query::TYPE_ENDS_WITH => Base::METHOD_TYPE_FILTER,
|
||||
default => '',
|
||||
};
|
||||
|
||||
$methodIsValid = false;
|
||||
foreach ($this->validators as $validator) {
|
||||
if ($validator->getMethodType() !== $methodType) {
|
||||
continue;
|
||||
}
|
||||
if (!$validator->isValid($query)) {
|
||||
$this->message = 'Query not valid: ' . $validator->getDescription();
|
||||
return false;
|
||||
}
|
||||
|
||||
$methodIsValid = true;
|
||||
}
|
||||
|
||||
if (!$methodIsValid) {
|
||||
$this->message = 'Query method not valid: ' . $method;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is array
|
||||
*
|
||||
* Function will return true if object is array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isArray(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Returns validator type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_OBJECT;
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Queries;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Limit;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Cursor;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Filter;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Order;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Select;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Filter;
|
||||
use Utopia\Database\Validator\Query\Order;
|
||||
use Utopia\Database\Validator\Query\Select;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
@@ -70,6 +70,6 @@ class Base extends Queries
|
||||
new Select($attributes),
|
||||
];
|
||||
|
||||
parent::__construct(...$validators);
|
||||
parent::__construct($validators);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Queries;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Select;
|
||||
use Utopia\Database\Database;
|
||||
|
||||
class Document extends Queries
|
||||
{
|
||||
/**
|
||||
* Expression constructor
|
||||
*
|
||||
* @param array $attributes
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
$attributes[] = new \Utopia\Database\Document([
|
||||
'key' => '$id',
|
||||
'type' => Database::VAR_STRING,
|
||||
'array' => false,
|
||||
]);
|
||||
$attributes[] = new \Utopia\Database\Document([
|
||||
'key' => '$createdAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'array' => false,
|
||||
]);
|
||||
$attributes[] = new \Utopia\Database\Document([
|
||||
'key' => '$updatedAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'array' => false,
|
||||
]);
|
||||
|
||||
$validators = [
|
||||
new Select($attributes),
|
||||
];
|
||||
|
||||
parent::__construct(...$validators);
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\IndexedQueries;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Cursor;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Filter;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Limit;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Offset;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Order;
|
||||
use Appwrite\Utopia\Database\Validator\Query\Select;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Documents extends IndexedQueries
|
||||
{
|
||||
/**
|
||||
* Expression constructor
|
||||
*
|
||||
* @param Document[] $attributes
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(array $attributes, array $indexes)
|
||||
{
|
||||
$attributes[] = new Document([
|
||||
'key' => '$id',
|
||||
'type' => Database::VAR_STRING,
|
||||
'array' => false,
|
||||
]);
|
||||
$attributes[] = new Document([
|
||||
'key' => '$createdAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'array' => false,
|
||||
]);
|
||||
$attributes[] = new Document([
|
||||
'key' => '$updatedAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'array' => false,
|
||||
]);
|
||||
|
||||
$validators = [
|
||||
new Limit(),
|
||||
new Offset(),
|
||||
new Cursor(),
|
||||
new Filter($attributes),
|
||||
new Order($attributes),
|
||||
new Select($attributes),
|
||||
];
|
||||
|
||||
parent::__construct($attributes, $indexes, ...$validators);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Utopia\Validator;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
abstract class Base extends Validator
|
||||
{
|
||||
public const METHOD_TYPE_LIMIT = 'limit';
|
||||
public const METHOD_TYPE_OFFSET = 'offset';
|
||||
public const METHOD_TYPE_CURSOR = 'cursor';
|
||||
public const METHOD_TYPE_ORDER = 'order';
|
||||
public const METHOD_TYPE_FILTER = 'filter';
|
||||
public const METHOD_TYPE_SELECT = 'select';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message = 'Invalid query';
|
||||
|
||||
/**
|
||||
* Get Description.
|
||||
*
|
||||
* Returns validator description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is array
|
||||
*
|
||||
* Function will return true if object is array.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isArray(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* Returns validator type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return self::TYPE_OBJECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns what type of query this Validator is for
|
||||
*/
|
||||
abstract public function getMethodType(): string;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\UID;
|
||||
|
||||
class Cursor extends Base
|
||||
{
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is cursorBefore or cursorAfter and value is not null
|
||||
*
|
||||
* Otherwise, returns false
|
||||
*
|
||||
* @param Query $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
// Validate method
|
||||
$method = $query->getMethod();
|
||||
|
||||
if ($method === Query::TYPE_CURSORAFTER || $method === Query::TYPE_CURSORBEFORE) {
|
||||
$cursor = $query->getValue();
|
||||
$validator = new UID();
|
||||
if ($validator->isValid($cursor)) {
|
||||
return true;
|
||||
}
|
||||
$this->message = 'Invalid cursor: ' . $validator->getDescription();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_CURSOR;
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Filter extends Base
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $message = 'Invalid query';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $schema = [];
|
||||
|
||||
private int $maxValuesCount;
|
||||
|
||||
/**
|
||||
* Query constructor
|
||||
*
|
||||
* @param int $maxValuesCount
|
||||
*/
|
||||
public function __construct(array $attributes = [], int $maxValuesCount = 100)
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->schema[$attribute->getAttribute('key')] = $attribute->getArrayCopy();
|
||||
}
|
||||
|
||||
$this->maxValuesCount = $maxValuesCount;
|
||||
}
|
||||
|
||||
protected function isValidAttribute($attribute): bool
|
||||
{
|
||||
if (\str_contains($attribute, '.')) {
|
||||
// For relationships, just validate the top level.
|
||||
// Utopia will validate each nested level during the recursive calls.
|
||||
$attribute = \explode('.', $attribute)[0];
|
||||
|
||||
// TODO: Remove this when nested queries are supported
|
||||
if (isset($this->schema[$attribute])) {
|
||||
$this->message = 'Cannot query nested attribute on: ' . $attribute;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Search for attribute in schema
|
||||
if (!isset($this->schema[$attribute])) {
|
||||
$this->message = 'Attribute not found in schema: ' . $attribute;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isValidAttributeAndValues(string $attribute, array $values): bool
|
||||
{
|
||||
if (!$this->isValidAttribute($attribute)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (\str_contains($attribute, '.')) {
|
||||
// For relationships, just validate the top level.
|
||||
// Utopia will validate each nested level during the recursive calls.
|
||||
$attribute = \explode('.', $attribute)[0];
|
||||
}
|
||||
|
||||
$attributeSchema = $this->schema[$attribute];
|
||||
|
||||
if (count($values) > $this->maxValuesCount) {
|
||||
$this->message = 'Query on attribute has greater than ' . $this->maxValuesCount . ' values: ' . $attribute;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the type of desired attribute from collection $schema
|
||||
$attributeType = $attributeSchema['type'];
|
||||
|
||||
foreach ($values as $value) {
|
||||
$condition = match ($attributeType) {
|
||||
Database::VAR_RELATIONSHIP => true,
|
||||
Database::VAR_DATETIME => gettype($value) === Database::VAR_STRING,
|
||||
Database::VAR_FLOAT => (gettype($value) === Database::VAR_FLOAT || gettype($value) === Database::VAR_INTEGER),
|
||||
default => gettype($value) === $attributeType
|
||||
};
|
||||
|
||||
if (!$condition) {
|
||||
$this->message = 'Query type does not match expected: ' . $attributeType;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is a filter method, attribute exists, and value matches attribute type
|
||||
*
|
||||
* Otherwise, returns false
|
||||
*
|
||||
* @param Query $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
// Validate method
|
||||
$method = $query->getMethod();
|
||||
$attribute = $query->getAttribute();
|
||||
|
||||
switch ($method) {
|
||||
case Query::TYPE_EQUAL:
|
||||
case Query::TYPE_NOTEQUAL:
|
||||
case Query::TYPE_LESSER:
|
||||
case Query::TYPE_LESSEREQUAL:
|
||||
case Query::TYPE_GREATER:
|
||||
case Query::TYPE_GREATEREQUAL:
|
||||
case Query::TYPE_SEARCH:
|
||||
case Query::TYPE_STARTS_WITH:
|
||||
case Query::TYPE_ENDS_WITH:
|
||||
case Query::TYPE_BETWEEN:
|
||||
case Query::TYPE_IS_NULL:
|
||||
case Query::TYPE_IS_NOT_NULL:
|
||||
$values = $query->getValues();
|
||||
return $this->isValidAttributeAndValues($attribute, $values);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_FILTER;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Validator\Range;
|
||||
|
||||
class Limit extends Base
|
||||
{
|
||||
protected int $maxLimit;
|
||||
|
||||
/**
|
||||
* Query constructor
|
||||
*
|
||||
* @param int $maxLimit
|
||||
*/
|
||||
public function __construct(int $maxLimit = PHP_INT_MAX)
|
||||
{
|
||||
$this->maxLimit = $maxLimit;
|
||||
}
|
||||
|
||||
protected function isValidLimit($limit): bool
|
||||
{
|
||||
$validator = new Range(0, $this->maxLimit);
|
||||
if ($validator->isValid($limit)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->message = 'Invalid limit: ' . $validator->getDescription();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is limit values are within range.
|
||||
*
|
||||
* @param Query $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
// Validate method
|
||||
$method = $query->getMethod();
|
||||
|
||||
if ($method !== Query::TYPE_LIMIT) {
|
||||
$this->message = 'Query method invalid: ' . $method;
|
||||
return false;
|
||||
}
|
||||
|
||||
$limit = $query->getValue();
|
||||
return $this->isValidLimit($limit);
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_LIMIT;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Validator\Range;
|
||||
|
||||
class Offset extends Base
|
||||
{
|
||||
protected int $maxOffset;
|
||||
|
||||
/**
|
||||
* Query constructor
|
||||
*
|
||||
* @param int $maxOffset
|
||||
*/
|
||||
public function __construct(int $maxOffset = PHP_INT_MAX)
|
||||
{
|
||||
$this->maxOffset = $maxOffset;
|
||||
}
|
||||
|
||||
protected function isValidOffset($offset): bool
|
||||
{
|
||||
$validator = new Range(0, $this->maxOffset);
|
||||
if ($validator->isValid($offset)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->message = 'Invalid offset: ' . $validator->getDescription();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is offset and values are within range.
|
||||
*
|
||||
* @param Query $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
// Validate method
|
||||
$method = $query->getMethod();
|
||||
|
||||
if ($method !== Query::TYPE_OFFSET) {
|
||||
$this->message = 'Query method invalid: ' . $method;
|
||||
return false;
|
||||
}
|
||||
|
||||
$offset = $query->getValue();
|
||||
return $this->isValidOffset($offset);
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_OFFSET;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Validator;
|
||||
|
||||
class Order extends Base
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $schema = [];
|
||||
|
||||
/**
|
||||
* Query constructor
|
||||
*
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->schema[$attribute->getAttribute('key')] = $attribute->getArrayCopy();
|
||||
}
|
||||
}
|
||||
|
||||
protected function isValidAttribute($attribute): bool
|
||||
{
|
||||
// Search for attribute in schema
|
||||
if (!isset($this->schema[$attribute])) {
|
||||
$this->message = 'Attribute not found in schema: ' . $attribute;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is ORDER_ASC or ORDER_DESC and attributes are valid
|
||||
*
|
||||
* Otherwise, returns false
|
||||
*
|
||||
* @param Query $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
$method = $query->getMethod();
|
||||
$attribute = $query->getAttribute();
|
||||
|
||||
if ($method === Query::TYPE_ORDERASC || $method === Query::TYPE_ORDERDESC) {
|
||||
if ($attribute === '') {
|
||||
return true;
|
||||
}
|
||||
return $this->isValidAttribute($attribute);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_ORDER;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
|
||||
class Select extends Base
|
||||
{
|
||||
protected array $schema = [];
|
||||
|
||||
/**
|
||||
* Query constructor
|
||||
*
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->schema[$attribute->getAttribute('key')] = $attribute->getArrayCopy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is valid.
|
||||
*
|
||||
* Returns true if method is TYPE_SELECT selections are valid
|
||||
*
|
||||
* Otherwise, returns false
|
||||
*
|
||||
* @param $query
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($query): bool
|
||||
{
|
||||
/* @var $query Query */
|
||||
|
||||
if ($query->getMethod() !== Query::TYPE_SELECT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($query->getValues() as $attribute) {
|
||||
if (\str_contains($attribute, '.')) {
|
||||
// For relationships, just validate the top level.
|
||||
// Utopia will validate each nested level during the recursive calls.
|
||||
$attribute = \explode('.', $attribute)[0];
|
||||
}
|
||||
if (!isset($this->schema[$attribute]) && $attribute !== '*') {
|
||||
$this->message = 'Attribute not found in schema: ' . $attribute;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_SELECT;
|
||||
}
|
||||
}
|
||||
@@ -200,11 +200,11 @@ class V15 extends Filter
|
||||
|
||||
$operations = [
|
||||
'equal' => Query::TYPE_EQUAL,
|
||||
'notEqual' => Query::TYPE_NOTEQUAL,
|
||||
'notEqual' => Query::TYPE_NOT_EQUAL,
|
||||
'lesser' => Query::TYPE_LESSER,
|
||||
'lesserEqual' => Query::TYPE_LESSEREQUAL,
|
||||
'lesserEqual' => Query::TYPE_LESSER_EQUAL,
|
||||
'greater' => Query::TYPE_GREATER,
|
||||
'greaterEqual' => Query::TYPE_GREATEREQUAL,
|
||||
'greaterEqual' => Query::TYPE_GREATER_EQUAL,
|
||||
'search' => Query::TYPE_SEARCH,
|
||||
];
|
||||
foreach ($content['queries'] as $i => $query) {
|
||||
|
||||
@@ -28,6 +28,12 @@ class Attribute extends Model
|
||||
'default' => '',
|
||||
'example' => 'available',
|
||||
])
|
||||
->addRule('error', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Error message. Displays error generated on failure of creating or deleting an attribute.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('required', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Is attribute required?',
|
||||
|
||||
@@ -18,10 +18,10 @@ class AttributeDatetime extends Attribute
|
||||
'example' => 'birthDay',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
'example' => self::TYPE_DATETIME,
|
||||
])
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_DATETIME,
|
||||
|
||||
@@ -34,6 +34,12 @@ class Database extends Model
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('enabled', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Database enabled.',
|
||||
'default' => true,
|
||||
'example' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ class Index extends Model
|
||||
'default' => '',
|
||||
'example' => 'available',
|
||||
])
|
||||
->addRule('error', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Error message. Displays error generated on failure of creating or deleting an index.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('attributes', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Index attributes.',
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Team extends Model
|
||||
{
|
||||
@@ -49,6 +50,24 @@ class Team extends Model
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Document before returning it to the client
|
||||
*
|
||||
* @return Document
|
||||
*/
|
||||
public function filter(Document $document): Document
|
||||
{
|
||||
$prefs = $document->getAttribute('prefs');
|
||||
if ($prefs instanceof Document) {
|
||||
$prefs = $prefs->getArrayCopy();
|
||||
}
|
||||
|
||||
if (is_array($prefs) && empty($prefs)) {
|
||||
$document->setAttribute('prefs', new \stdClass());
|
||||
}
|
||||
return $document;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user