From e4abc0e0dad7ca118d166c8a786c8cc8ffb76be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 14 Jan 2026 13:16:50 +0100 Subject: [PATCH 1/2] Add more file params (encryption, compression) --- src/Appwrite/Utopia/Response/Model/File.php | 24 ++++ .../Storage/StorageCustomClientTest.php | 113 ++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/File.php b/src/Appwrite/Utopia/Response/Model/File.php index 11a128abcc..c4e36286ea 100644 --- a/src/Appwrite/Utopia/Response/Model/File.php +++ b/src/Appwrite/Utopia/Response/Model/File.php @@ -4,6 +4,8 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use Utopia\Database\Document; +use Utopia\Storage\Compression\Compression; class File extends Model { @@ -77,6 +79,18 @@ class File extends Model 'default' => 0, 'example' => 17890, ]) + ->addRule('encryption', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether file contents are encrypted at rest.', + 'default' => false, + 'example' => true, + ]) + ->addRule('compression', [ + 'type' => self::TYPE_STRING, + 'description' => 'Compression algorithm used for the file. Will be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd).', + 'default' => '', + 'example' => 'gzip' + ]) ; } @@ -99,4 +113,14 @@ class File extends Model { return Response::MODEL_FILE; } + + public function filter(Document $document): Document + { + $document->setAttribute('compression', $document->getAttribute('algorithm', '')); + + $encryption = !empty($document->getAttribute('openSSLCipher', '')); + $document->setAttribute('encryption', $encryption); + + return $document; + } } diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index ec9f0d0cc7..4d1a0f44c8 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -1447,4 +1447,117 @@ class StorageCustomClientTest extends Scope ]); $this->assertEquals(204, $response['headers']['status-code']); } + + public function testFileEncryptionAndCompression(): void + { + // Create bucket + $bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'bucketId' => ID::unique(), + 'name' => 'Test Bucket', + 'permissions' => [ + Permission::read(Role::any()) + ], + 'encryption' => true, + 'compression' => 'gzip' + ]); + $this->assertSame(201, $bucket['headers']['status-code']); + + // Create file + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', [ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'transformations.png'), + ]); + $this->assertSame(201, $file['headers']['status-code']); + $this->assertSame('gzip', $file['body']['compression']); + $this->assertSame(true, $file['body']['encryption']); + + // Get file + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'], [ + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertSame(200, $file['headers']['status-code']); + $this->assertSame('gzip', $file['body']['compression']); + $this->assertSame(true, $file['body']['encryption']); + + // List files + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files', [ + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertSame(200, $files['headers']['status-code']); + $this->assertSame(1, $files['body']['total']); + $this->assertSame('gzip', $files['body']['files'][0]['compression']); + $this->assertSame(true, $files['body']['files'][0]['encryption']); + + // Update the bucket + $bucket = $this->client->call(Client::METHOD_PUT, '/storage/buckets/' . $bucket['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'name' => 'Test Bucket', + 'encryption' => false, + 'compression' => 'none' + ]); + + // Existing fie did not update + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'], [ + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertSame(200, $file['headers']['status-code']); + $this->assertSame('gzip', $file['body']['compression']); + $this->assertSame(true, $file['body']['encryption']); + + // Create 2nd file + $file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', [ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'fileId' => ID::unique(), + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'transformations.png'), + ]); + $this->assertSame(201, $file['headers']['status-code']); + $this->assertSame('none', $file['body']['compression']); + $this->assertSame(false, $file['body']['encryption']); + + // Get file + $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'], [ + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertSame(200, $file['headers']['status-code']); + $this->assertSame('none', $file['body']['compression']); + $this->assertSame(false, $file['body']['encryption']); + + // List files + $files = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files', [ + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertSame(200, $files['headers']['status-code']); + $this->assertSame(2, $files['body']['total']); + $this->assertSame('none', $files['body']['files'][1]['compression']); + $this->assertSame(false, $files['body']['files'][1]['encryption']); + $this->assertSame('gzip', $files['body']['files'][0]['compression']); + $this->assertSame(true, $files['body']['files'][0]['encryption']); + + // Delete the bucket + $response = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucket['body']['$id'], [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + $this->assertEquals(204, $response['headers']['status-code']); + } } From 7b10fe13714f7ba9a2acc06115e4b73985deb2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 14 Jan 2026 14:17:12 +0100 Subject: [PATCH 2/2] typo fix --- tests/e2e/Services/Storage/StorageCustomClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Storage/StorageCustomClientTest.php b/tests/e2e/Services/Storage/StorageCustomClientTest.php index 4d1a0f44c8..0337856779 100644 --- a/tests/e2e/Services/Storage/StorageCustomClientTest.php +++ b/tests/e2e/Services/Storage/StorageCustomClientTest.php @@ -1509,7 +1509,7 @@ class StorageCustomClientTest extends Scope 'compression' => 'none' ]); - // Existing fie did not update + // Existing file did not update $file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucket['body']['$id'] . '/files/' . $file['body']['$id'], [ 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'],