diff --git a/src/Database/Database.php b/src/Database/Database.php index 4b39ef231..0b0c2553c 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -2855,9 +2855,8 @@ public function updateDocument(string $collection, string $id, Document $documen } $time = DateTime::now(); - $document->setAttribute('$updatedAt', $time); - $old = Authorization::skip(fn () => $this->silent(fn () => $this->getDocument($collection, $id))); // Skip ensures user does not need read permission for this + $collection = $this->silent(fn () => $this->getCollection($collection)); $validator = new Authorization(self::PERMISSION_UPDATE); @@ -2865,7 +2864,19 @@ public function updateDocument(string $collection, string $id, Document $documen if ($collection->getId() !== self::METADATA) { $documentSecurity = $collection->getAttribute('documentSecurity', false); - if (!$validator->isValid([ + $skipPermission = true; + //compare if the document any changes + foreach ($document as $key=>$value) { + //skip the nested documents as they will be checked later in recursions. + if ($old->getAttribute($key) instanceof Document) { + continue; + } + if ($old->getAttribute($key) !== $value) { + $skipPermission = false; + break; + } + } + if (!$skipPermission && !$validator->isValid([ ...$collection->getUpdate(), ...($documentSecurity ? $old->getUpdate() : []) ])) { @@ -2873,6 +2884,8 @@ public function updateDocument(string $collection, string $id, Document $documen } } + $document->setAttribute('$updatedAt', $time); + // Check if document was updated after the request timestamp $oldUpdatedAt = new \DateTime($old->getUpdatedAt()); if (!is_null($this->timestamp) && $oldUpdatedAt > $this->timestamp) { diff --git a/tests/Database/Base.php b/tests/Database/Base.php index 403ca424b..56ca7b941 100644 --- a/tests/Database/Base.php +++ b/tests/Database/Base.php @@ -2993,6 +2993,28 @@ public function testWritePermissionsUpdateFailure(Document $document): Document Permission::update(Role::any()), Permission::delete(Role::any()), ], + 'string' => 'textđź“ť', + 'integer' => 6, + 'bigint' => 8589934592, // 2^33 + 'float' => 5.55, + 'boolean' => true, + 'colors' => ['pink', 'green', 'blue'], + ])); + + return $document; + } + + + /** + * @depends testCreateDocument + */ + public function testNoChangeUpdateDocumentWithoutPermission(Document $document): Document + { + Authorization::cleanRoles(); + Authorization::setRole(Role::any()->toString()); + + + $document = static::getDatabase()->createDocument('documents', new Document([ 'string' => 'textđź“ť', 'integer' => 5, 'bigint' => 8589934592, // 2^33 @@ -3000,6 +3022,25 @@ public function testWritePermissionsUpdateFailure(Document $document): Document 'boolean' => true, 'colors' => ['pink', 'green', 'blue'], ])); + Authorization::cleanRoles(); + //no changes in document + $documentToUpdate = new Document([ + '$id' => ID::custom($document->getId()), + 'string' => 'textđź“ť', + 'integer' => 5, + 'bigint' => 8589934592, // 2^33 + 'float' => 5.55, + 'boolean' => true, + 'colors' => ['pink', 'green', 'blue'], + '$collection' => 'documents', + ]); + $documentToUpdate->setAttribute('$createdAt', $document->getAttribute('$createdAt')); + $documentToUpdate->setAttribute('$updatedAt', $document->getAttribute('$updatedAt')); + $updatedDocument = static::getDatabase()->updateDocument('documents', $document->getId(), $documentToUpdate); + + + // Document should be updated without any problem and without any authorization exception as there is no change in document. + $this->assertEquals(true, $updatedDocument->getUpdatedAt() > $document->getUpdatedAt()); return $document; } @@ -10764,7 +10805,6 @@ public function testCollectionPermissionsUpdateWorks(array $data): array public function testCollectionPermissionsUpdateThrowsException(array $data): void { [$collection, $document] = $data; - Authorization::cleanRoles(); Authorization::setRole(Role::any()->toString()); @@ -10772,7 +10812,7 @@ public function testCollectionPermissionsUpdateThrowsException(array $data): voi $document = static::getDatabase()->updateDocument( $collection->getId(), $document->getId(), - $document->setAttribute('test', 'ipsum') + $document->setAttribute('test', 'lorem') ); }