1
0
Fork 0
mirror of synced 2024-09-09 14:21:24 +12:00

Merge branch 'master' of https://github.com/appwrite/appwrite into 1.4.x

This commit is contained in:
Torsten Dittmann 2023-05-13 17:18:33 +02:00
commit 0935912fef
20 changed files with 170 additions and 37 deletions

View file

@ -6,7 +6,7 @@ on:
jobs:
tests:
name: Unit & E2E
name: Release
runs-on: ubuntu-latest
steps:
@ -37,9 +37,9 @@ jobs:
with:
images: appwrite/appwrite
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- name: Build and push
uses: docker/build-push-action@v4

View file

@ -1,3 +1,9 @@
# Version 1.3.4
## Bugs
- Update migration to properly migrate bucket permissiosn [#5497](https://github.com/appwrite/appwrite/pull/5497)
# Version 1.3.3
## Bugs
@ -9,6 +15,7 @@
- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363)
- Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395)
- Fixed deleting keys, webhooks, platforms and domains after deleting project [#5395](https://github.com/appwrite/appwrite/pull/5395)
- Fixed empty team prefs returning as JSON object rather array [#5361](https://github.com/appwrite/appwrite/pull/5361)
# Version 1.3.1

View file

@ -1,5 +1,4 @@
> 准备好迎接狂风暴'云'了吗? 🌩 ☂️
> Appwrite Cloud即将到来!你能够通过https://appwrite.io/cloud了解更多的资讯, 注册即可领取试用额度哦
> 好消息Appwrite 云现已进入公开测试版!立即访问 cloud.appwrite.io 注册,体验无忧的托管服务。今天就加入我们的云端吧!☁️🎉
<br />
<p align="center">
@ -24,7 +23,7 @@
[English](README.md) | 简体中文
[**宣布带有数据库关系的 Appwrite 1.3!了解最新消息!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**Appwrite 云公开测试版!立即注册!**](https://cloud.appwrite.io)
Appwrite是一个基于Docker的端到端开发者平台其容器化的微服务库可应用于网页端移动端以及后端。Appwrite 通过视觉化界面简化了从零开始编写 API 的繁琐过程,在保证软件安全的前提下为开发者创造了一个高效的开发环境。
@ -67,7 +66,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
### Windows
@ -79,7 +78,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
#### PowerShell
@ -89,7 +88,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。

View file

@ -1,5 +1,4 @@
> It's going to get cloudy! 🌩 ☂️
> The Appwrite Cloud is coming soon! You can learn more about our upcoming hosted solution and signup for free credits at: https://appwrite.io/cloud
> Great news! Appwrite Cloud is now in public beta! Sign up at [cloud.appwrite.io](https://cloud.appwrite.io) for a hassle-free, hosted experience. Join us in the Cloud today! ☁️🎉
<br />
<p align="center">
@ -25,7 +24,7 @@
English | [简体中文](README-CN.md)
[**Announcing Appwrite 1.3 with Database Relationships! Learn what's new!**](https://dev.to/appwrite/join-celebrations-appwrite-13-ships-relationships-57fc)
[**Announcing Appwrite Cloud Public Beta! Sign up today!**](https://cloud.appwrite.io)
Appwrite is an end-to-end backend server for Web, Mobile, Native, or Backend apps packaged as a set of Docker<nobr> microservices. Appwrite abstracts the complexity and repetitiveness required to build a modern backend API from scratch and allows you to build secure apps faster.
@ -76,7 +75,7 @@ docker run -it --rm \
--volume /var/run/docker.sock:/var/run/docker.sock \
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
--entrypoint="install" \
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
### Windows
@ -88,7 +87,7 @@ docker run -it --rm ^
--volume //var/run/docker.sock:/var/run/docker.sock ^
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
--entrypoint="install" ^
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
#### PowerShell
@ -98,7 +97,7 @@ docker run -it --rm `
--volume /var/run/docker.sock:/var/run/docker.sock `
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
--entrypoint="install" `
appwrite/appwrite:1.3.3
appwrite/appwrite:1.3.4
```
Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation.

View file

@ -88,6 +88,11 @@ return [
'description' => 'The request cannot be fulfilled with the current protocol. Please check the value of the _APP_OPTIONS_FORCE_HTTPS environment variable.',
'code' => 500,
],
Exception::GENERAL_USAGE_DISABLED => [
'name' => Exception::GENERAL_USAGE_DISABLED,
'description' => 'Usage stats is not configured. Please check the value of the _APP_USAGE_STATS environment variable of your Appwrite server.',
'code' => 501,
],
/** User Errors */
Exception::USER_COUNT_EXCEEDED => [

View file

@ -152,7 +152,7 @@ return [
],
[
'name' => '_APP_LOGGING_PROVIDER',
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appsignal\', \'logowl\'',
'description' => 'This variable allows you to enable logging errors to 3rd party providers. This value is empty by default, to enable the logger set the value to one of \'sentry\', \'raygun\', \'appSignal\', \'logOwl\'',
'introduction' => '0.12.0',
'default' => '',
'required' => false,

View file

@ -3279,6 +3279,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$permissions = $document->getPermissions() ?? [];
}
$data = \array_merge($document->getArrayCopy(), $data); // Merge existing data with new data
$data['$collection'] = $collection->getId(); // Make sure user doesn't switch collectionID
$data['$createdAt'] = $document->getCreatedAt(); // Make sure user doesn't switch createdAt
$data['$id'] = $document->getId(); // Make sure user doesn't switch document unique ID
@ -3368,8 +3369,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum
$checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE);
$newDocument = new Document(\array_merge($document->getArrayCopy(), $data));
try {
$document = $dbForProject->withRequestTimestamp(
$requestTimestamp,
@ -3603,7 +3602,7 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
App::get('/v1/databases/usage')
->desc('Get usage stats for the database')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
@ -3721,7 +3720,7 @@ App::get('/v1/databases/usage')
App::get('/v1/databases/:databaseId/usage')
->desc('Get usage stats for the database')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')
@ -3831,7 +3830,7 @@ App::get('/v1/databases/:databaseId/usage')
App::get('/v1/databases/:databaseId/collections/:collectionId/usage')
->alias('/v1/database/:collectionId/usage', ['databaseId' => 'default'])
->desc('Get usage stats for a collection')
->groups(['api', 'database'])
->groups(['api', 'database', 'usage'])
->label('scope', 'collections.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'databases')

View file

@ -211,7 +211,7 @@ App::get('/v1/functions/:functionId')
App::get('/v1/functions/:functionId/usage')
->desc('Get Function Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')
@ -321,7 +321,7 @@ App::get('/v1/functions/:functionId/usage')
App::get('/v1/functions/usage')
->desc('Get Functions Usage')
->groups(['api', 'functions'])
->groups(['api', 'functions', 'usage'])
->label('scope', 'functions.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'functions')

View file

@ -245,7 +245,7 @@ App::get('/v1/projects/:projectId')
App::get('/v1/projects/:projectId/usage')
->desc('Get usage stats for a project')
->groups(['api', 'projects'])
->groups(['api', 'projects', 'usage'])
->label('scope', 'projects.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')

View file

@ -128,7 +128,7 @@ App::post('/v1/storage/buckets')
$bucket = $dbForProject->getDocument('buckets', $bucketId);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
$dbForProject->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes, permissions: $permissions ?? [], documentSecurity: $fileSecurity);
} catch (Duplicate) {
throw new Exception(Exception::STORAGE_BUCKET_ALREADY_EXISTS);
}
@ -274,6 +274,7 @@ App::put('/v1/storage/buckets/:bucketId')
->setAttribute('encryption', $encryption)
->setAttribute('compression', $compression)
->setAttribute('antivirus', $antivirus));
$dbForProject->updateCollection('bucket_' . $bucket->getInternalId(), $permissions, $fileSecurity);
$events
->setParam('bucketId', $bucket->getId())
@ -514,6 +515,7 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$mimeType = $deviceFiles->getFileMimeType($path); // Get mime-type before compression and encryption
$fileHash = $deviceFiles->getFileHash($path); // Get file hash before compression and encryption
$data = '';
// Compression
$algorithm = $bucket->getAttribute('compression', COMPRESSION_TYPE_NONE);
@ -547,7 +549,6 @@ App::post('/v1/storage/buckets/:bucketId/files')
}
$sizeActual = $deviceFiles->getFileSize($path);
$fileHash = $deviceFiles->getFileHash($path);
$openSSLVersion = null;
$openSSLCipher = null;
@ -1447,7 +1448,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
App::get('/v1/storage/usage')
->desc('Get usage stats for storage')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')
@ -1557,7 +1558,7 @@ App::get('/v1/storage/usage')
App::get('/v1/storage/:bucketId/usage')
->desc('Get usage stats for a storage bucket')
->groups(['api', 'storage'])
->groups(['api', 'storage', 'usage'])
->label('scope', 'files.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'storage')

View file

@ -1129,7 +1129,7 @@ App::delete('/v1/users/:userId')
App::get('/v1/users/usage')
->desc('Get usage stats for the users API')
->groups(['api', 'users'])
->groups(['api', 'users', 'usage'])
->label('scope', 'users.read')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'users')

View file

@ -552,3 +552,11 @@ App::shutdown()
->submit();
}
});
App::init()
->groups(['usage'])
->action(function () {
if (App::getEnv('_APP_USAGE_STATS', 'enabled') !== 'enabled') {
throw new Exception(Exception::GENERAL_USAGE_DISABLED);
}
});

View file

@ -101,7 +101,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return
const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
const APP_CACHE_BUSTER = 503;
const APP_VERSION_STABLE = '1.3.3';
const APP_VERSION_STABLE = '1.3.4';
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
const APP_DATABASE_ATTRIBUTE_IP = 'ip';

View file

@ -224,9 +224,9 @@ $cli
}
}
Console::log("Running \"docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes\"");
Console::log("Running \"docker compose up -d --remove-orphans --renew-anon-volumes\"");
$exit = Console::execute("${env} docker compose -f {$path}/docker-compose.yml up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
$exit = Console::execute("${env} docker compose --project-directory {$path} up -d --remove-orphans --renew-anon-volumes", '', $stdout, $stderr);
if ($exit !== 0) {
$message = 'Failed to install Appwrite dockers';

View file

@ -57,7 +57,7 @@ account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe')
### Learn more
You can use the following resources to learn more and get help
- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-flutter)
- 🚀 [Getting Started Tutorial](https://appwrite.io/docs/getting-started-for-web)
- 📜 [Appwrite Docs](https://appwrite.io/docs)
- 💬 [Discord Community](https://appwrite.io/discord)
- 🚂 [Appwrite Flutter Playground](https://github.com/appwrite/playground-for-flutter)
- 🚂 [Appwrite Web Playground](https://github.com/appwrite/playground-for-web)

View file

@ -51,6 +51,7 @@ class Exception extends \Exception
public const GENERAL_CURSOR_NOT_FOUND = 'general_cursor_not_found';
public const GENERAL_SERVER_ERROR = 'general_server_error';
public const GENERAL_PROTOCOL_UNSUPPORTED = 'general_protocol_unsupported';
public const GENERAL_USAGE_DISABLED = 'general_usage_disabled';
/** Users */
public const USER_COUNT_EXCEEDED = 'user_count_exceeded';

View file

@ -59,6 +59,7 @@ abstract class Migration
'1.3.1' => 'V18',
'1.3.2' => 'V18',
'1.3.3' => 'V18',
'1.3.4' => 'V18',
];
/**

View file

@ -182,6 +182,19 @@ class V18 extends Migration
*/
$document->setAttribute('options', $document->getAttribute('options', new \stdClass()));
break;
case 'buckets':
/**
* Set the bucket permission in the metadata table
*/
try {
$internalBucketId = "bucket_{$this->project->getInternalId()}";
$permissions = $document->getPermissions();
$fileSecurity = $document->getAttribute('fileSecurity', false);
$this->projectDB->updateCollection($internalBucketId, $permissions, $fileSecurity);
} catch (\Throwable $th) {
Console::warning($th->getMessage());
}
break;
}
return $document;

View file

@ -3968,4 +3968,105 @@ trait DatabasesBase
$this->assertArrayHasKey('fullName', $response['body']);
$this->assertArrayNotHasKey('libraries', $response['body']);
}
/**
* @depends testCreateDatabase
* @param array $data
* @return void
* @throws \Exception
*/
public function testUpdateWithExistingRelationships(array $data): void
{
$databaseId = $data['databaseId'];
$collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'collectionId' => ID::unique(),
'name' => 'Collection1',
'documentSecurity' => true,
'permissions' => [
Permission::create(Role::user($this->getUser()['$id'])),
Permission::read(Role::user($this->getUser()['$id'])),
],
]);
$collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'collectionId' => ID::unique(),
'name' => 'Collection2',
'documentSecurity' => true,
'permissions' => [
Permission::create(Role::user($this->getUser()['$id'])),
Permission::read(Role::user($this->getUser()['$id'])),
],
]);
$collection1 = $collection1['body']['$id'];
$collection2 = $collection2['body']['$id'];
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'name',
'size' => '49',
'required' => true,
]);
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2 . '/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'name',
'size' => '49',
'required' => true,
]);
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/relationship', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'relatedCollectionId' => $collection2,
'type' => Database::RELATION_ONE_TO_MANY,
'twoWay' => true,
'key' => 'collection2'
]);
sleep(1);
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'documentId' => ID::unique(),
'data' => [
'name' => 'Document 1',
'collection2' => [
[
'name' => 'Document 2',
],
],
],
]);
$update = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents/' . $document['body']['$id'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id']
], $this->getHeaders()), [
'data' => [
'name' => 'Document 1 Updated',
],
]);
$this->assertEquals(200, $update['headers']['status-code']);
}
}

View file

@ -57,8 +57,7 @@ trait StorageBase
$this->assertEquals('logo.png', $file['body']['name']);
$this->assertEquals('image/png', $file['body']['mimeType']);
$this->assertEquals(47218, $file['body']['sizeOriginal']);
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) != $file['body']['signature']); // should validate that the file is encrypted
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']);
/**
* Test for Large File above 20MB
* This should also validate the test for when Bucket encryption
@ -289,7 +288,7 @@ trait StorageBase
$this->assertEquals('logo.png', $file['body']['name']);
$this->assertEquals('image/png', $file['body']['mimeType']);
$this->assertEquals(47218, $file['body']['sizeOriginal']);
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) != $file['body']['signature']); // should validate that the file is encrypted
$this->assertTrue(md5_file(realpath(__DIR__ . '/../../../resources/logo.png')) == $file['body']['signature']);
return ['bucketId' => $bucketId];
}