1
0
Fork 0
mirror of synced 2024-06-02 10:54:44 +12:00

Merge pull request #3380 from appwrite/origin/feat-internal-id

Origin/feat internal ids for account / teams / users
This commit is contained in:
Torsten Dittmann 2022-06-20 17:32:44 +02:00 committed by GitHub
commit e7f328c2fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 296 additions and 170 deletions

View file

@ -97,6 +97,17 @@ $collections = [
'$id' => 'attributes',
'name' => 'Attributes',
'attributes' => [
[
'$id' => 'collectionInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'collectionId',
'type' => Database::VAR_STRING,
@ -229,7 +240,7 @@ $collections = [
[
'$id' => '_key_collection',
'type' => Database::INDEX_KEY,
'attributes' => ['collectionId'],
'attributes' => ['collectionInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -241,6 +252,17 @@ $collections = [
'$id' => 'indexes',
'name' => 'Indexes',
'attributes' => [
[
'$id' => 'collectionInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'collectionId',
'type' => Database::VAR_STRING,
@ -323,10 +345,10 @@ $collections = [
[
'$id' => '_key_collection',
'type' => Database::INDEX_KEY,
'attributes' => ['collectionId'],
'attributes' => ['collectionInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
]
],
],
@ -335,6 +357,17 @@ $collections = [
'$id' => 'projects',
'name' => 'Projects',
'attributes' => [
[
'$id' => 'teamInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'teamId',
'type' => Database::VAR_STRING,
@ -572,6 +605,17 @@ $collections = [
'$id' => 'platforms',
'name' => 'platforms',
'attributes' => [
[
'$id' => 'projectInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'projectId',
'type' => Database::VAR_STRING,
@ -643,7 +687,7 @@ $collections = [
[
'$id' => '_key_project',
'type' => Database::INDEX_KEY,
'attributes' => ['projectId'],
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -655,6 +699,17 @@ $collections = [
'$id' => 'domains',
'name' => 'domains',
'attributes' => [
[
'$id' => 'projectInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'projectId',
'type' => Database::VAR_STRING,
@ -737,7 +792,7 @@ $collections = [
[
'$id' => '_key_project',
'type' => Database::INDEX_KEY,
'attributes' => ['projectId'],
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -749,6 +804,17 @@ $collections = [
'$id' => 'keys',
'name' => 'keys',
'attributes' => [
[
'$id' => 'projectInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'projectId',
'type' => Database::VAR_STRING,
@ -809,7 +875,7 @@ $collections = [
[
'$id' => '_key_project',
'type' => Database::INDEX_KEY,
'attributes' => ['projectId'],
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -821,6 +887,17 @@ $collections = [
'$id' => 'webhooks',
'name' => 'webhooks',
'attributes' => [
[
'$id' => 'projectInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'projectId',
'type' => Database::VAR_STRING,
@ -914,10 +991,10 @@ $collections = [
[
'$id' => '_key_project',
'type' => Database::INDEX_KEY,
'attributes' => ['projectId'],
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
]
],
],
@ -1093,6 +1170,17 @@ $collections = [
'$id' => 'tokens',
'name' => 'Tokens',
'attributes' => [
[
'$id' => 'userInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'userId',
'type' => Database::VAR_STRING,
@ -1164,7 +1252,7 @@ $collections = [
[
'$id' => '_key_user',
'type' => Database::INDEX_KEY,
'attributes' => ['userId'],
'attributes' => ['userInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -1176,6 +1264,17 @@ $collections = [
'$id' => 'sessions',
'name' => 'Sessions',
'attributes' => [
[
'$id' => 'userInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'userId',
'type' => Database::VAR_STRING,
@ -1441,7 +1540,7 @@ $collections = [
[
'$id' => '_key_user',
'type' => Database::INDEX_KEY,
'attributes' => ['userId'],
'attributes' => ['userInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -1504,7 +1603,7 @@ $collections = [
'name' => 'Memberships',
'attributes' => [
[
'$id' => 'teamId',
'$id' => 'userInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
@ -1525,6 +1624,28 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => 'teamInternalId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'teamId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'roles',
'type' => Database::VAR_STRING,
@ -1596,21 +1717,21 @@ $collections = [
[
'$id' => '_key_unique',
'type' => Database::INDEX_UNIQUE,
'attributes' => ['teamId', 'userId'],
'attributes' => ['teamInternalId', 'userInternalId'],
'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
'$id' => '_key_team',
'$id' => '_key_internal',
'type' => Database::INDEX_KEY,
'attributes' => ['teamId'],
'attributes' => ['userInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => '_key_user',
'$id' => '_key_team',
'type' => Database::INDEX_KEY,
'attributes' => ['userId'],
'attributes' => ['teamInternalId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
@ -1660,7 +1781,6 @@ $collections = [
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
@ -1821,7 +1941,6 @@ $collections = [
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
@ -2101,7 +2220,6 @@ $collections = [
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
@ -2529,7 +2647,6 @@ $collections = [
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[

View file

@ -178,6 +178,7 @@ App::post('/v1/account/sessions')
[
'$id' => $dbForProject->getId(),
'userId' => $profile->getId(),
'userInternalId' => $profile->getInternalId(),
'provider' => Auth::SESSION_PROVIDER_EMAIL,
'providerUid' => $email,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
@ -507,6 +508,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
$session = new Document(array_merge([
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'provider' => $provider,
'providerUid' => $oauth2ID,
'providerAccessToken' => $accessToken,
@ -661,6 +663,7 @@ App::post('/v1/account/sessions/magic-url')
$token = new Document([
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'type' => Auth::TOKEN_TYPE_MAGIC_URL,
'secret' => Auth::hash($loginSecret), // One way hash encryption to protect DB leak
'expire' => $expire,
@ -738,6 +741,8 @@ App::put('/v1/account/sessions/magic-url')
->inject('events')
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Event $events) {
/** @var Utopia\Database\Document $user */
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
if ($user->isEmpty()) {
@ -758,6 +763,7 @@ App::put('/v1/account/sessions/magic-url')
[
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'provider' => Auth::SESSION_PROVIDER_MAGIC_URL,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expiry,
@ -901,6 +907,7 @@ App::post('/v1/account/sessions/anonymous')
[
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'provider' => Auth::SESSION_PROVIDER_ANONYMOUS,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expiry,
@ -1679,6 +1686,7 @@ App::post('/v1/account/recovery')
$recovery = new Document([
'$id' => $dbForProject->getId(),
'userId' => $profile->getId(),
'userInternalId' => $profile->getInternalId(),
'type' => Auth::TOKEN_TYPE_RECOVERY,
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak
'expire' => $expire,
@ -1839,6 +1847,7 @@ App::post('/v1/account/verification')
$verification = new Document([
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'type' => Auth::TOKEN_TYPE_VERIFICATION,
'secret' => Auth::hash($verificationSecret), // One way hash encryption to protect DB leak
'expire' => $expire,

View file

@ -47,6 +47,7 @@ use MaxMind\Db\Reader;
*
*
* @return Document Newly created attribute document
* @throws Exception
*/
function createAttribute(string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage): Document
{
@ -84,8 +85,9 @@ function createAttribute(string $collectionId, Document $attribute, Response $re
try {
$attribute = new Document([
'$id' => $collectionId . '_' . $key,
'$id' => $collection->getInternalId() . '_' . $key,
'key' => $key,
'collectionInternalId' => $collection->getInternalId(),
'collectionId' => $collectionId,
'type' => $type,
'status' => 'processing', // processing, available, failed, deleting, stuck
@ -1117,7 +1119,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:key')
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
}
$attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key);
$attribute = $dbForProject->getDocument('attributes', $collection->getInternalId() . '_' . $key);
if ($attribute->isEmpty()) {
throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND);
@ -1173,7 +1175,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key')
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
}
$attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key);
$attribute = $dbForProject->getDocument('attributes', $collection->getInternalId() . '_' . $key);
if ($attribute->isEmpty()) {
throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND);
@ -1260,8 +1262,8 @@ App::post('/v1/database/collections/:collectionId/indexes')
}
$count = $dbForProject->count('indexes', [
new Query('collectionId', Query::TYPE_EQUAL, [$collectionId])
], 61);
new Query('collectionInternalId', Query::TYPE_EQUAL, [$collection->getInternalId()])
]);
$limit = 64 - MariaDB::getNumberOfDefaultIndexes();
@ -1298,9 +1300,10 @@ App::post('/v1/database/collections/:collectionId/indexes')
try {
$index = $dbForProject->createDocument('indexes', new Document([
'$id' => $collectionId . '_' . $key,
'$id' => $collection->getInternalId() . '_' . $key,
'key' => $key,
'status' => 'processing', // processing, available, failed, deleting, stuck
'collectionInternalId' => $collection->getInternalId(),
'collectionId' => $collectionId,
'type' => $type,
'attributes' => $attributes,
@ -1438,7 +1441,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key')
throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND);
}
$index = $dbForProject->getDocument('indexes', $collectionId . '_' . $key);
$index = $dbForProject->getDocument('indexes', $collection->getInternalId() . '_' . $key);
if (empty($index->getId())) {
throw new Exception('Index not found', 404, Exception::INDEX_NOT_FOUND);

View file

@ -78,14 +78,17 @@ App::post('/v1/projects')
}
$projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId;
if ($projectId === 'console') {
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
}
$project = $dbForConsole->createDocument('projects', new Document([
'$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId,
'$id' => $projectId,
'$read' => ['team:' . $teamId],
'$write' => ['team:' . $teamId . '/owner', 'team:' . $teamId . '/developer'],
'name' => $name,
'teamInternalId' => $team->getInternalId(),
'teamId' => $team->getId(),
'description' => $description,
'logo' => $logo,
@ -109,7 +112,7 @@ App::post('/v1/projects')
/** @var array $collections */
$collections = Config::getParam('collections', []);
$dbForProject->setNamespace("_{$project->getId()}");
$dbForProject->setNamespace("_{$project->getInternalId()}");
$dbForProject->create('appwrite');
$audit = new Audit($dbForProject);
@ -268,7 +271,7 @@ App::get('/v1/projects/:projectId/usage')
],
];
$dbForProject->setNamespace("_{$projectId}");
$dbForProject->setNamespace("_{$project->getInternalId()}");
$metrics = [
'requests',
@ -589,6 +592,7 @@ App::post('/v1/projects/:projectId/webhooks')
'$id' => $dbForConsole->getId(),
'$read' => ['role:all'],
'$write' => ['role:all'],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
'name' => $name,
'events' => $events,
@ -629,7 +633,7 @@ App::get('/v1/projects/:projectId/webhooks')
}
$webhooks = $dbForConsole->find('webhooks', [
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
], 5000);
$response->dynamic(new Document([
@ -662,7 +666,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForConsole->findOne('webhooks', [
new Query('_uid', Query::TYPE_EQUAL, [$webhookId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($webhook === false || $webhook->isEmpty()) {
@ -705,7 +709,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForConsole->findOne('webhooks', [
new Query('_uid', Query::TYPE_EQUAL, [$webhookId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($webhook === false || $webhook->isEmpty()) {
@ -754,7 +758,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId')
$webhook = $dbForConsole->findOne('webhooks', [
new Query('_uid', Query::TYPE_EQUAL, [$webhookId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($webhook === false || $webhook->isEmpty()) {
@ -798,6 +802,7 @@ App::post('/v1/projects/:projectId/keys')
'$id' => $dbForConsole->getId(),
'$read' => ['role:all'],
'$write' => ['role:all'],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
'name' => $name,
'scopes' => $scopes,
@ -835,7 +840,7 @@ App::get('/v1/projects/:projectId/keys')
}
$keys = $dbForConsole->find('keys', [
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]),
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]),
], 5000);
$response->dynamic(new Document([
@ -868,7 +873,7 @@ App::get('/v1/projects/:projectId/keys/:keyId')
$key = $dbForConsole->findOne('keys', [
new Query('_uid', Query::TYPE_EQUAL, [$keyId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($key === false || $key->isEmpty()) {
@ -905,7 +910,7 @@ App::put('/v1/projects/:projectId/keys/:keyId')
$key = $dbForConsole->findOne('keys', [
new Query('_uid', Query::TYPE_EQUAL, [$keyId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($key === false || $key->isEmpty()) {
@ -948,7 +953,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId')
$key = $dbForConsole->findOne('keys', [
new Query('_uid', Query::TYPE_EQUAL, [$keyId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($key === false || $key->isEmpty()) {
@ -993,6 +998,7 @@ App::post('/v1/projects/:projectId/platforms')
'$id' => $dbForConsole->getId(),
'$read' => ['role:all'],
'$write' => ['role:all'],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
'type' => $type,
'name' => $name,
@ -1064,7 +1070,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForConsole->findOne('platforms', [
new Query('_uid', Query::TYPE_EQUAL, [$platformId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($platform === false || $platform->isEmpty()) {
@ -1101,7 +1107,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForConsole->findOne('platforms', [
new Query('_uid', Query::TYPE_EQUAL, [$platformId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($platform === false || $platform->isEmpty()) {
@ -1145,7 +1151,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId')
$platform = $dbForConsole->findOne('platforms', [
new Query('_uid', Query::TYPE_EQUAL, [$platformId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($platform === false || $platform->isEmpty()) {
@ -1185,7 +1191,7 @@ App::post('/v1/projects/:projectId/domains')
$document = $dbForConsole->findOne('domains', [
new Query('domain', Query::TYPE_EQUAL, [$domain]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]),
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]),
]);
if ($document && !$document->isEmpty()) {
@ -1204,6 +1210,7 @@ App::post('/v1/projects/:projectId/domains')
'$id' => $dbForConsole->getId(),
'$read' => ['role:all'],
'$write' => ['role:all'],
'projectInternalId' => $project->getInternalId(),
'projectId' => $project->getId(),
'updated' => \time(),
'domain' => $domain->get(),
@ -1243,7 +1250,7 @@ App::get('/v1/projects/:projectId/domains')
}
$domains = $dbForConsole->find('domains', [
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
], 5000);
$response->dynamic(new Document([
@ -1276,7 +1283,7 @@ App::get('/v1/projects/:projectId/domains/:domainId')
$domain = $dbForConsole->findOne('domains', [
new Query('_uid', Query::TYPE_EQUAL, [$domainId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($domain === false || $domain->isEmpty()) {
@ -1310,7 +1317,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
$domain = $dbForConsole->findOne('domains', [
new Query('_uid', Query::TYPE_EQUAL, [$domainId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($domain === false || $domain->isEmpty()) {
@ -1370,7 +1377,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
$domain = $dbForConsole->findOne('domains', [
new Query('_uid', Query::TYPE_EQUAL, [$domainId]),
new Query('projectId', Query::TYPE_EQUAL, [$project->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()])
]);
if ($domain === false || $domain->isEmpty()) {

View file

@ -73,7 +73,9 @@ App::post('/v1/teams')
'$read' => ['user:' . $user->getId(), 'team:' . $team->getId()],
'$write' => ['user:' . $user->getId(), 'team:' . $team->getId() . '/owner'],
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'teamId' => $team->getId(),
'teamInternalId' => $team->getInternalId(),
'roles' => $roles,
'invited' => \time(),
'joined' => \time(),
@ -366,7 +368,9 @@ App::post('/v1/teams/:teamId/memberships')
'$read' => ['role:all'],
'$write' => ['user:' . $invitee->getId(), 'team:' . $team->getId() . '/owner'],
'userId' => $invitee->getId(),
'userInternalId' => $invitee->getInternalId(),
'teamId' => $team->getId(),
'teamInternalId' => $team->getInternalId(),
'roles' => $roles,
'invited' => \time(),
'joined' => ($isPrivilegedUser || $isAppUser) ? \time() : 0,
@ -701,6 +705,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
$session = new Document(array_merge([
'$id' => $dbForProject->getId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'provider' => Auth::SESSION_PROVIDER_EMAIL,
'providerUid' => $user->getAttribute('email'),
'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak

View file

@ -257,7 +257,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('attributes', [
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], $database->getAttributeLimit());
}
);
@ -270,7 +270,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('indexes', [
new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()])
new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], 64);
}
);
@ -283,7 +283,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('platforms', [
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY);
}
);
@ -296,7 +296,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('domains', [
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY);
}
);
@ -309,7 +309,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('keys', [
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY);
}
);
@ -322,7 +322,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return $database
->find('webhooks', [
new Query('projectId', Query::TYPE_EQUAL, [$document->getId()])
new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY);
}
);
@ -334,7 +334,7 @@ Database::addFilter(
},
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn () => $database->find('sessions', [
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY));
}
);
@ -347,7 +347,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn() => $database
->find('tokens', [
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY));
}
);
@ -360,7 +360,7 @@ Database::addFilter(
function (mixed $value, Document $document, Database $database) {
return Authorization::skip(fn() => $database
->find('memberships', [
new Query('userId', Query::TYPE_EQUAL, [$document->getId()])
new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()])
], APP_LIMIT_SUBQUERY));
}
);
@ -842,6 +842,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) {
App::setResource('console', function () {
return new Document([
'$id' => 'console',
'$internalId' => 'console',
'name' => 'Appwrite',
'$collection' => 'projects',
'description' => 'Appwrite core engine',
@ -871,12 +872,12 @@ App::setResource('console', function () {
]);
}, []);
App::setResource('dbForProject', function ($db, $cache, $project) {
App::setResource('dbForProject', function ($db, $cache, Document $project) {
$cache = new Cache(new RedisCache($cache));
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$project->getId()}");
$database->setNamespace("_{$project->getInternalId()}");
return $database;
}, ['db', 'cache', 'project']);

View file

@ -150,6 +150,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume
'timestamp' => time(),
'value' => '{}'
]);
$statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document));
} catch (\Throwable $th) {
call_user_func($logError, $th, "createWorkerDocument");
@ -297,7 +298,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) {
$connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId]));
[$database, $returnDatabase] = getDatabase($register, "_{$projectId}");
[$consoleDatabase, $returnConsoleDatabase] = getDatabase($register, '_console');
$project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId));
[$database, $returnDatabase] = getDatabase($register, "_{$project->getInternalId()}");
$user = $database->getDocument('users', $userId);
@ -306,6 +309,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
call_user_func($returnDatabase);
call_user_func($returnConsoleDatabase);
}
}
@ -373,7 +377,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$project->getId()}");
$database->setNamespace("_{$project->getInternalId()}");
/*
* Project Check
@ -480,7 +484,9 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($db), $cache);
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
$database->setNamespace("_{$realtime->connections[$connection]['projectId']}");
$database->setNamespace("_console");
$project = Authorization::skip(fn() => $database->getDocument('projects', $realtime->connections[$connection]['projectId']));
$database->setNamespace("_{$project->getInternalId()}");
/*
* Abuse Check

View file

@ -15,6 +15,9 @@ use Utopia\Database\Validator\Authorization;
use Utopia\Registry\Registry;
use Utopia\Logger\Log;
Authorization::disable();
Authorization::setDefaultStatus(false);
function getDatabase(Registry &$register, string $namespace): Database
{
$attempts = 0;
@ -120,11 +123,8 @@ $cli
$influxDB = getInfluxDB($register);
$usage = new Usage($database, $influxDB, $logError);
$usageDB = new UsageDB($database, $logError);
Authorization::disable();
$iterations = 0;
Console::loop(function () use ($interval, $usage, $usageDB, &$iterations) {
$now = date('d-m-Y H:i:s', time());

View file

@ -15,9 +15,6 @@ use Utopia\Config\Config;
require_once __DIR__ . '/../init.php';
// Disable Auth since we already validate it in the API
Authorization::disable();
Console::title('Builds V1 Worker');
Console::success(APP_NAME . ' build worker v1 has started');

View file

@ -36,8 +36,6 @@ class CertificatesV1 extends Worker
public function run(): void
{
Authorization::disable();
Authorization::setDefaultStatus(false);
/**
* 1. Read arguments and validate domain
* 2. Get main domain

View file

@ -5,7 +5,6 @@ use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Resque\Worker;
use Utopia\CLI\Console;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
require_once __DIR__ . '/../init.php';
@ -20,8 +19,6 @@ class DatabaseV1 extends Worker
public function run(): void
{
Authorization::disable();
$type = $this->args['type'];
$project = new Document($this->args['project']);
$collection = new Document($this->args['collection'] ?? []);
@ -53,8 +50,6 @@ class DatabaseV1 extends Worker
Console::error('No database operation for type: ' . $type);
break;
}
Authorization::reset();
}
public function shutdown(): void

View file

@ -15,9 +15,6 @@ use Utopia\Audit\Audit;
require_once __DIR__ . '/../init.php';
Authorization::disable();
Authorization::setDefaultStatus(false);
Console::title('Deletes V1 Worker');
Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");

View file

@ -44,6 +44,10 @@ class FunctionsV1 extends Worker
$user = new Document($this->args['user'] ?? []);
$payload = json_encode($this->args['payload'] ?? []);
if ($project->getId() === 'console') {
return;
}
$database = $this->getProjectDB($project->getId());
/**
@ -57,7 +61,7 @@ class FunctionsV1 extends Worker
/** @var Document[] $functions */
while ($sum >= $limit) {
$functions = Authorization::skip(fn () => $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]));
$functions = $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]);
$sum = \count($functions);
$offset = $offset + $limit;
@ -101,7 +105,7 @@ class FunctionsV1 extends Worker
$jwt = $this->args['jwt'] ?? '';
$data = $this->args['data'] ?? '';
$function = Authorization::skip(fn () => $database->getDocument('functions', $execution->getAttribute('functionId')));
$function = $database->getDocument('functions', $execution->getAttribute('functionId'));
$this->execute(
project: $project,
@ -132,7 +136,7 @@ class FunctionsV1 extends Worker
*/
// Reschedule
$function = Authorization::skip(fn () => $database->getDocument('functions', $function->getId()));
$function = $database->getDocument('functions', $function->getId());
if (empty($function->getId())) {
throw new Exception('Function not found (' . $function->getId() . ')');
@ -149,11 +153,11 @@ class FunctionsV1 extends Worker
->setAttribute('scheduleNext', $next)
->setAttribute('schedulePrevious', \time());
$function = Authorization::skip(fn () => $database->updateDocument(
$function = $database->updateDocument(
'functions',
$function->getId(),
$function->setAttribute('scheduleNext', (int) $next)
));
);
if ($function === false) {
throw new Exception('Function update failed.');
@ -198,7 +202,7 @@ class FunctionsV1 extends Worker
$deploymentId = $function->getAttribute('deployment', '');
/** Check if deployment exists */
$deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $deploymentId));
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($deployment->getAttribute('resourceId') !== $functionId) {
throw new Exception('Deployment not found. Create deployment before trying to execute a function', 404);
@ -209,7 +213,7 @@ class FunctionsV1 extends Worker
}
/** Check if build has exists */
$build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')));
$build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''));
if ($build->isEmpty()) {
throw new Exception('Build not found', 404);
}
@ -227,38 +231,31 @@ class FunctionsV1 extends Worker
$runtime = $runtimes[$function->getAttribute('runtime')];
/**
* Create execution or update execution status
* @var Document $execution
*/
$execution = Authorization::skip(function () use ($dbForProject, &$executionId, $functionId, $deploymentId, $trigger, $user) {
$execution = $dbForProject->getDocument('executions', $executionId ?? '');
/** Create execution or update execution status */
$execution = $dbForProject->getDocument('executions', $executionId ?? '');
if ($execution->isEmpty()) {
$executionId = $dbForProject->getId();
$execution = $dbForProject->createDocument('executions', new Document([
'$id' => $executionId,
'$read' => $user->isEmpty() ? [] : ['user:' . $user->getId()],
'$write' => [],
'functionId' => $functionId,
'deploymentId' => $deploymentId,
'trigger' => $trigger,
'status' => 'waiting',
'statusCode' => 0,
'response' => '',
'stderr' => '',
'time' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
if ($execution->isEmpty()) {
$executionId = $dbForProject->getId();
$execution = $dbForProject->createDocument('executions', new Document([
'$id' => $executionId,
'$read' => $user->isEmpty() ? [] : ['user:' . $user->getId()],
'$write' => [],
'functionId' => $functionId,
'deploymentId' => $deploymentId,
'trigger' => $trigger,
'status' => 'waiting',
'statusCode' => 0,
'response' => '',
'stderr' => '',
'time' => 0.0,
'search' => implode(' ', [$functionId, $executionId]),
]));
if ($execution->isEmpty()) {
throw new Exception('Failed to create or read execution');
}
throw new Exception('Failed to create or read execution');
}
$execution->setAttribute('status', 'processing');
$execution = $dbForProject->updateDocument('executions', $executionId, $execution);
return $execution;
});
}
$execution->setAttribute('status', 'processing');
$execution = $dbForProject->updateDocument('executions', $executionId, $execution);
/** Collect environment variables */
$vars = [
@ -309,8 +306,7 @@ class FunctionsV1 extends Worker
Console::error($th->getMessage());
}
$execution = Authorization::skip(fn () => $dbForProject->updateDocument('executions', $executionId, $execution));
/** @var Document $execution */
$execution = $dbForProject->updateDocument('executions', $executionId, $execution);
/** Trigger Webhook */
$executionModel = new Execution();

View file

@ -17,6 +17,7 @@ use Utopia\Storage\Device\Wasabi;
use Utopia\Storage\Device\Backblaze;
use Utopia\Storage\Device\S3;
use Exception;
use Utopia\Database\Validator\Authorization;
abstract class Worker
{
@ -112,6 +113,11 @@ abstract class Worker
public function perform(): void
{
try {
/**
* Disabling global authorization in workers.
*/
Authorization::disable();
Authorization::setDefaultStatus(false);
$this->run();
} catch (\Throwable $error) {
foreach (self::$errorCallbacks as $errorCallback) {
@ -159,7 +165,16 @@ abstract class Worker
*/
protected function getProjectDB(string $projectId): Database
{
return $this->getDB(self::DATABASE_PROJECT, $projectId);
$consoleDB = $this->getConsoleDB();
if ($projectId === 'console') {
return $consoleDB;
}
/** @var Document $project */
$project = Authorization::skip(fn() => $consoleDB->getDocument('projects', $projectId));
return $this->getDB(self::DATABASE_PROJECT, $projectId, $project->getInternalId());
}
/**
@ -177,7 +192,7 @@ abstract class Worker
* @param string $projectId of internal or external DB
* @return Database
*/
private function getDB($type, $projectId = ''): Database
private function getDB(string $type, string $projectId = '', string $projectInternalId = ''): Database
{
global $register;
@ -189,7 +204,7 @@ abstract class Worker
if (!$projectId) {
throw new \Exception('ProjectID not provided - cannot get database');
}
$namespace = "_{$projectId}";
$namespace = "_{$projectInternalId}";
break;
case self::DATABASE_CONSOLE:
$namespace = "_console";

View file

@ -180,7 +180,10 @@ class Usage
private function createOrUpdateMetric(string $projectId, int $time, string $period, string $metric, int $value, int $type): void
{
$id = \md5("{$time}_{$period}_{$metric}");
$this->database->setNamespace('_' . $projectId);
$this->database->setNamespace('_console');
$project = $this->database->getDocument('projects', $projectId);
$this->database->setNamespace('_' . $project->getInternalId());
try {
$document = $this->database->getDocument('stats', $id);
if ($document->isEmpty()) {

View file

@ -28,7 +28,10 @@ class UsageDB extends Usage
$period = $options['key'];
$time = (int) (floor(time() / $options['multiplier']) * $options['multiplier']);
$id = \md5("{$time}_{$period}_{$metric}");
$this->database->setNamespace('_' . $projectId);
$this->database->setNamespace('_console');
$project = $this->database->getDocument('projects', $projectId);
$this->database->setNamespace('_' . $project->getInternalId());
try {
$document = $this->database->getDocument('stats', $id);
if ($document->isEmpty()) {
@ -70,15 +73,21 @@ class UsageDB extends Usage
*/
private function foreachDocument(string $projectId, string $collection, array $queries, callable $callback): void
{
if ($projectId === 'console') {
return;
}
$limit = 50;
$results = [];
$sum = $limit;
$latestDocument = null;
$this->database->setNamespace('_' . $projectId);
$this->database->setNamespace('_console');
$project = $this->database->getDocument('projects', $projectId);
$this->database->setNamespace('_' . $project->getInternalId());
while ($sum === $limit) {
try {
$results = $this->database->find($collection, $queries, $limit, cursor:$latestDocument);
$results = $this->database->find($collection, $queries, $limit, cursor: $latestDocument);
} catch (\Exception $e) {
if (is_callable($this->errorHandler)) {
call_user_func($this->errorHandler, $e, "fetch_documents_project_{$projectId}_collection_{$collection}");
@ -115,7 +124,10 @@ class UsageDB extends Usage
*/
private function sum(string $projectId, string $collection, string $attribute, string $metric): int
{
$this->database->setNamespace('_' . $projectId);
$this->database->setNamespace('_console');
$project = $this->database->getDocument('projects', $projectId);
$this->database->setNamespace('_' . $project->getInternalId());
try {
$sum = (int) $this->database->sum($collection, $attribute);
$this->createOrUpdateMetric($projectId, $metric, $sum);
@ -141,7 +153,10 @@ class UsageDB extends Usage
*/
private function count(string $projectId, string $collection, string $metric): int
{
$this->database->setNamespace("_{$projectId}");
$this->database->setNamespace('_console');
$project = $this->database->getDocument('projects', $projectId);
$this->database->setNamespace('_' . $project->getInternalId());
try {
$count = $this->database->count($collection);
$this->createOrUpdateMetric($projectId, $metric, $count);
@ -252,11 +267,12 @@ class UsageDB extends Usage
*/
public function collect(): void
{
$this->foreachDocument('console', 'projects', [], function ($project) {
$projectId = $project->getId();
$this->usersStats($projectId);
$this->databaseStats($projectId);
$this->storageStats($projectId);
$this->foreachDocument('console', 'projects', [], function (Document $project) {
$projectId = $project->getId();
$this->usersStats($projectId);
$this->databaseStats($projectId);
$this->storageStats($projectId);
});
}
}

View file

@ -789,7 +789,7 @@ class DatabaseCustomServerTest extends Scope
$this->assertEquals('available', $attribute['status'], 'attribute: ' . $attribute['key']);
}
// testing for indexLimit = 64
// Test indexLimit = 64
// MariaDB, MySQL, and MongoDB create 5 indexes per new collection
// Add up to the limit, then check if the next index throws IndexLimitException
for ($i = 0; $i < 59; $i++) {

View file

@ -587,6 +587,7 @@ class FunctionsCustomServerTest extends Scope
/**
* Test for SUCCESS
*/
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],

View file

@ -75,14 +75,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*.create", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']);
$this->assertContains("collections.*.attributes.*.create", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.*.attributes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
@ -97,14 +93,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*.update", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']);
$this->assertContains("collections.*.attributes.*.update", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.*.attributes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
@ -165,14 +157,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*.create", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']);
$this->assertContains("collections.*.indexes.*.create", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.*.indexes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
@ -187,14 +175,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*.update", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']);
$this->assertContains("collections.*.indexes.*.update", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.*.indexes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
@ -247,14 +231,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*.delete", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']);
$this->assertContains("collections.*.indexes.*.delete", $response['data']['events']);
$this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']);
$this->assertContains("collections.*.indexes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);
@ -306,14 +286,10 @@ class RealtimeConsoleClientTest extends Scope
$this->assertArrayHasKey('timestamp', $response['data']);
$this->assertCount(1, $response['data']['channels']);
$this->assertContains('console', $response['data']['channels']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*.delete", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']);
$this->assertContains("collections.{$actorsId}", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']);
$this->assertContains("collections.*.attributes.*.delete", $response['data']['events']);
$this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']);
$this->assertContains("collections.*.attributes.*", $response['data']['events']);
$this->assertContains("collections.*", $response['data']['events']);
$this->assertNotEmpty($response['data']['payload']);

View file

@ -119,13 +119,9 @@ trait WebhooksBase
$this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@ -149,13 +145,9 @@ trait WebhooksBase
$this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);

View file

@ -95,13 +95,9 @@ class WebhooksCustomServerTest extends Scope
$this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);
@ -124,13 +120,9 @@ class WebhooksCustomServerTest extends Scope
$this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString('collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']);
$this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);