diff --git a/src/Database/Adapter.php b/src/Database/Adapter.php index bac76fc73..b0c31bf24 100644 --- a/src/Database/Adapter.php +++ b/src/Database/Adapter.php @@ -1233,6 +1233,7 @@ protected function escapeWildcards(string $value): string * @param string $attribute * @param int|float $value * @param string $updatedAt + * @param string|null $updatedBy * @param int|float|null $min * @param int|float|null $max * @return bool @@ -1244,6 +1245,7 @@ abstract public function increaseDocumentAttribute( string $attribute, int|float $value, string $updatedAt, + ?string $updatedBy, int|float|null $min = null, int|float|null $max = null ): bool; diff --git a/src/Database/Adapter/MariaDB.php b/src/Database/Adapter/MariaDB.php index 5e8f15369..35a7eccf1 100644 --- a/src/Database/Adapter/MariaDB.php +++ b/src/Database/Adapter/MariaDB.php @@ -159,6 +159,8 @@ public function createCollection(string $name, array $attributes = [], array $in _uid VARCHAR(255) NOT NULL, _createdAt DATETIME(3) DEFAULT NULL, _updatedAt DATETIME(3) DEFAULT NULL, + _createdBy VARCHAR(255) DEFAULT NULL, + _updatedBy VARCHAR(255) DEFAULT NULL, _permissions MEDIUMTEXT DEFAULT NULL, PRIMARY KEY (_id), " . \implode(' ', $attributeStrings) . " @@ -171,13 +173,17 @@ public function createCollection(string $name, array $attributes = [], array $in UNIQUE KEY _uid (_uid, _tenant), KEY _created_at (_tenant, _createdAt), KEY _updated_at (_tenant, _updatedAt), + KEY _created_by (_tenant, _createdBy), + KEY _updated_by (_tenant, _updatedBy), KEY _tenant_id (_tenant, _id) "; } else { $collection .= " UNIQUE KEY _uid (_uid), KEY _created_at (_createdAt), - KEY _updated_at (_updatedAt) + KEY _updated_at (_updatedAt), + KEY _created_by (_createdBy), + KEY _updated_by (_updatedBy) "; } @@ -827,6 +833,8 @@ public function createDocument(Document $collection, Document $document): Docume $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = \json_encode($document->getPermissions()); if ($this->sharedTables) { @@ -953,6 +961,7 @@ public function updateDocument(Document $collection, string $id, Document $docum $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = json_encode($document->getPermissions()); $name = $this->filter($collection); @@ -1241,6 +1250,7 @@ public function getUpsertStatement( * @param string $attribute * @param int|float $value * @param string $updatedAt + * @param string|null $updatedBy * @param int|float|null $min * @param int|float|null $max * @return bool @@ -1252,6 +1262,7 @@ public function increaseDocumentAttribute( string $attribute, int|float $value, string $updatedAt, + ?string $updatedBy, int|float|null $min = null, int|float|null $max = null ): bool { @@ -1265,7 +1276,8 @@ public function increaseDocumentAttribute( UPDATE {$this->getSQLTable($name)} SET `{$attribute}` = `{$attribute}` + :val, - `_updatedAt` = :updatedAt + `_updatedAt` = :updatedAt, + `_updatedBy` = :updatedBy WHERE _uid = :_uid {$this->getTenantQuery($collection)} "; @@ -1278,6 +1290,7 @@ public function increaseDocumentAttribute( $stmt->bindValue(':_uid', $id); $stmt->bindValue(':val', $value); $stmt->bindValue(':updatedAt', $updatedAt); + $stmt->bindValue(':updatedBy', $updatedBy); if ($this->sharedTables) { $stmt->bindValue(':_tenant', $this->tenant); diff --git a/src/Database/Adapter/Pool.php b/src/Database/Adapter/Pool.php index c2cd363ba..341c27174 100644 --- a/src/Database/Adapter/Pool.php +++ b/src/Database/Adapter/Pool.php @@ -475,7 +475,7 @@ protected function getAttributeProjection(array $selections, string $prefix): st return $this->delegate(__FUNCTION__, \func_get_args()); } - public function increaseDocumentAttribute(string $collection, string $id, string $attribute, float|int $value, string $updatedAt, float|int|null $min = null, float|int|null $max = null): bool + public function increaseDocumentAttribute(string $collection, string $id, string $attribute, float|int $value, string $updatedAt, ?string $updatedBy, float|int|null $min = null, float|int|null $max = null): bool { return $this->delegate(__FUNCTION__, \func_get_args()); } diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index 25f9ffc34..3e813718e 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -237,6 +237,8 @@ public function createCollection(string $name, array $attributes = [], array $in " . $sqlTenant . " \"_createdAt\" TIMESTAMP(3) DEFAULT NULL, \"_updatedAt\" TIMESTAMP(3) DEFAULT NULL, + \"_createdBy\" VARCHAR(255) DEFAULT NULL, + \"_updatedBy\" VARCHAR(255) DEFAULT NULL, " . \implode(' ', $attributeStrings) . " _permissions TEXT DEFAULT NULL ); @@ -247,6 +249,8 @@ public function createCollection(string $name, array $attributes = [], array $in CREATE UNIQUE INDEX \"{$namespace}_{$this->tenant}_{$id}_uid\" ON {$this->getSQLTable($id)} (\"_uid\", \"_tenant\"); CREATE INDEX \"{$namespace}_{$this->tenant}_{$id}_created\" ON {$this->getSQLTable($id)} (_tenant, \"_createdAt\"); CREATE INDEX \"{$namespace}_{$this->tenant}_{$id}_updated\" ON {$this->getSQLTable($id)} (_tenant, \"_updatedAt\"); + CREATE INDEX \"{$namespace}_{$this->tenant}_{$id}_created_by\" ON {$this->getSQLTable($id)} (_tenant, \"_createdBy\"); + CREATE INDEX \"{$namespace}_{$this->tenant}_{$id}_updated_by\" ON {$this->getSQLTable($id)} (_tenant, \"_updatedBy\"); CREATE INDEX \"{$namespace}_{$this->tenant}_{$id}_tenant_id\" ON {$this->getSQLTable($id)} (_tenant, _id); "; } else { @@ -254,6 +258,8 @@ public function createCollection(string $name, array $attributes = [], array $in CREATE UNIQUE INDEX \"{$namespace}_{$id}_uid\" ON {$this->getSQLTable($id)} (\"_uid\"); CREATE INDEX \"{$namespace}_{$id}_created\" ON {$this->getSQLTable($id)} (\"_createdAt\"); CREATE INDEX \"{$namespace}_{$id}_updated\" ON {$this->getSQLTable($id)} (\"_updatedAt\"); + CREATE INDEX \"{$namespace}_{$id}_created_by\" ON {$this->getSQLTable($id)} (\"_createdBy\"); + CREATE INDEX \"{$namespace}_{$id}_updated_by\" ON {$this->getSQLTable($id)} (\"_updatedBy\"); "; } @@ -961,6 +967,8 @@ public function createDocument(Document $collection, Document $document): Docume $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = \json_encode($document->getPermissions()); if ($this->sharedTables) { @@ -1075,6 +1083,8 @@ public function updateDocument(Document $collection, string $id, Document $docum $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = json_encode($document->getPermissions()); $name = $this->filter($collection); @@ -1343,12 +1353,13 @@ protected function getUpsertStatement( * @param string $attribute * @param int|float $value * @param string $updatedAt + * @param string|null $updatedBy * @param int|float|null $min * @param int|float|null $max * @return bool * @throws DatabaseException */ - public function increaseDocumentAttribute(string $collection, string $id, string $attribute, int|float $value, string $updatedAt, int|float|null $min = null, int|float|null $max = null): bool + public function increaseDocumentAttribute(string $collection, string $id, string $attribute, int|float $value, string $updatedAt, ?string $updatedBy, int|float|null $min = null, int|float|null $max = null): bool { $name = $this->filter($collection); $attribute = $this->filter($attribute); @@ -1360,7 +1371,8 @@ public function increaseDocumentAttribute(string $collection, string $id, string UPDATE {$this->getSQLTable($name)} SET \"{$attribute}\" = \"{$attribute}\" + :val, - \"_updatedAt\" = :updatedAt + \"_updatedAt\" = :updatedAt, + \"_updatedBy\" = :updatedBy WHERE _uid = :_uid {$this->getTenantQuery($collection)} "; @@ -1373,6 +1385,7 @@ public function increaseDocumentAttribute(string $collection, string $id, string $stmt->bindValue(':_uid', $id); $stmt->bindValue(':val', $value); $stmt->bindValue(':updatedAt', $updatedAt); + $stmt->bindValue(':updatedBy', $updatedBy); if ($this->sharedTables) { $stmt->bindValue(':_tenant', $this->tenant); diff --git a/src/Database/Adapter/SQL.php b/src/Database/Adapter/SQL.php index 600f047f1..9c17fbe63 100644 --- a/src/Database/Adapter/SQL.php +++ b/src/Database/Adapter/SQL.php @@ -408,6 +408,14 @@ public function getDocument(Document $collection, string $id, array $queries = [ $document['$updatedAt'] = $document['_updatedAt']; unset($document['_updatedAt']); } + if (\array_key_exists('_createdBy', $document)) { + $document['$createdBy'] = $document['_createdBy']; + unset($document['_createdBy']); + } + if (\array_key_exists('_updatedBy', $document)) { + $document['$updatedBy'] = $document['_updatedBy']; + unset($document['_updatedBy']); + } if (\array_key_exists('_permissions', $document)) { $document['$permissions'] = json_decode($document['_permissions'] ?? '[]', true); unset($document['_permissions']); @@ -468,6 +476,14 @@ public function updateDocuments(Document $collection, Document $updates, array $ $attributes['_createdAt'] = $updates->getCreatedAt(); } + if (!empty($updates->getCreatedBy())) { + $attributes['_createdBy'] = $updates->getCreatedBy(); + } + + if (!empty($updates->getUpdatedBy())) { + $attributes['_updatedBy'] = $updates->getUpdatedBy(); + } + if ($updates->offsetExists('$permissions')) { $attributes['_permissions'] = json_encode($updates->getPermissions()); } @@ -1053,10 +1069,12 @@ public function getAttributeWidth(Document $collection): int * `_tenant` int => 4 bytes * `_createdAt` datetime(3) => 7 bytes * `_updatedAt` datetime(3) => 7 bytes + * `_createdBy` varchar(255) => 1021 (4 * 255 + 1) bytes + * `_updatedBy` varchar(255) => 1021 (4 * 255 + 1) bytes * `_permissions` mediumtext => 20 */ - $total = 1067; + $total = 3109; $attributes = $collection->getAttributes()['attributes']; @@ -1892,6 +1910,8 @@ protected function getAttributeProjection(array $selections, string $prefix): st '$permissions', '$createdAt', '$updatedAt', + '$createdBy', + '$updatedBy' ]; $selections = \array_diff($selections, [...$internalKeys, '$collection']); @@ -1919,6 +1939,8 @@ protected function getInternalKeyForAttribute(string $attribute): string '$tenant' => '_tenant', '$createdAt' => '_createdAt', '$updatedAt' => '_updatedAt', + '$createdBy' => '_createdBy', + '$updatedBy' => '_updatedBy', '$permissions' => '_permissions', default => $attribute }; @@ -2013,6 +2035,8 @@ public function createDocuments(Document $collection, array $documents): array $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); $attributes['_permissions'] = \json_encode($document->getPermissions()); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); if (!empty($document->getSequence())) { $attributes['_id'] = $document->getSequence(); @@ -2127,6 +2151,8 @@ public function upsertDocuments( $attributes['_uid'] = $document->getId(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = \json_encode($document->getPermissions()); if (!empty($document->getSequence())) { @@ -2504,6 +2530,14 @@ public function find(Document $collection, array $queries = [], ?int $limit = 25 $results[$index]['$updatedAt'] = $document['_updatedAt']; unset($results[$index]['_updatedAt']); } + if (\array_key_exists('_createdBy', $document)) { + $results[$index]['$createdBy'] = $document['_createdBy']; + unset($results[$index]['_createdBy']); + } + if (\array_key_exists('_updatedBy', $document)) { + $results[$index]['$updatedBy'] = $document['_updatedBy']; + unset($results[$index]['_updatedBy']); + } if (\array_key_exists('_permissions', $document)) { $results[$index]['$permissions'] = \json_decode($document['_permissions'] ?? '[]', true); unset($results[$index]['_permissions']); diff --git a/src/Database/Adapter/SQLite.php b/src/Database/Adapter/SQLite.php index ff0246265..51b0c3cae 100644 --- a/src/Database/Adapter/SQLite.php +++ b/src/Database/Adapter/SQLite.php @@ -168,6 +168,8 @@ public function createCollection(string $name, array $attributes = [], array $in {$tenantQuery} `_createdAt` DATETIME(3) DEFAULT NULL, `_updatedAt` DATETIME(3) DEFAULT NULL, + `_createdBy` VARCHAR(255) DEFAULT NULL, + `_updatedBy` VARCHAR(255) DEFAULT NULL, `_permissions` MEDIUMTEXT DEFAULT NULL".(!empty($attributes) ? ',' : '')." " . \substr(\implode(' ', $attributeStrings), 0, -2) . " ) @@ -525,6 +527,8 @@ public function createDocument(Document $collection, Document $document): Docume $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = json_encode($document->getPermissions()); if ($this->sharedTables) { @@ -647,6 +651,8 @@ public function updateDocument(Document $collection, string $id, Document $docum $attributes = $document->getAttributes(); $attributes['_createdAt'] = $document->getCreatedAt(); $attributes['_updatedAt'] = $document->getUpdatedAt(); + $attributes['_createdBy'] = $document->getCreatedBy(); + $attributes['_updatedBy'] = $document->getUpdatedBy(); $attributes['_permissions'] = json_encode($document->getPermissions()); if ($this->sharedTables) { @@ -1032,6 +1038,8 @@ protected function getSQLIndex(string $collection, string $id, string $type, arr '$id' => ID::custom('_uid'), '$createdAt' => '_createdAt', '$updatedAt' => '_updatedAt', + '$createdBy' => '_createdBy', + '$updatedBy' => '_updatedBy', default => $attribute }, $attributes); diff --git a/src/Database/Database.php b/src/Database/Database.php index 90a6d378f..e20d95cc2 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -230,6 +230,28 @@ class Database 'array' => false, 'filters' => ['datetime'] ], + [ + '$id' => '$createdBy', + 'type' => self::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => '$updatedBy', + 'type' => self::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [] + ], [ '$id' => '$permissions', 'type' => Database::VAR_STRING, @@ -246,6 +268,8 @@ class Database '_uid', '_createdAt', '_updatedAt', + '_createdBy', + '_updatedBy', '_permissions', ]; @@ -254,6 +278,8 @@ class Database '_uid', '_createdAt', '_updatedAt', + '_createdBy', + '_updatedBy', '_permissions_id', '_permissions', ]; @@ -3865,12 +3891,16 @@ public function createDocument(string $collection, Document $document): Document $createdAt = $document->getCreatedAt(); $updatedAt = $document->getUpdatedAt(); + $createdBy = $document->getCreatedBy(); + $updatedBy = $document->getUpdatedBy(); $document ->setAttribute('$id', empty($document->getId()) ? ID::unique() : $document->getId()) ->setAttribute('$collection', $collection->getId()) ->setAttribute('$createdAt', ($createdAt === null || !$this->preserveDates) ? $time : $createdAt) - ->setAttribute('$updatedAt', ($updatedAt === null || !$this->preserveDates) ? $time : $updatedAt); + ->setAttribute('$updatedAt', ($updatedAt === null || !$this->preserveDates) ? $time : $updatedAt) + ->setAttribute('$createdBy', $createdBy === null ? Authorization::getUser() : $createdBy) + ->setAttribute('$updatedBy', $updatedBy === null ? Authorization::getUser() : $updatedBy); if (empty($document->getPermissions())) { $document->setAttribute('$permissions', []); @@ -3971,12 +4001,17 @@ public function createDocuments( foreach ($documents as $document) { $createdAt = $document->getCreatedAt(); $updatedAt = $document->getUpdatedAt(); + $createdBy = $document->getCreatedBy(); + $updatedBy = $document->getUpdatedBy(); $document ->setAttribute('$id', empty($document->getId()) ? ID::unique() : $document->getId()) ->setAttribute('$collection', $collection->getId()) ->setAttribute('$createdAt', ($createdAt === null || !$this->preserveDates) ? $time : $createdAt) - ->setAttribute('$updatedAt', ($updatedAt === null || !$this->preserveDates) ? $time : $updatedAt); + ->setAttribute('$updatedAt', ($updatedAt === null || !$this->preserveDates) ? $time : $updatedAt) + ->setAttribute('$createdBy', $createdBy === null ? Authorization::getUser() : $createdBy) + ->setAttribute('$updatedBy', $updatedBy === null ? Authorization::getUser() : $updatedBy); + if (empty($document->getPermissions())) { $document->setAttribute('$permissions', []); @@ -4385,7 +4420,8 @@ public function updateDocument(string $collection, string $id, Document $documen $collection = $this->silent(fn () => $this->getCollection($collection)); $newUpdatedAt = $document->getUpdatedAt(); - $document = $this->withTransaction(function () use ($collection, $id, $document, $newUpdatedAt) { + $newUpdatedBy = $document->getUpdatedBy(); + $document = $this->withTransaction(function () use ($collection, $id, $document, $newUpdatedAt, $newUpdatedBy) { $time = DateTime::now(); $old = Authorization::skip(fn () => $this->silent( fn () => $this->getDocument($collection->getId(), $id, forUpdate: true) @@ -4406,10 +4442,12 @@ public function updateDocument(string $collection, string $id, Document $documen $skipPermissionsUpdate = ($originalPermissions === $currentPermissions); } $createdAt = $document->getCreatedAt(); + $createdBy = $document->getCreatedBy(); $document = \array_merge($old->getArrayCopy(), $document->getArrayCopy()); $document['$collection'] = $old->getAttribute('$collection'); // Make sure user doesn't switch collection ID $document['$createdAt'] = ($createdAt === null || !$this->preserveDates) ? $old->getCreatedAt() : $createdAt; + $document['$createdBy'] = $createdBy === null ? $old->getCreatedBy() : $createdBy; if ($this->adapter->getSharedTables()) { $document['$tenant'] = $old->getTenant(); // Make sure user doesn't switch tenant @@ -4534,6 +4572,7 @@ public function updateDocument(string $collection, string $id, Document $documen if ($shouldUpdate) { $document->setAttribute('$updatedAt', ($newUpdatedAt === null || !$this->preserveDates) ? $time : $newUpdatedAt); + $document->setAttribute('$updatedBy', $newUpdatedBy === null ? Authorization::getUser() : $newUpdatedBy); } // Check if document was updated after the request timestamp @@ -4663,12 +4702,20 @@ public function updateDocuments( $updates['$createdAt'] = $updates->getCreatedAt(); } + if ($updates->getCreatedBy() === null) { + unset($updates['$createdBy']); + } else { + $updates['$createdBy'] = $updates->getCreatedBy(); + } + if ($this->adapter->getSharedTables()) { $updates['$tenant'] = $this->adapter->getTenant(); } $updatedAt = $updates->getUpdatedAt(); + $updatedBy = $updates->getUpdatedBy(); $updates['$updatedAt'] = ($updatedAt === null || !$this->preserveDates) ? DateTime::now() : $updatedAt; + $updates['$updatedBy'] = $updatedBy === null ? Authorization::getUser() : $updatedBy; $updates = $this->encode($collection, $updates); // Check new document structure @@ -5334,11 +5381,12 @@ public function upsertDocumentsWithIncrease( } $updatedAt = $document->getUpdatedAt(); - + $updatedBy = $document->getUpdatedBy(); $document ->setAttribute('$id', empty($document->getId()) ? ID::unique() : $document->getId()) ->setAttribute('$collection', $collection->getId()) ->setAttribute('$updatedAt', ($updatedAt === null || !$this->preserveDates) ? $time : $updatedAt) + ->setAttribute('$updatedBy', $updatedBy === null ? Authorization::getUser() : $updatedBy) ->removeAttribute('$sequence'); $createdAt = $document->getCreatedAt(); @@ -5348,6 +5396,12 @@ public function upsertDocumentsWithIncrease( $document->setAttribute('$createdAt', $createdAt); } + $createdBy = $document->getCreatedBy(); + if ($createdBy === null) { + $document->setAttribute('$createdBy', $old->isEmpty() ? Authorization::getUser() : $old->getCreatedBy()); + } else { + $document->setAttribute('$createdBy', $createdBy); + } // Force matching optional parameter sets // Doesn't use decode as that intentionally skips null defaults to reduce payload size foreach ($collectionAttributes as $attr) { @@ -5548,6 +5602,7 @@ public function increaseDocumentAttribute( $time = DateTime::now(); $updatedAt = $document->getUpdatedAt(); $updatedAt = (empty($updatedAt) || !$this->preserveDates) ? $time : $updatedAt; + $updatedBy = Authorization::getUser(); $max = $max ? $max - $value : null; $this->adapter->increaseDocumentAttribute( @@ -5556,12 +5611,12 @@ public function increaseDocumentAttribute( $attribute, $value, $updatedAt, + $updatedBy, max: $max ); - return $document->setAttribute( - $attribute, - $document->getAttribute($attribute) + $value + return $document->setAttributes( + [$attribute => $document->getAttribute($attribute) + $value, '$updatedAt' => $updatedAt, '$updatedBy' => $updatedBy] ); }); @@ -5647,6 +5702,7 @@ public function decreaseDocumentAttribute( $time = DateTime::now(); $updatedAt = $document->getUpdatedAt(); $updatedAt = (empty($updatedAt) || !$this->preserveDates) ? $time : $updatedAt; + $updatedBy = Authorization::getUser(); $min = $min ? $min + $value : null; $this->adapter->increaseDocumentAttribute( @@ -5655,12 +5711,12 @@ public function decreaseDocumentAttribute( $attribute, $value * -1, $updatedAt, + $updatedBy, min: $min ); - return $document->setAttribute( - $attribute, - $document->getAttribute($attribute) - $value + return $document->setAttributes( + [$attribute => $document->getAttribute($attribute) - $value, '$updatedAt' => $updatedAt, '$updatedBy' => $updatedBy] ); }); diff --git a/src/Database/Document.php b/src/Database/Document.php index e8a7a3a08..1fed790de 100644 --- a/src/Database/Document.php +++ b/src/Database/Document.php @@ -164,6 +164,14 @@ public function getCreatedAt(): ?string return $this->getAttribute('$createdAt'); } + /** + * @return string|null + */ + public function getCreatedBy(): ?string + { + return $this->getAttribute('$createdBy'); + } + /** * @return string|null */ @@ -172,6 +180,14 @@ public function getUpdatedAt(): ?string return $this->getAttribute('$updatedAt'); } + /** + * @return string|null + */ + public function getUpdatedBy(): ?string + { + return $this->getAttribute('$updatedBy'); + } + /** * @return int|null */ diff --git a/src/Database/Validator/Authorization.php b/src/Database/Validator/Authorization.php index 2dd645ba7..3347b2a3d 100644 --- a/src/Database/Validator/Authorization.php +++ b/src/Database/Validator/Authorization.php @@ -2,6 +2,7 @@ namespace Utopia\Database\Validator; +use Utopia\Database\Helpers\Role; use Utopia\Validator; class Authorization extends Validator @@ -23,6 +24,11 @@ class Authorization extends Validator */ protected string $message = 'Authorization Error'; + /** + * @var string|null + */ + protected static ?string $user = null; + /** * @param string $action */ @@ -82,6 +88,11 @@ public function isValid($permissions): bool */ public static function setRole(string $role): void { + $parsedRole = Role::parse($role); + if ($parsedRole->getRole() === 'user') { + $userIdetifier = $parsedRole->getIdentifier(); + self::$user = $userIdetifier; + } self::$roles[$role] = true; } @@ -92,9 +103,23 @@ public static function setRole(string $role): void */ public static function unsetRole(string $role): void { + $parsedRole = Role::parse($role); + if ($parsedRole->getRole() === 'user' && self::$user === $parsedRole->getIdentifier()) { + self::$user = null; + } unset(self::$roles[$role]); } + /** + * Get current user + * + * @return string|null + */ + public static function getUser(): string|null + { + return self::$user; + } + /** * @return array */ diff --git a/src/Database/Validator/Structure.php b/src/Database/Validator/Structure.php index cfb12fa3a..664ecfa87 100644 --- a/src/Database/Validator/Structure.php +++ b/src/Database/Validator/Structure.php @@ -84,7 +84,29 @@ class Structure extends Validator 'signed' => false, 'array' => false, 'filters' => [], - ] + ], + [ + '$id' => '$createdBy', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [] + ], + [ + '$id' => '$updatedBy', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [] + ], ]; /** diff --git a/tests/e2e/Adapter/Scopes/AttributeTests.php b/tests/e2e/Adapter/Scopes/AttributeTests.php index 89ab81a50..a9524e210 100644 --- a/tests/e2e/Adapter/Scopes/AttributeTests.php +++ b/tests/e2e/Adapter/Scopes/AttributeTests.php @@ -803,7 +803,7 @@ public function testWidthLimit(): void $collection = $database->createCollection('width_limit'); $init = $database->getAdapter()->getAttributeWidth($collection); - $this->assertEquals(1067, $init); + $this->assertEquals(3109, $init); $attribute = new Document([ '$id' => ID::custom('varchar_100'), @@ -957,7 +957,7 @@ public function testExceptionWidthLimit(): void $attributes[] = new Document([ '$id' => ID::custom('varchar_16000'), 'type' => Database::VAR_STRING, - 'size' => 16000, + 'size' => 15500, 'required' => true, 'default' => null, 'signed' => true, @@ -1816,13 +1816,13 @@ public function testCreateAttributesMissingRequired(): void { /** @var Database $database */ $database = static::getDatabase(); - + $collectionName = uniqid('test_attr_missing'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); $attributes = [[ '$id' => 'foo', @@ -1830,7 +1830,7 @@ public function testCreateAttributesMissingRequired(): void 'size' => 10 ]]; try { - $database->createAttributes(__FUNCTION__, $attributes); + $database->createAttributes($collectionName, $attributes); $this->fail('Expected DatabaseException not thrown'); } catch (\Throwable $e) { $this->assertInstanceOf(DatabaseException::class, $e); @@ -1841,14 +1841,15 @@ public function testCreateAttributesDuplicateMetadata(): void { /** @var Database $database */ $database = static::getDatabase(); + $collecitonName = uniqid('test_attr_dup'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); - $database->createAttribute(__FUNCTION__, 'dup', Database::VAR_STRING, 10, false); + $database->createCollection($collecitonName); + $database->createAttribute($collecitonName, 'dup', Database::VAR_STRING, 10, false); $attributes = [[ '$id' => 'dup', @@ -1858,7 +1859,7 @@ public function testCreateAttributesDuplicateMetadata(): void ]]; try { - $database->createAttributes(__FUNCTION__, $attributes); + $database->createAttributes($collecitonName, $attributes); $this->fail('Expected DuplicateException not thrown'); } catch (\Throwable $e) { $this->assertInstanceOf(DuplicateException::class, $e); @@ -1924,13 +1925,14 @@ public function testCreateAttributesDefaultOnRequired(): void { /** @var Database $database */ $database = static::getDatabase(); + $collectionName = uniqid('test_attr_def_req'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); $attributes = [[ '$id' => 'foo', @@ -1941,7 +1943,7 @@ public function testCreateAttributesDefaultOnRequired(): void ]]; try { - $database->createAttributes(__FUNCTION__, $attributes); + $database->createAttributes($collectionName, $attributes); $this->fail('Expected DatabaseException not thrown'); } catch (\Throwable $e) { $this->assertInstanceOf(DatabaseException::class, $e); @@ -1979,13 +1981,13 @@ public function testCreateAttributesStringSizeLimit(): void { /** @var Database $database */ $database = static::getDatabase(); - + $collectionName = uniqid('test_str_size'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); $max = $database->getAdapter()->getLimitForString(); @@ -1997,7 +1999,7 @@ public function testCreateAttributesStringSizeLimit(): void ]]; try { - $database->createAttributes(__FUNCTION__, $attributes); + $database->createAttributes($collectionName, $attributes); $this->fail('Expected DatabaseException not thrown'); } catch (\Throwable $e) { $this->assertInstanceOf(DatabaseException::class, $e); @@ -2008,13 +2010,14 @@ public function testCreateAttributesIntegerSizeLimit(): void { /** @var Database $database */ $database = static::getDatabase(); + $collectionName = uniqid('test_int_size'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); $limit = $database->getAdapter()->getLimitForInt() / 2; @@ -2026,7 +2029,7 @@ public function testCreateAttributesIntegerSizeLimit(): void ]]; try { - $database->createAttributes(__FUNCTION__, $attributes); + $database->createAttributes($collectionName, $attributes); $this->fail('Expected DatabaseException not thrown'); } catch (\Throwable $e) { $this->assertInstanceOf(DatabaseException::class, $e); @@ -2037,13 +2040,14 @@ public function testCreateAttributesSuccessMultiple(): void { /** @var Database $database */ $database = static::getDatabase(); + $collectionName = uniqid('test_attr_success'); if (!$database->getAdapter()->getSupportForBatchCreateAttributes()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); $attributes = [ [ @@ -2060,16 +2064,16 @@ public function testCreateAttributesSuccessMultiple(): void ], ]; - $result = $database->createAttributes(__FUNCTION__, $attributes); + $result = $database->createAttributes($collectionName, $attributes); $this->assertTrue($result); - $collection = $database->getCollection(__FUNCTION__); + $collection = $database->getCollection($collectionName); $attrs = $collection->getAttribute('attributes'); $this->assertCount(2, $attrs); $this->assertEquals('a', $attrs[0]['$id']); $this->assertEquals('b', $attrs[1]['$id']); - $doc = $database->createDocument(__FUNCTION__, new Document([ + $doc = $database->createDocument($collectionName, new Document([ 'a' => 'foo', 'b' => 123, ])); diff --git a/tests/e2e/Adapter/Scopes/CollectionTests.php b/tests/e2e/Adapter/Scopes/CollectionTests.php index 5178a414d..5a1b753c5 100644 --- a/tests/e2e/Adapter/Scopes/CollectionTests.php +++ b/tests/e2e/Adapter/Scopes/CollectionTests.php @@ -607,7 +607,7 @@ public function testRowSizeToLarge(): void $collection_1 = $database->createCollection('row_size_1'); $collection_2 = $database->createCollection('row_size_2'); - $this->assertEquals(true, $database->createAttribute($collection_1->getId(), 'attr_1', Database::VAR_STRING, 16000, true)); + $this->assertEquals(true, $database->createAttribute($collection_1->getId(), 'attr_1', Database::VAR_STRING, 15500, true)); try { $database->createAttribute($collection_1->getId(), 'attr_2', Database::VAR_STRING, Database::LENGTH_KEY, true); diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 200dfa871..adc06241e 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -398,41 +398,46 @@ public function testCreateDocuments(): void public function testCreateDocumentsWithAutoIncrement(): void { + $collectionName = 'tesstAutoIncr'; /** @var Database $database */ $database = static::getDatabase(); + try { - $database->createCollection(__FUNCTION__); + $database->createCollection($collectionName); - $this->assertEquals(true, $database->createAttribute(__FUNCTION__, 'string', Database::VAR_STRING, 128, true)); + $this->assertEquals(true, $database->createAttribute($collectionName, 'string', Database::VAR_STRING, 128, true)); - /** @var array $documents */ - $documents = []; - $count = 10; - $sequence = 1_000_000; + /** @var array $documents */ + $documents = []; + $count = 10; + $sequence = 1_000_000; - for ($i = $sequence; $i <= ($sequence + $count); $i++) { - $documents[] = new Document([ - '$sequence' => (string)$i, - '$permissions' => [ - Permission::read(Role::any()), - Permission::create(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'string' => 'text', - ]); - } + for ($i = $sequence; $i <= ($sequence + $count); $i++) { + $documents[] = new Document([ + '$sequence' => (string)$i, + '$permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'string' => 'text', + ]); + } - $count = $database->createDocuments(__FUNCTION__, $documents, 6); - $this->assertEquals($count, \count($documents)); + $count = $database->createDocuments($collectionName, $documents, 6); + $this->assertEquals($count, \count($documents)); - $documents = $database->find(__FUNCTION__, [ - Query::orderAsc() - ]); - foreach ($documents as $index => $document) { - $this->assertEquals($sequence + $index, $document->getSequence()); - $this->assertNotEmpty(true, $document->getId()); - $this->assertEquals('text', $document->getAttribute('string')); + $documents = $database->find($collectionName, [ + Query::orderAsc() + ]); + foreach ($documents as $index => $document) { + $this->assertEquals($sequence + $index, $document->getSequence()); + $this->assertNotEmpty(true, $document->getId()); + $this->assertEquals('text', $document->getAttribute('string')); + } + } finally { + $database->deleteCollection($collectionName); } } @@ -860,22 +865,23 @@ public function testUpsertDocumentsAttributeMismatch(): void { /** @var Database $database */ $database = static::getDatabase(); + $collectionName = uniqid("test_attr_"); if (!$database->getAdapter()->getSupportForUpserts()) { $this->expectNotToPerformAssertions(); return; } - $database->createCollection(__FUNCTION__, permissions: [ + $database->createCollection($collectionName, permissions: [ Permission::create(Role::any()), Permission::read(Role::any()), Permission::update(Role::any()), Permission::delete(Role::any()), ], documentSecurity: false); - $database->createAttribute(__FUNCTION__, 'first', Database::VAR_STRING, 128, true); - $database->createAttribute(__FUNCTION__, 'last', Database::VAR_STRING, 128, false); + $database->createAttribute($collectionName, 'first', Database::VAR_STRING, 128, true); + $database->createAttribute($collectionName, 'last', Database::VAR_STRING, 128, false); - $existingDocument = $database->createDocument(__FUNCTION__, new Document([ + $existingDocument = $database->createDocument($collectionName, new Document([ '$id' => 'first', 'first' => 'first', 'last' => 'last', @@ -887,7 +893,7 @@ public function testUpsertDocumentsAttributeMismatch(): void ]); // Ensure missing optionals on new document is allowed - $docs = $database->upsertDocuments(__FUNCTION__, [ + $docs = $database->upsertDocuments($collectionName, [ $existingDocument->setAttribute('first', 'updated'), $newDocument, ]); @@ -899,7 +905,7 @@ public function testUpsertDocumentsAttributeMismatch(): void $this->assertEquals('', $newDocument->getAttribute('last')); try { - $database->upsertDocuments(__FUNCTION__, [ + $database->upsertDocuments($collectionName, [ $existingDocument->removeAttribute('first'), $newDocument ]); @@ -909,7 +915,7 @@ public function testUpsertDocumentsAttributeMismatch(): void } // Ensure missing optionals on existing document is allowed - $docs = $database->upsertDocuments(__FUNCTION__, [ + $docs = $database->upsertDocuments($collectionName, [ $existingDocument ->setAttribute('first', 'first') ->removeAttribute('last'), @@ -924,7 +930,7 @@ public function testUpsertDocumentsAttributeMismatch(): void $this->assertEquals('last', $newDocument->getAttribute('last')); // Ensure set null on existing document is allowed - $docs = $database->upsertDocuments(__FUNCTION__, [ + $docs = $database->upsertDocuments($collectionName, [ $existingDocument ->setAttribute('first', 'first') ->setAttribute('last', null), @@ -951,7 +957,7 @@ public function testUpsertDocumentsAttributeMismatch(): void ]); // Ensure mismatch of attribute orders is allowed - $docs = $database->upsertDocuments(__FUNCTION__, [ + $docs = $database->upsertDocuments($collectionName, [ $doc3, $doc4 ]); @@ -962,8 +968,8 @@ public function testUpsertDocumentsAttributeMismatch(): void $this->assertEquals('fourth', $doc4->getAttribute('first')); $this->assertEquals('last', $doc4->getAttribute('last')); - $doc3 = $database->getDocument(__FUNCTION__, 'third'); - $doc4 = $database->getDocument(__FUNCTION__, 'fourth'); + $doc3 = $database->getDocument($collectionName, 'third'); + $doc4 = $database->getDocument($collectionName, 'fourth'); $this->assertEquals('third', $doc3->getAttribute('first')); $this->assertEquals('last', $doc3->getAttribute('last')); @@ -1208,6 +1214,7 @@ public function testIncreaseDecrease(): Document $document = $database->getDocument($collection, $document->getId()); $this->assertEquals(104.4, $document->getAttribute('increase_float')); + $database->deleteCollection($collection); return $document; } @@ -6020,4 +6027,221 @@ public function testCreateUpdateDocumentsMismatch(): void } $database->deleteCollection($colName); } + + public function testCreatedByUpdatedBy(): void + { + $collection = 'test_created_updated_by'; + $database = static::getDatabase(); + + $database->createCollection($collection); + $database->createAttribute($collection, 'string', Database::VAR_STRING, 128, false); + $database->createAttribute($collection, 'number', Database::VAR_INTEGER, 0, false); + + Authorization::setRole('user:test_user_1'); + $doc1 = $database->createDocument($collection, new Document([ + '$id' => 'test1', + 'string' => 'test1', + 'number' => 100, + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ])); + + $this->assertEquals('test_user_1', $doc1->getCreatedBy()); + $this->assertEquals('test_user_1', $doc1->getUpdatedBy()); + + $retrievedDoc1 = $database->getDocument($collection, 'test1'); + $this->assertEquals('test_user_1', $retrievedDoc1->getCreatedBy()); + $this->assertEquals('test_user_1', $retrievedDoc1->getUpdatedBy()); + + $doc2 = $database->createDocument($collection, new Document([ + '$id' => 'test2', + 'string' => 'test2', + 'number' => 200, + '$createdBy' => 'explicit_creator', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ])); + + $this->assertEquals('explicit_creator', $doc2->getCreatedBy()); + $this->assertEquals('test_user_1', $doc2->getUpdatedBy()); + + $retrievedDoc2 = $database->getDocument($collection, 'test2'); + $this->assertEquals('explicit_creator', $retrievedDoc2->getCreatedBy()); + $this->assertEquals('test_user_1', $retrievedDoc2->getUpdatedBy()); + + $doc3 = $database->createDocument($collection, new Document([ + '$id' => 'test3', + 'string' => 'test3', + 'number' => 300, + '$updatedBy' => 'explicit_updater', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ])); + + $this->assertEquals('test_user_1', $doc3->getCreatedBy()); + $this->assertEquals('explicit_updater', $doc3->getUpdatedBy()); + + $retrievedDoc3 = $database->getDocument($collection, 'test3'); + $this->assertEquals('test_user_1', $retrievedDoc3->getCreatedBy()); + $this->assertEquals('explicit_updater', $retrievedDoc3->getUpdatedBy()); + + $doc4 = $database->createDocument($collection, new Document([ + '$id' => 'test4', + 'string' => 'test4', + 'number' => 400, + '$createdBy' => 'explicit_creator_2', + '$updatedBy' => 'explicit_updater_2', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ])); + + $this->assertEquals('explicit_creator_2', $doc4->getCreatedBy()); + $this->assertEquals('explicit_updater_2', $doc4->getUpdatedBy()); + + $retrievedDoc4 = $database->getDocument($collection, 'test4'); + $this->assertEquals('explicit_creator_2', $retrievedDoc4->getCreatedBy()); + $this->assertEquals('explicit_updater_2', $retrievedDoc4->getUpdatedBy()); + + $allDocs = $database->find($collection); + $this->assertCount(4, $allDocs); + + Authorization::setRole('user:test_user_2'); + $updateDoc = new Document([ + 'string' => 'updated_test1', + 'number' => 150 + ]); + $updatedDoc = $database->updateDocument($collection, 'test1', $updateDoc); + + // Verify createdBy is preserved, updatedBy changes to current user + $this->assertEquals('test_user_1', $updatedDoc->getCreatedBy()); // Should preserve original creator + $this->assertEquals('test_user_2', $updatedDoc->getUpdatedBy()); // Should update to current user + + $retrievedUpdatedDoc = $database->getDocument($collection, 'test1'); + $this->assertEquals('test_user_1', $retrievedUpdatedDoc->getCreatedBy()); + $this->assertEquals('test_user_2', $retrievedUpdatedDoc->getUpdatedBy()); + + $upsertDoc = new Document([ + '$id' => 'test2', + 'string' => 'upserted_test2', + 'number' => 250 + ]); + if ($database->getAdapter()->getSupportForUpserts()) { + $upsertCount = $database->upsertDocuments($collection, [$upsertDoc]); + $this->assertEquals(1, $upsertCount); + + $upsertedDoc = $database->getDocument($collection, 'test2'); + $this->assertEquals('explicit_creator', $upsertedDoc->getCreatedBy()); // Should preserve original creator + $this->assertEquals('test_user_2', $upsertedDoc->getUpdatedBy()); // Should update to current user + + $upsertNewDoc = new Document([ + '$id' => 'test5', + 'string' => 'new_test5', + 'number' => 500, + '$createdBy' => 'new_creator', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ]); + + $upsertNewCount = $database->upsertDocuments($collection, [$upsertNewDoc]); + $this->assertEquals(1, $upsertNewCount); + + $newUpsertedDoc = $database->getDocument($collection, 'test5'); + $this->assertEquals('new_creator', $newUpsertedDoc->getCreatedBy()); // Should use explicit creator + $this->assertEquals('test_user_2', $newUpsertedDoc->getUpdatedBy()); // Should use current user + + $bulkDocs = [ + new Document([ + '$id' => 'bulk1', + 'string' => 'bulk1', + 'number' => 600, + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ]), + new Document([ + '$id' => 'bulk2', + 'string' => 'bulk2', + 'number' => 700, + '$createdBy' => 'bulk_creator', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ]), + new Document([ + '$id' => 'bulk3', + 'string' => 'bulk3', + 'number' => 800, + '$updatedBy' => 'bulk_updater', + '$permissions' => [Permission::read(Role::any()), Permission::write(Role::any()), Permission::update(Role::any())] + ]) + ]; + $bulkCount = $database->createDocuments($collection, $bulkDocs); + $this->assertEquals(3, $bulkCount); + + $bulkDoc1 = $database->getDocument($collection, 'bulk1'); + $bulkDoc2 = $database->getDocument($collection, 'bulk2'); + $bulkDoc3 = $database->getDocument($collection, 'bulk3'); + + $this->assertEquals('test_user_2', $bulkDoc1->getCreatedBy()); + $this->assertEquals('test_user_2', $bulkDoc1->getUpdatedBy()); + + $this->assertEquals('bulk_creator', $bulkDoc2->getCreatedBy()); + $this->assertEquals('test_user_2', $bulkDoc2->getUpdatedBy()); + + $this->assertEquals('test_user_2', $bulkDoc3->getCreatedBy()); + $this->assertEquals('bulk_updater', $bulkDoc3->getUpdatedBy()); + + $finalAllDocs = $database->find($collection); + $this->assertCount(8, $finalAllDocs); + + $database->deleteCollection($collection); + + // testing with increment decrement + Authorization::setRole('user:test_user_3'); + $collection = 'increase_decrease'; + $database->createCollection($collection); + + $this->assertEquals(true, $database->createAttribute($collection, 'increase', Database::VAR_INTEGER, 0, true)); + + $document = $database->createDocument($collection, new Document([ + 'increase' => 100, + '$permissions' => [ + Permission::read(Role::any()), + Permission::create(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ] + ])); + + $doc = $database->increaseDocumentAttribute($collection, $document->getId(), 'increase', 1, 301); + $this->assertEquals(101, $doc->getAttribute('increase')); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_3', $doc->getUpdatedBy()); + + $document = $database->getDocument($collection, $document->getId()); + $this->assertEquals(101, $document->getAttribute('increase')); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_3', $doc->getUpdatedBy()); + + Authorization::setRole('user:test_user_4'); + $doc = $database->increaseDocumentAttribute($collection, $document->getId(), 'increase', 1, 301); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_4', $doc->getUpdatedBy()); + + $doc = $database->getDocument($collection, $document->getId()); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_4', $doc->getUpdatedBy()); + + $doc = $database->decreaseDocumentAttribute($collection, $document->getId(), 'increase', 1, -100); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_4', $doc->getUpdatedBy()); + + $doc = $database->getDocument($collection, $document->getId()); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_4', $doc->getUpdatedBy()); + + Authorization::setRole('user:test_user_5'); + + $doc = $database->decreaseDocumentAttribute($collection, $document->getId(), 'increase', 1, -100); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_5', $doc->getUpdatedBy()); + + $doc = $database->getDocument($collection, $document->getId()); + $this->assertEquals('test_user_3', $doc->getCreatedBy()); + $this->assertEquals('test_user_5', $doc->getUpdatedBy()); + + $database->deleteCollection($collection); + } + } } diff --git a/tests/e2e/Adapter/Scopes/GeneralTests.php b/tests/e2e/Adapter/Scopes/GeneralTests.php index 1664273c1..99b62d21f 100644 --- a/tests/e2e/Adapter/Scopes/GeneralTests.php +++ b/tests/e2e/Adapter/Scopes/GeneralTests.php @@ -295,7 +295,7 @@ public function testGetAttributeLimit(): void } public function testGetIndexLimit(): void { - $this->assertEquals(58, $this->getDatabase()->getLimitForIndexes()); + $this->assertEquals(56, $this->getDatabase()->getLimitForIndexes()); } public function testGetId(): void diff --git a/tests/e2e/Adapter/Scopes/Relationships/ManyToOneTests.php b/tests/e2e/Adapter/Scopes/Relationships/ManyToOneTests.php index 73a1c7a6f..05e3adce9 100644 --- a/tests/e2e/Adapter/Scopes/Relationships/ManyToOneTests.php +++ b/tests/e2e/Adapter/Scopes/Relationships/ManyToOneTests.php @@ -1770,8 +1770,8 @@ public function testDeleteDocumentsRelationshipErrorDoesNotDeleteParent_ManyToOn return; } - $parentCollection = 'parent_relationship_error_many_to_one'; - $childCollection = 'child_relationship_error_many_to_one'; + $parentCollection = uniqid('parent_rel'); + $childCollection = uniqid('child_rel'); $database->createCollection($parentCollection); $database->createCollection($childCollection); diff --git a/tests/e2e/Adapter/Scopes/Relationships/OneToManyTests.php b/tests/e2e/Adapter/Scopes/Relationships/OneToManyTests.php index b29bf2087..681dbfc6d 100644 --- a/tests/e2e/Adapter/Scopes/Relationships/OneToManyTests.php +++ b/tests/e2e/Adapter/Scopes/Relationships/OneToManyTests.php @@ -2165,8 +2165,8 @@ public function testDeleteDocumentsRelationshipErrorDoesNotDeleteParent_OneToMan return; } - $parentCollection = 'parent_relationship_error_one_to_many'; - $childCollection = 'child_relationship_error_one_to_many'; + $parentCollection = uniqid('parent_rel'); + $childCollection = uniqid('child_rel'); $database->createCollection($parentCollection); $database->createCollection($childCollection); diff --git a/tests/e2e/Adapter/Scopes/Relationships/OneToOneTests.php b/tests/e2e/Adapter/Scopes/Relationships/OneToOneTests.php index 52881707b..ed950b0cd 100644 --- a/tests/e2e/Adapter/Scopes/Relationships/OneToOneTests.php +++ b/tests/e2e/Adapter/Scopes/Relationships/OneToOneTests.php @@ -2382,8 +2382,8 @@ public function testDeleteDocumentsRelationshipErrorDoesNotDeleteParent_OneToOne return; } - $parentCollection = 'parent_relationship_error_one_to_one'; - $childCollection = 'child_relationship_error_one_to_one'; + $parentCollection = uniqid('parent_rel'); + $childCollection = uniqid('child_rel'); $database->createCollection($parentCollection); $database->createCollection($childCollection); diff --git a/tests/e2e/Adapter/Scopes/SpatialTests.php b/tests/e2e/Adapter/Scopes/SpatialTests.php index e9839b7de..330bbfac0 100644 --- a/tests/e2e/Adapter/Scopes/SpatialTests.php +++ b/tests/e2e/Adapter/Scopes/SpatialTests.php @@ -726,7 +726,7 @@ public function testSpatialIndex(): void } // Basic spatial index create/delete - $collectionName = 'spatial_index_'; + $collectionName = uniqid('sp_idx'); try { $database->createCollection($collectionName); $database->createAttribute($collectionName, 'loc', Database::VAR_POINT, 0, true); @@ -749,7 +749,7 @@ public function testSpatialIndex(): void $orderSupported = $database->getAdapter()->getSupportForSpatialIndexOrder(); // createCollection with orders - $collOrderCreate = 'spatial_idx_order_create'; + $collOrderCreate = uniqid('sp_idx_'); try { $attributes = [new Document([ '$id' => ID::custom('loc'), @@ -787,7 +787,7 @@ public function testSpatialIndex(): void } // createIndex with orders - $collOrderIndex = 'spatial_idx_order_index_' . uniqid(); + $collOrderIndex = uniqid('sp_idx_'); try { $database->createCollection($collOrderIndex); $database->createAttribute($collOrderIndex, 'loc', Database::VAR_POINT, 0, true); @@ -809,7 +809,7 @@ public function testSpatialIndex(): void $nullSupported = $database->getAdapter()->getSupportForSpatialIndexNull(); // createCollection with required=false - $collNullCreate = 'spatial_idx_null_create_' . uniqid(); + $collNullCreate = uniqid('sp_idx'); try { $attributes = [new Document([ '$id' => ID::custom('loc'), @@ -847,7 +847,7 @@ public function testSpatialIndex(): void } // createIndex with required=false - $collNullIndex = 'spatial_idx_null_index_' . uniqid(); + $collNullIndex = uniqid('sp_idx_'); try { $database->createCollection($collNullIndex); $database->createAttribute($collNullIndex, 'loc', Database::VAR_POINT, 0, false); @@ -865,7 +865,7 @@ public function testSpatialIndex(): void $database->deleteCollection($collNullIndex); } - $collUpdateNull = 'spatial_idx_req'; + $collUpdateNull = uniqid('sp_idx'); try { $database->createCollection($collUpdateNull); @@ -889,7 +889,7 @@ public function testSpatialIndex(): void } - $collUpdateNull = 'spatial_idx_index_null_required_true'; + $collUpdateNull = uniqid('sp_idx'); try { $database->createCollection($collUpdateNull); @@ -2490,7 +2490,7 @@ public function testSpatialIndexSingleAttributeOnly(): void return; } - $collectionName = 'spatial_idx_single_attr_' . uniqid(); + $collectionName = uniqid("sp_idx"); try { $database->createCollection($collectionName); diff --git a/tests/unit/Validator/AuthorizationTest.php b/tests/unit/Validator/AuthorizationTest.php index 08c1e46f2..85ca1a233 100644 --- a/tests/unit/Validator/AuthorizationTest.php +++ b/tests/unit/Validator/AuthorizationTest.php @@ -119,4 +119,38 @@ public function testNestedSkips(): void $this->assertEquals(true, Authorization::$status); } + + public function testSetUserFromRoles(): void + { + $currentUserRole = Role::user("123"); + Authorization::setRole(Role::user("123")->toString()); + $this->assertEquals($currentUserRole->getIdentifier(), Authorization::getUser()); + + $roles = []; + $roles[] = Role::user("123"); + $roles[] = Role::user("123", 'verififed'); + $roles[] = Role::user("126", 'unverififed'); + $roles[] = Role::member("member123"); + $roles[] = Role::team("team1", ); + $roles[] = Role::team("team2", 'verified'); + $roles[] = Role::label("label"); + $roles[] = Role::guests(); + $roles[] = Role::any(); + $roles[] = Role::users(); + + foreach ($roles as $role) { + Authorization::setRole($role->toString()); + } + $expectedRole = Role::user("126", 'unverififed'); + $this->assertEquals($expectedRole->getIdentifier(), Authorization::getUser()); + + // unsetting non set user + Authorization::unsetRole(Role::user("123")->toString()); + $expectedRole = Role::user("126", 'unverififed'); + $this->assertEquals($expectedRole->getIdentifier(), Authorization::getUser()); + + // unsetting set user + Authorization::unsetRole(Role::user("126")->toString()); + $this->assertEquals(null, Authorization::getUser()); + } }