1
0
Fork 0
mirror of synced 2024-06-29 19:50:26 +12:00

Merge pull request #1487 from appwrite/feat-db-search-attribute

feat-db-search-attribute
This commit is contained in:
Torsten Dittmann 2021-10-06 13:45:44 +00:00 committed by GitHub
commit 5a20340900
13 changed files with 484 additions and 99 deletions

View file

@ -546,13 +546,24 @@ $collections = [
'array' => false, 'array' => false,
'filters' => ['subQueryDomains'], 'filters' => ['subQueryDomains'],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
'$id' => '_fulltext_name', '$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT, 'type' => Database::INDEX_FULLTEXT,
'attributes' => ['name'], 'attributes' => ['search'],
'lengths' => [1024], 'lengths' => [2048],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
], ],
@ -1049,6 +1060,17 @@ $collections = [
'array' => true, 'array' => true,
'filters' => ['json'], 'filters' => ['json'],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[ [
'$id' => 'deleted', '$id' => 'deleted',
'type' => Database::VAR_BOOLEAN, 'type' => Database::VAR_BOOLEAN,
@ -1069,6 +1091,13 @@ $collections = [
'lengths' => [320], 'lengths' => [320],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
[
'$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [2048],
'orders' => [Database::ORDER_ASC],
],
[ [
'$id' => '_key_deleted_email', '$id' => '_key_deleted_email',
'type' => Database::INDEX_KEY, 'type' => Database::INDEX_KEY,
@ -1365,13 +1394,24 @@ $collections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
'$id' => '_fulltext_name', '$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT, 'type' => Database::INDEX_FULLTEXT,
'attributes' => ['name'], 'attributes' => ['search'],
'lengths' => [1024], 'lengths' => [2048],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
], ],
@ -1645,6 +1685,17 @@ $collections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
@ -1655,10 +1706,10 @@ $collections = [
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
[ [
'$id' => '_fulltext_name', '$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT, 'type' => Database::INDEX_FULLTEXT,
'attributes' => ['name'], 'attributes' => ['search'],
'lengths' => [1024], 'lengths' => [2048],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
], ],
@ -1813,13 +1864,24 @@ $collections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
'$id' => '_fulltext_name', '$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT, 'type' => Database::INDEX_FULLTEXT,
'attributes' => ['name'], 'attributes' => ['search'],
'lengths' => [1024], 'lengths' => [2048],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
], ],
@ -1886,6 +1948,17 @@ $collections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
@ -1895,6 +1968,13 @@ $collections = [
'lengths' => [Database::LENGTH_KEY], 'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
[
'$id' => '_key_search',
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [2048],
'orders' => [Database::ORDER_ASC],
],
], ],
], ],
@ -2003,6 +2083,17 @@ $collections = [
'array' => false, 'array' => false,
'filters' => [], 'filters' => [],
], ],
[
'$id' => 'search',
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
], ],
'indexes' => [ 'indexes' => [
[ [
@ -2012,6 +2103,13 @@ $collections = [
'lengths' => [Database::LENGTH_KEY], 'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC], 'orders' => [Database::ORDER_ASC],
], ],
[
'$id' => '_fulltext_search',
'type' => Database::INDEX_FULLTEXT,
'attributes' => ['search'],
'lengths' => [16384],
'orders' => [Database::ORDER_ASC],
],
], ],
], ],

View file

@ -107,6 +107,7 @@ App::post('/v1/account')
'sessions' => [], 'sessions' => [],
'tokens' => [], 'tokens' => [],
'memberships' => [], 'memberships' => [],
'search' => implode(' ', [$userId, $email, $name]),
'deleted' => false 'deleted' => false
])); ]));
} catch (Duplicate $th) { } catch (Duplicate $th) {
@ -498,6 +499,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
'sessions' => [], 'sessions' => [],
'tokens' => [], 'tokens' => [],
'memberships' => [], 'memberships' => [],
'search' => implode(' ', [$userId, $email, $name]),
'deleted' => false 'deleted' => false
])); ]));
} catch (Duplicate $th) { } catch (Duplicate $th) {
@ -671,6 +673,7 @@ App::post('/v1/account/sessions/anonymous')
'sessions' => [], 'sessions' => [],
'tokens' => [], 'tokens' => [],
'memberships' => [], 'memberships' => [],
'search' => $userId,
'deleted' => false 'deleted' => false
])); ]));
@ -1039,7 +1042,10 @@ App::patch('/v1/account/name')
/** @var Appwrite\Event\Event $audits */ /** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Stats\Stats $usage */ /** @var Appwrite\Stats\Stats $usage */
$user = $dbForInternal->updateDocument('users', $user->getId(), $user->setAttribute('name', $name)); $user = $dbForInternal->updateDocument('users', $user->getId(), $user
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$user->getId(), $name, $user->getAttribute('email')]))
);
$audits $audits
->setParam('userId', $user->getId()) ->setParam('userId', $user->getId())
@ -1138,11 +1144,18 @@ App::patch('/v1/account/email')
} }
$email = \strtolower($email); $email = \strtolower($email);
$profile = $dbForInternal->findOne('users', [new Query('email', Query::TYPE_EQUAL, [$email])]); // Get user by email address
if ($profile) {
throw new Exception('User already registered', 409);
}
try { try {
$user = $dbForInternal->updateDocument('users', $user->getId(), $user $user = $dbForInternal->updateDocument('users', $user->getId(), $user
->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', '')) ->setAttribute('password', $isAnonymousUser ? Auth::passwordHash($password) : $user->getAttribute('password', ''))
->setAttribute('email', $email) ->setAttribute('email', $email)
->setAttribute('emailVerification', false) // After this user needs to confirm mail again ->setAttribute('emailVerification', false) // After this user needs to confirm mail again
->setAttribute('search', implode(' ', [$user->getId(), $user->getAttribute('name'), $user->getAttribute('email')]))
); );
} catch(Duplicate $th) { } catch(Duplicate $th) {
throw new Exception('Email already exists', 409); throw new Exception('Email already exists', 409);
@ -1598,7 +1611,6 @@ App::put('/v1/account/recovery')
* We act like we're updating and validating * We act like we're updating and validating
* the recovery token but actually we don't need it anymore. * the recovery token but actually we don't need it anymore.
*/ */
foreach ($tokens as $key => $token) { foreach ($tokens as $key => $token) {
if ($recovery === $token->getId()) { if ($recovery === $token->getId()) {
$recovery = $token; $recovery = $token;

View file

@ -209,12 +209,6 @@ App::get('/v1/database/collections')
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
$queries = [];
if (!empty($search)) {
$queries[] = new Query('name', Query::TYPE_SEARCH, [$search]);
}
if (!empty($after)) { if (!empty($after)) {
$afterCollection = $dbForInternal->getDocument('collections', $after); $afterCollection = $dbForInternal->getDocument('collections', $after);
@ -223,6 +217,12 @@ App::get('/v1/database/collections')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('name', Query::TYPE_SEARCH, [$search]);
}
$usage->setParam('database.collections.read', 1); $usage->setParam('database.collections.read', 1);
$response->dynamic(new Document([ $response->dynamic(new Document([

View file

@ -53,8 +53,9 @@ App::post('/v1/functions')
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
$functionId = ($functionId == 'unique()') ? $dbForInternal->getId() : $functionId;
$function = $dbForInternal->createDocument('functions', new Document([ $function = $dbForInternal->createDocument('functions', new Document([
'$id' => $functionId == 'unique()' ? $dbForInternal->getId() : $functionId, '$id' => $functionId,
'execute' => $execute, 'execute' => $execute,
'dateCreated' => time(), 'dateCreated' => time(),
'dateUpdated' => time(), 'dateUpdated' => time(),
@ -68,6 +69,7 @@ App::post('/v1/functions')
'schedulePrevious' => 0, 'schedulePrevious' => 0,
'scheduleNext' => 0, 'scheduleNext' => 0,
'timeout' => $timeout, 'timeout' => $timeout,
'search' => implode(' ', [$functionId, $name, $runtime]),
])); ]));
$response->setStatusCode(Response::STATUS_CODE_CREATED); $response->setStatusCode(Response::STATUS_CODE_CREATED);
@ -96,8 +98,6 @@ App::get('/v1/functions')
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : [];
if (!empty($after)) { if (!empty($after)) {
$afterFunction = $dbForInternal->getDocument('functions', $after); $afterFunction = $dbForInternal->getDocument('functions', $after);
@ -106,6 +106,12 @@ App::get('/v1/functions')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$response->dynamic(new Document([ $response->dynamic(new Document([
'functions' => $dbForInternal->find('functions', $queries, $limit, $offset, [], [$orderType], $afterFunction ?? null), 'functions' => $dbForInternal->find('functions', $queries, $limit, $offset, [], [$orderType], $afterFunction ?? null),
'sum' => $dbForInternal->count('functions', $queries, APP_LIMIT_COUNT), 'sum' => $dbForInternal->count('functions', $queries, APP_LIMIT_COUNT),
@ -271,6 +277,7 @@ App::put('/v1/functions/:functionId')
'schedule' => $schedule, 'schedule' => $schedule,
'scheduleNext' => (int)$next, 'scheduleNext' => (int)$next,
'timeout' => $timeout, 'timeout' => $timeout,
'search' => implode(' ', [$functionId, $name, $function->getAttribute('runtime')]),
]))); ])));
if ($next && $schedule !== $original) { if ($next && $schedule !== $original) {
@ -447,8 +454,9 @@ App::post('/v1/functions/:functionId/tags')
throw new Exception('Failed moving file', 500); throw new Exception('Failed moving file', 500);
} }
$tagId = $dbForInternal->getId();
$tag = $dbForInternal->createDocument('tags', new Document([ $tag = $dbForInternal->createDocument('tags', new Document([
'$id' => $dbForInternal->getId(), '$id' => $tagId,
'$read' => [], '$read' => [],
'$write' => [], '$write' => [],
'functionId' => $function->getId(), 'functionId' => $function->getId(),
@ -456,6 +464,7 @@ App::post('/v1/functions/:functionId/tags')
'command' => $command, 'command' => $command,
'path' => $path, 'path' => $path,
'size' => $size, 'size' => $size,
'search' => implode(' ', [$tagId, $command]),
])); ]));
$usage $usage
@ -495,8 +504,6 @@ App::get('/v1/functions/:functionId/tags')
throw new Exception('Function not found', 404); throw new Exception('Function not found', 404);
} }
$queries[] = new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]);
if (!empty($after)) { if (!empty($after)) {
$afterTag = $dbForInternal->getDocument('tags', $after); $afterTag = $dbForInternal->getDocument('tags', $after);
@ -505,6 +512,14 @@ App::get('/v1/functions/:functionId/tags')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$queries[] = new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]);
$results = $dbForInternal->find('tags', $queries, $limit, $offset, [], [$orderType], $afterTag ?? null); $results = $dbForInternal->find('tags', $queries, $limit, $offset, [], [$orderType], $afterTag ?? null);
$sum = $dbForInternal->count('tags', $queries, APP_LIMIT_COUNT); $sum = $dbForInternal->count('tags', $queries, APP_LIMIT_COUNT);
@ -665,8 +680,10 @@ App::post('/v1/functions/:functionId/executions')
Authorization::disable(); Authorization::disable();
$executionId = $dbForInternal->getId();
$execution = $dbForInternal->createDocument('executions', new Document([ $execution = $dbForInternal->createDocument('executions', new Document([
'$id' => $dbForInternal->getId(), '$id' => $executionId,
'$read' => (!$user->isEmpty()) ? ['user:' . $user->getId()] : [], '$read' => (!$user->isEmpty()) ? ['user:' . $user->getId()] : [],
'$write' => [], '$write' => [],
'dateCreated' => time(), 'dateCreated' => time(),
@ -678,6 +695,7 @@ App::post('/v1/functions/:functionId/executions')
'stdout' => '', 'stdout' => '',
'stderr' => '', 'stderr' => '',
'time' => 0.0, 'time' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
])); ]));
Authorization::reset(); Authorization::reset();
@ -732,10 +750,11 @@ App::get('/v1/functions/:functionId/executions')
->param('functionId', '', new UID(), 'Function unique ID.') ->param('functionId', '', new UID(), 'Function unique ID.')
->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->param('after', '', new UID(), 'ID of the execution used as the starting point for the query, excluding the execution itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('after', '', new UID(), 'ID of the execution used as the starting point for the query, excluding the execution itself. Should be used for efficient pagination when working with large sets of data.', true)
->inject('response') ->inject('response')
->inject('dbForInternal') ->inject('dbForInternal')
->action(function ($functionId, $limit, $offset, $after, $response, $dbForInternal) { ->action(function ($functionId, $limit, $offset, $search, $after, $response, $dbForInternal) {
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
@ -755,13 +774,17 @@ App::get('/v1/functions/:functionId/executions')
} }
} }
$results = $dbForInternal->find('executions', [ $queries = [
new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]), new Query('functionId', Query::TYPE_EQUAL, [$function->getId()])
], $limit, $offset, [], [Database::ORDER_DESC], $afterExecution ?? null); ];
$sum = $dbForInternal->count('executions', [ if (!empty($search)) {
new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]), $queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
], APP_LIMIT_COUNT); }
$results = $dbForInternal->find('executions', $queries, $limit, $offset, [], [Database::ORDER_DESC], $afterExecution ?? null);
$sum = $dbForInternal->count('executions', $queries, APP_LIMIT_COUNT);
$response->dynamic(new Document([ $response->dynamic(new Document([
'executions' => $results, 'executions' => $results,

View file

@ -79,6 +79,7 @@ App::post('/v1/projects')
$auths[$method['key'] ?? ''] = true; $auths[$method['key'] ?? ''] = true;
} }
$projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId;
$project = $dbForConsole->createDocument('projects', new Document([ $project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId, '$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId,
'$read' => ['team:' . $teamId], '$read' => ['team:' . $teamId],
@ -101,7 +102,8 @@ App::post('/v1/projects')
'webhooks' => null, 'webhooks' => null,
'keys' => null, 'keys' => null,
'domains' => null, 'domains' => null,
'auths' => $auths 'auths' => $auths,
'search' => implode(' ', [$projectId, $name]),
])); ]));
$collections = Config::getParam('collections2', []); /** @var array $collections */ $collections = Config::getParam('collections2', []); /** @var array $collections */
@ -173,8 +175,6 @@ App::get('/v1/projects')
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */ /** @var Utopia\Database\Database $dbForConsole */
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : [];
if (!empty($after)) { if (!empty($after)) {
$afterProject = $dbForConsole->getDocument('projects', $after); $afterProject = $dbForConsole->getDocument('projects', $after);
@ -183,6 +183,12 @@ App::get('/v1/projects')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$results = $dbForConsole->find('projects', $queries, $limit, $offset, [], [$orderType], $afterProject ?? null); $results = $dbForConsole->find('projects', $queries, $limit, $offset, [], [$orderType], $afterProject ?? null);
$sum = $dbForConsole->count('projects', $queries, APP_LIMIT_COUNT); $sum = $dbForConsole->count('projects', $queries, APP_LIMIT_COUNT);
@ -358,6 +364,7 @@ App::patch('/v1/projects/:projectId')
->setAttribute('legalCity', $legalCity) ->setAttribute('legalCity', $legalCity)
->setAttribute('legalAddress', $legalAddress) ->setAttribute('legalAddress', $legalAddress)
->setAttribute('legalTaxId', $legalTaxId) ->setAttribute('legalTaxId', $legalTaxId)
->setAttribute('search', implode(' ', [$projectId, $name]))
); );
$response->dynamic($project, Response::MODEL_PROJECT); $response->dynamic($project, Response::MODEL_PROJECT);

View file

@ -125,13 +125,14 @@ App::post('/v1/storage/files')
$sizeActual = $device->getFileSize($path); $sizeActual = $device->getFileSize($path);
$fileId = ($fileId == 'unique()') ? $dbForInternal->getId() : $fileId;
$file = $dbForInternal->createDocument('files', new Document([ $file = $dbForInternal->createDocument('files', new Document([
'$id' => $fileId == 'unique()' ? $dbForInternal->getId() : $fileId, '$id' => $fileId,
'$read' => (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? [], // By default set read permissions for user '$read' => (is_null($read) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $read ?? [], // By default set read permissions for user
'$write' => (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? [], // By default set write permissions for user '$write' => (is_null($write) && !$user->isEmpty()) ? ['user:'.$user->getId()] : $write ?? [], // By default set write permissions for user
'dateCreated' => \time(), 'dateCreated' => \time(),
'bucketId' => '', 'bucketId' => '',
'name' => $file['name'], 'name' => $file['name'] ?? '',
'path' => $path, 'path' => $path,
'signature' => $device->getFileHash($path), 'signature' => $device->getFileHash($path),
'mimeType' => $mimeType, 'mimeType' => $mimeType,
@ -143,6 +144,7 @@ App::post('/v1/storage/files')
'openSSLCipher' => OpenSSL::CIPHER_AES_128_GCM, 'openSSLCipher' => OpenSSL::CIPHER_AES_128_GCM,
'openSSLTag' => \bin2hex($tag), 'openSSLTag' => \bin2hex($tag),
'openSSLIV' => \bin2hex($iv), 'openSSLIV' => \bin2hex($iv),
'search' => implode(' ', [$fileId, $file['name'] ?? '',]),
])); ]));
$audits $audits
@ -185,8 +187,6 @@ App::get('/v1/storage/files')
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
/** @var Appwrite\Stats\Stats $usage */ /** @var Appwrite\Stats\Stats $usage */
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, $search)] : [];
if (!empty($after)) { if (!empty($after)) {
$afterFile = $dbForInternal->getDocument('files', $after); $afterFile = $dbForInternal->getDocument('files', $after);
@ -195,6 +195,12 @@ App::get('/v1/storage/files')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$usage $usage
->setParam('storage.files.read', 1) ->setParam('storage.files.read', 1)
->setParam('bucketId', 'default') ->setParam('bucketId', 'default')

View file

@ -57,6 +57,7 @@ App::post('/v1/teams')
'name' => $name, 'name' => $name,
'sum' => ($isPrivilegedUser || $isAppUser) ? 0 : 1, 'sum' => ($isPrivilegedUser || $isAppUser) ? 0 : 1,
'dateCreated' => \time(), 'dateCreated' => \time(),
'search' => implode(' ', [$teamId, $name]),
])); ]));
Authorization::reset(); Authorization::reset();
@ -107,8 +108,6 @@ App::get('/v1/teams')
/** @var Appwrite\Utopia\Response $response */ /** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForInternal */ /** @var Utopia\Database\Database $dbForInternal */
$queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : [];
if (!empty($after)) { if (!empty($after)) {
$afterTeam = $dbForInternal->getDocument('teams', $after); $afterTeam = $dbForInternal->getDocument('teams', $after);
@ -117,6 +116,12 @@ App::get('/v1/teams')
} }
} }
$queries = [];
if (!empty($search)) {
$queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$results = $dbForInternal->find('teams', $queries, $limit, $offset, [], [$orderType], $afterTeam ?? null); $results = $dbForInternal->find('teams', $queries, $limit, $offset, [], [$orderType], $afterTeam ?? null);
$sum = $dbForInternal->count('teams', $queries, APP_LIMIT_COUNT); $sum = $dbForInternal->count('teams', $queries, APP_LIMIT_COUNT);
@ -179,7 +184,10 @@ App::put('/v1/teams/:teamId')
throw new Exception('Team not found', 404); throw new Exception('Team not found', 404);
} }
$team = $dbForInternal->updateDocument('teams', $team->getId(), $team->setAttribute('name', $name)); $team = $dbForInternal->updateDocument('teams', $team->getId(),$team
->setAttribute('name', $name)
->setAttribute('search', implode(' ', [$teamId, $name]))
);
$response->dynamic($team, Response::MODEL_TEAM); $response->dynamic($team, Response::MODEL_TEAM);
}); });
@ -323,6 +331,7 @@ App::post('/v1/teams/:teamId/memberships')
'sessions' => [], 'sessions' => [],
'tokens' => [], 'tokens' => [],
'memberships' => [], 'memberships' => [],
'search' => implode(' ', [$userId, $email, $name]),
])); ]));
} catch (Duplicate $th) { } catch (Duplicate $th) {
throw new Exception('Account already exists', 409); throw new Exception('Account already exists', 409);

View file

@ -66,6 +66,7 @@ App::post('/v1/users')
'sessions' => [], 'sessions' => [],
'tokens' => [], 'tokens' => [],
'memberships' => [], 'memberships' => [],
'search' => implode(' ', [$userId, $email, $name]),
'deleted' => false 'deleted' => false
])); ]));
} catch (Duplicate $th) { } catch (Duplicate $th) {
@ -107,25 +108,26 @@ App::get('/v1/users')
if (!empty($after)) { if (!empty($after)) {
$afterUser = $dbForInternal->getDocument('users', $after); $afterUser = $dbForInternal->getDocument('users', $after);
if ($afterUser->isEmpty() || $afterUser->getAttribute('deleted')) { if ($afterUser->isEmpty()) {
throw new Exception('User for after not found', 400); throw new Exception("User '{$after}' for the 'after' value not found.", 400);
} }
} }
$results = $dbForInternal->find('users', [ $queries = [
new Query('deleted', Query::TYPE_EQUAL, [false]), new Query('deleted', Query::TYPE_EQUAL, [false])
], $limit, $offset, [], [$orderType], $afterUser ?? null); ];
$sum = $dbForInternal->count('users', [
new Query('deleted', Query::TYPE_EQUAL, [false]), if (!empty($search)) {
], APP_LIMIT_COUNT); $queries[] = new Query('search', Query::TYPE_SEARCH, [$search]);
}
$usage $usage
->setParam('users.read', 1) ->setParam('users.read', 1)
; ;
$response->dynamic(new Document([ $response->dynamic(new Document([
'users' => $results, 'users' => $dbForInternal->find('users', $queries, $limit, $offset, [], [$orderType], $afterUser ?? null),
'sum' => $sum, 'sum' => $dbForInternal->count('users', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_USER_LIST); ]), Response::MODEL_USER_LIST);
}); });

View file

@ -78,6 +78,45 @@ class FunctionsCustomServerTest extends Scope
* Test for SUCCESS * Test for SUCCESS
*/ */
/**
* Test search queries
*/
$response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['functionId']
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertCount(1, $response['body']['functions']);
$this->assertEquals($response['body']['functions'][0]['name'], 'Test');
$response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'Test'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertCount(1, $response['body']['functions']);
$this->assertEquals($response['body']['functions'][0]['$id'], $data['functionId']);
$response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'php-8.0'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertCount(1, $response['body']['functions']);
$this->assertEquals($response['body']['functions'][0]['$id'], $data['functionId']);
/**
* Test pagination
*/
$response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ $response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
@ -122,7 +161,6 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(1, $response['body']['functions']); $this->assertCount(1, $response['body']['functions']);
$this->assertEquals($response['body']['functions'][0]['name'], 'Test 2'); $this->assertEquals($response['body']['functions'][0]['name'], 'Test 2');
return $data; return $data;
} }
@ -283,6 +321,48 @@ class FunctionsCustomServerTest extends Scope
$this->assertIsArray($function['body']['tags']); $this->assertIsArray($function['body']['tags']);
$this->assertCount(1, $function['body']['tags']); $this->assertCount(1, $function['body']['tags']);
/**
* Test search queries
*/
$function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/tags', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
'search' => $data['functionId']
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['sum'], 1);
$this->assertIsArray($function['body']['tags']);
$this->assertCount(1, $function['body']['tags']);
$this->assertEquals($function['body']['tags'][0]['$id'], $data['tagId']);
$function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/tags', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
'search' => 'Test'
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['sum'], 1);
$this->assertIsArray($function['body']['tags']);
$this->assertCount(1, $function['body']['tags']);
$this->assertEquals($function['body']['tags'][0]['$id'], $data['tagId']);
$function = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/tags', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
'search' => 'php-8.0'
]));
$this->assertEquals($function['headers']['status-code'], 200);
$this->assertEquals($function['body']['sum'], 1);
$this->assertIsArray($function['body']['tags']);
$this->assertCount(1, $function['body']['tags']);
$this->assertEquals($function['body']['tags'][0]['$id'], $data['tagId']);
return $data; return $data;
} }
@ -394,6 +474,36 @@ class FunctionsCustomServerTest extends Scope
$this->assertCount(1, $function['body']['executions']); $this->assertCount(1, $function['body']['executions']);
$this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']); $this->assertEquals($function['body']['executions'][0]['$id'], $data['executionId']);
/**
* Test search queries
*/
$response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['executionId'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertCount(1, $response['body']['executions']);
$this->assertEquals($data['functionId'], $response['body']['executions'][0]['functionId']);
$response = $this->client->call(Client::METHOD_GET, '/functions/'.$data['functionId'].'/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['functionId'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertCount(1, $response['body']['executions']);
$this->assertEquals($data['executionId'], $response['body']['executions'][0]['$id']);
return $data; return $data;
} }

View file

@ -87,6 +87,7 @@ class ProjectsConsoleClientTest extends Scope
/** /**
* Test for SUCCESS * Test for SUCCESS
*/ */
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
@ -97,6 +98,35 @@ class ProjectsConsoleClientTest extends Scope
$this->assertEquals($id, $response['body']['projects'][0]['$id']); $this->assertEquals($id, $response['body']['projects'][0]['$id']);
$this->assertEquals('Project Test', $response['body']['projects'][0]['name']); $this->assertEquals('Project Test', $response['body']['projects'][0]['name']);
/**
* Test search queries
*/
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
'search' => $id
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['sum'], 1);
$this->assertIsArray($response['body']['projects']);
$this->assertCount(1, $response['body']['projects']);
$this->assertEquals($response['body']['projects'][0]['name'], 'Project Test');
$response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders(), [
'search' => 'Project Test'
]));
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertEquals($response['body']['sum'], 1);
$this->assertIsArray($response['body']['projects']);
$this->assertCount(1, $response['body']['projects']);
$this->assertEquals($response['body']['projects'][0]['$id'], $data['projectId']);
/** /**
* Test after pagination * Test after pagination
*/ */

View file

@ -163,7 +163,7 @@ trait StorageBase
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
'fileId' => 'unique()', 'fileId' => 'unique()',
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/file.png'), 'image/png', 'file.png'),
'read' => ['role:all'], 'read' => ['role:all'],
'write' => ['role:all'], 'write' => ['role:all'],
]); ]);
@ -171,9 +171,9 @@ trait StorageBase
$this->assertEquals($file['headers']['status-code'], 201); $this->assertEquals($file['headers']['status-code'], 201);
$this->assertNotEmpty($file['body']['$id']); $this->assertNotEmpty($file['body']['$id']);
$this->assertIsInt($file['body']['dateCreated']); $this->assertIsInt($file['body']['dateCreated']);
$this->assertEquals('logo.png', $file['body']['name']); $this->assertEquals('file.png', $file['body']['name']);
$this->assertEquals('image/png', $file['body']['mimeType']); $this->assertEquals('image/jpeg', $file['body']['mimeType']);
$this->assertEquals(47218, $file['body']['sizeOriginal']); $this->assertEquals(16804, $file['body']['sizeOriginal']);
$files = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([ $files = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
@ -197,6 +197,32 @@ trait StorageBase
$this->assertEquals($files['body']['files'][1]['$id'], $response['body']['files'][0]['$id']); $this->assertEquals($files['body']['files'][1]['$id'], $response['body']['files'][0]['$id']);
$this->assertCount(1, $response['body']['files']); $this->assertCount(1, $response['body']['files']);
$response = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['fileId'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertCount(1, $response['body']['files']);
$this->assertEquals('logo.png', $response['body']['files'][0]['name']);
$response = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'logo',
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertCount(1, $response['body']['files']);
$this->assertEquals($data['fileId'], $response['body']['files'][0]['$id']);
/** /**
* Test for FAILURE * Test for FAILURE
*/ */

View file

@ -172,6 +172,19 @@ trait TeamsBase
$this->assertCount(1, $response['body']['teams']); $this->assertCount(1, $response['body']['teams']);
$this->assertEquals('Manchester United', $response['body']['teams'][0]['name']); $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']);
$response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['teamUid'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertGreaterThan(0, $response['body']['sum']);
$this->assertIsInt($response['body']['sum']);
$this->assertCount(1, $response['body']['teams']);
$this->assertEquals('Arsenal', $response['body']['teams'][0]['name']);
$teams = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ $teams = $this->client->call(Client::METHOD_GET, '/teams', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],

View file

@ -16,14 +16,14 @@ trait UsersBase
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
'userId' => 'unique()', 'userId' => 'unique()',
'email' => 'users.service@example.com', 'email' => 'cristiano.ronaldo@manchester-united.co.uk',
'password' => 'password', 'password' => 'password',
'name' => 'Project User', 'name' => 'Cristiano Ronaldo',
]); ]);
$this->assertEquals($user['headers']['status-code'], 201); $this->assertEquals($user['headers']['status-code'], 201);
$this->assertEquals($user['body']['name'], 'Project User'); $this->assertEquals($user['body']['name'], 'Cristiano Ronaldo');
$this->assertEquals($user['body']['email'], 'users.service@example.com'); $this->assertEquals($user['body']['email'], 'cristiano.ronaldo@manchester-united.co.uk');
$this->assertEquals($user['body']['status'], true); $this->assertEquals($user['body']['status'], true);
$this->assertGreaterThan(0, $user['body']['registration']); $this->assertGreaterThan(0, $user['body']['registration']);
@ -35,15 +35,15 @@ trait UsersBase
'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [ ], $this->getHeaders()), [
'userId' => 'user1', 'userId' => 'user1',
'email' => 'users.service1@example.com', 'email' => 'lionel.messi@psg.fr',
'password' => 'password', 'password' => 'password',
'name' => 'Project User', 'name' => 'Lionel Messi',
]); ]);
$this->assertEquals($res['headers']['status-code'], 201); $this->assertEquals($res['headers']['status-code'], 201);
$this->assertEquals($res['body']['$id'], 'user1'); $this->assertEquals($res['body']['$id'], 'user1');
$this->assertEquals($res['body']['name'], 'Project User'); $this->assertEquals($res['body']['name'], 'Lionel Messi');
$this->assertEquals($res['body']['email'], 'users.service1@example.com'); $this->assertEquals($res['body']['email'], 'lionel.messi@psg.fr');
$this->assertEquals(true, $res['body']['status']); $this->assertEquals(true, $res['body']['status']);
$this->assertGreaterThan(0, $res['body']['registration']); $this->assertGreaterThan(0, $res['body']['registration']);
@ -56,7 +56,7 @@ trait UsersBase
public function testListUsers(array $data): void public function testListUsers(array $data): void
{ {
/** /**
* Test for SUCCESS * Test for SUCCESS listUsers
*/ */
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([ $response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json', 'content-type' => 'application/json',
@ -82,8 +82,72 @@ trait UsersBase
$this->assertNotEmpty($response['body']); $this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']); $this->assertNotEmpty($response['body']['users']);
$this->assertCount(1, $response['body']['users']); $this->assertCount(1, $response['body']['users']);
$this->assertEquals($response['body']['users'][0]['$id'], 'user1'); $this->assertEquals($response['body']['users'][0]['$id'], 'user1');
/**
* Test for SUCCESS searchUsers
*/
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'Ronaldo'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']);
$this->assertCount(1, $response['body']['users']);
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'cristiano.ronaldo'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']);
$this->assertCount(1, $response['body']['users']);
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'manchester'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']);
$this->assertCount(1, $response['body']['users']);
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'manchester-united.co.uk'
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertIsArray($response['body']);
$this->assertIsArray($response['body']['users']);
$this->assertIsInt($response['body']['sum']);
$this->assertEquals(1, $response['body']['sum']);
$this->assertCount(1, $response['body']['users']);
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => $data['userId']
]);
$this->assertEquals($response['headers']['status-code'], 200);
$this->assertNotEmpty($response['body']);
$this->assertNotEmpty($response['body']['users']);
$this->assertCount(1, $response['body']['users']);
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
} }
/** /**
@ -100,8 +164,8 @@ trait UsersBase
], $this->getHeaders())); ], $this->getHeaders()));
$this->assertEquals($user['headers']['status-code'], 200); $this->assertEquals($user['headers']['status-code'], 200);
$this->assertEquals($user['body']['name'], 'Project User'); $this->assertEquals($user['body']['name'], 'Cristiano Ronaldo');
$this->assertEquals($user['body']['email'], 'users.service@example.com'); $this->assertEquals($user['body']['email'], 'cristiano.ronaldo@manchester-united.co.uk');
$this->assertEquals($user['body']['status'], true); $this->assertEquals($user['body']['status'], true);
$this->assertGreaterThan(0, $user['body']['registration']); $this->assertGreaterThan(0, $user['body']['registration']);
@ -132,21 +196,6 @@ trait UsersBase
$this->assertIsInt($users['body']['sum']); $this->assertIsInt($users['body']['sum']);
$this->assertGreaterThan(0, $users['body']['sum']); $this->assertGreaterThan(0, $users['body']['sum']);
$users = $this->client->call(Client::METHOD_GET, '/users', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'example.com'
]);
$this->assertEquals($users['headers']['status-code'], 200);
$this->assertIsArray($users['body']);
$this->assertIsArray($users['body']['users']);
$this->assertIsInt($users['body']['sum']);
$this->assertEquals(2, $users['body']['sum']);
$this->assertGreaterThan(0, $users['body']['sum']);
$this->assertCount(2, $users['body']['users']);
return $data; return $data;
} }