Merge branch 'master' into fix-preview-when-no-extension
This commit is contained in:
commit
43f60739d7
12
.gitpod.yml
12
.gitpod.yml
|
@ -5,14 +5,20 @@ tasks:
|
|||
- init: docker-compose pull &&
|
||||
docker-compose build &&
|
||||
docker run --rm --interactive --tty --volume $PWD:/app composer update --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist
|
||||
command: |
|
||||
docker-compose up -d
|
||||
|
||||
ports:
|
||||
- port: 8080
|
||||
onOpen: ignore
|
||||
onOpen: open-preview
|
||||
visibility: public
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- ms-azuretools.vscode-docker
|
||||
|
||||
github:
|
||||
# https://www.gitpod.io/docs/prebuilds#github-specific-configuration
|
||||
prebuilds:
|
||||
# enable for pull requests coming from forks (defaults to false)
|
||||
pullRequestsFromForks: true
|
||||
# add a check to pull requests (defaults to true)
|
||||
addCheck: false
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
# Version 0.13.3
|
||||
## Bugs
|
||||
- Fixed search for terms that inlcude `@` characters
|
||||
- Fixed Bucket permissions
|
||||
- Fixed file upload error in UI
|
||||
- Fixed input field for float attributes in UI
|
||||
- Fixed `appwrite-executor` restart behavior in docker-compose.yml
|
||||
|
||||
# Version 0.13.2
|
||||
## Bugs
|
||||
- Fixed global issue with write permissions
|
||||
|
|
|
@ -59,7 +59,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
@ -71,7 +71,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
@ -81,7 +81,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
|
|
@ -53,7 +53,7 @@ Table of Contents:
|
|||
|
||||
Appwrite backend server is designed to run in a container environment. Running your server is as easy as running one command from your terminal. You can either run Appwrite on your localhost using docker-compose or on any other container orchestration tool like Kubernetes, Docker Swarm, or Rancher.
|
||||
|
||||
The easiest way to start running your Appwrite server is by running our docker-compose file. Before running the installation command make sure you have [Docker](https://www.docker.com/products/docker-desktop) installed on your machine:
|
||||
The easiest way to start running your Appwrite server is by running our docker-compose file. Before running the installation command, make sure you have [Docker](https://www.docker.com/products/docker-desktop) installed on your machine:
|
||||
|
||||
### Unix
|
||||
|
||||
|
@ -62,7 +62,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
@ -74,7 +74,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
@ -84,7 +84,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:0.13.2
|
||||
appwrite/appwrite:0.13.3
|
||||
```
|
||||
|
||||
Once the Docker installation completes, 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 installation completes.
|
||||
|
|
|
@ -1687,7 +1687,7 @@ App::get('/v1/database/collections/:collectionId/documents')
|
|||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_DOCUMENT_LIST)
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/database#createCollection).')
|
||||
->param('queries', [], new ArrayList(new Text(0), 100), 'Array of query strings.', true)
|
||||
->param('queries', [], new ArrayList(new Text(0), 100), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/database#querying-documents).', true)
|
||||
->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true)
|
||||
->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Offset value. The default value is 0. Use this value to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
|
||||
->param('cursor', '', new UID(), 'ID of the document used as the starting point for the query, excluding the document itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true)
|
||||
|
@ -1949,7 +1949,7 @@ App::patch('/v1/database/collections/:collectionId/documents/:documentId')
|
|||
->label('sdk.response.model', Response::MODEL_DOCUMENT)
|
||||
->param('collectionId', null, new UID(), 'Collection ID.')
|
||||
->param('documentId', null, new UID(), 'Document ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.')
|
||||
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default inherits the existing read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default inherits the existing write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
|
||||
->inject('response')
|
||||
|
|
|
@ -715,7 +715,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -738,9 +738,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
|
||||
if (!empty($cursor)) {
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$cursorFile = Authorization::skip(function () use ($dbForProject, $bucket, $cursor) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $cursor);
|
||||
});
|
||||
$cursorFile = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $cursor));
|
||||
} else {
|
||||
$cursorFile = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $cursor);
|
||||
}
|
||||
|
@ -757,9 +755,7 @@ App::get('/v1/storage/buckets/:bucketId/files')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$files = Authorization::skip(function () use ($dbForProject, $bucket, $queries, $limit, $offset, $cursor, $cursorDirection, $orderType) {
|
||||
return $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
});
|
||||
$files = Authorization::skip(fn () => $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection));
|
||||
} else {
|
||||
$files = $dbForProject->find('bucket_' . $bucket->getInternalId(), $queries, $limit, $offset, [], [$orderType], $cursorFile ?? null, $cursorDirection);
|
||||
}
|
||||
|
@ -799,7 +795,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
/** @var Appwrite\Stats\Stats $usage */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -815,9 +811,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $bucket, $fileId) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -825,10 +819,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
if ($file->isEmpty() || $file->getAttribute('bucketId') !== $bucketId) {
|
||||
throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$usage
|
||||
->setParam('storage.files.read', 1)
|
||||
->setParam('bucketId', $bucketId)
|
||||
;
|
||||
|
||||
$response->dynamic($file, Response::MODEL_FILE);
|
||||
});
|
||||
|
||||
|
@ -879,7 +875,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
throw new Exception('Imagick extension is missing', 500, Exception::GENERAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -907,9 +903,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview')
|
|||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(function () use ($dbForProject, $bucket, $fileId) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -1048,7 +1042,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
/** @var Utopia\Storage\Device $deviceFiles */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -1064,9 +1058,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $fileId, $bucket) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -1193,7 +1185,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
/** @var Utopia\Storage\Device $deviceFiles */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -1209,9 +1201,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $fileId, $bucket) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -1356,7 +1346,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
/** @var Appwrite\Event\Event $events */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
$read = (is_null($read) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $read ?? []; // By default set read permissions for user
|
||||
$write = (is_null($write) && !$user->isEmpty()) ? ['user:' . $user->getId()] : $write ?? [];
|
||||
|
||||
|
@ -1390,9 +1380,7 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $fileId, $bucket) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -1401,18 +1389,15 @@ App::put('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
throw new Exception('File not found', 404, Exception::STORAGE_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
;
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $fileId, $bucket, $file, $read, $write) {
|
||||
return $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file));
|
||||
} else {
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file
|
||||
->setAttribute('$read', $read)
|
||||
->setAttribute('$write', $write)
|
||||
);
|
||||
$file = $dbForProject->updateDocument('bucket_' . $bucket->getInternalId(), $fileId, $file);
|
||||
}
|
||||
|
||||
$events->setParam('bucket', $bucket->getArrayCopy());
|
||||
|
@ -1462,7 +1447,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
/** @var Utopia\Storage\Device $deviceFiles */
|
||||
/** @var string $mode */
|
||||
|
||||
$bucket = $dbForProject->getDocument('buckets', $bucketId);
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty()
|
||||
|| (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
|
@ -1478,9 +1463,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$file = Authorization::skip(function () use ($dbForProject, $fileId, $bucket) {
|
||||
return $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
@ -1506,9 +1489,7 @@ App::delete('/v1/storage/buckets/:bucketId/files/:fileId')
|
|||
$deviceLocal->delete($cacheDir, true);
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
$deleted = Authorization::skip(function () use ($dbForProject, $fileId, $bucket) {
|
||||
return $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
});
|
||||
$deleted = Authorization::skip(fn () => $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
$deleted = $dbForProject->deleteDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ const APP_LIMIT_USERS = 10000;
|
|||
const APP_LIMIT_ANTIVIRUS = 20000000; //20MB
|
||||
const APP_LIMIT_ENCRYPTION = 20000000; //20MB
|
||||
const APP_LIMIT_COMPRESSION = 20000000; //20MB
|
||||
const APP_CACHE_BUSTER = 302;
|
||||
const APP_VERSION_STABLE = '0.13.2';
|
||||
const APP_CACHE_BUSTER = 303;
|
||||
const APP_VERSION_STABLE = '0.13.3';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
|
|
|
@ -762,21 +762,21 @@ $logs = $this->getParam('logs', null);
|
|||
<div class="row responsive thin">
|
||||
<div class="col span-6 margin-bottom-small">
|
||||
<label for="float-min">Min</label>
|
||||
<input id="float-min" type="number" class="full-width" name="min" step="0.01" autocomplete="off" data-cast-to="float" />
|
||||
<input id="float-min" type="number" class="full-width" name="min" step="any" autocomplete="off" data-cast-to="float" />
|
||||
</div>
|
||||
<div class="col span-6 margin-bottom-small">
|
||||
<label for="float-max">Max</label>
|
||||
<input id="float-max" type="number" class="full-width" name="max" step="0.01" autocomplete="off" data-cast-to="float" />
|
||||
<input id="float-max" type="number" class="full-width" name="max" step="any" autocomplete="off" data-cast-to="float" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="float-default">Default Value</label>
|
||||
|
||||
<template x-if="!(array || required)">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float">
|
||||
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float">
|
||||
</template>
|
||||
<template x-if="(array || required)">
|
||||
<input name="xdefault" type="number" step="0.01" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
|
||||
<input name="xdefault" type="number" step="any" class="margin-bottom-large" autocomplete="off" data-cast-to="float" disabled>
|
||||
</template>
|
||||
|
||||
<footer>
|
||||
|
|
|
@ -110,7 +110,7 @@ $logs = $this->getParam('logs', null);
|
|||
<template x-if="attr.type === 'double'">
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
step="any"
|
||||
:placeholder="attr.default"
|
||||
:name="attr.key"
|
||||
:required="attr.required"
|
||||
|
@ -203,7 +203,7 @@ $logs = $this->getParam('logs', null);
|
|||
<template x-if="attr.type === 'double'">
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
step="any"
|
||||
:placeholder="attr.default"
|
||||
:name="attr.key"
|
||||
:required="attr.required"
|
||||
|
|
|
@ -173,6 +173,7 @@ services:
|
|||
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>
|
||||
entrypoint: executor
|
||||
container_name: appwrite-executor
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
networks:
|
||||
appwrite:
|
||||
|
@ -561,4 +562,4 @@ volumes:
|
|||
appwrite-functions:
|
||||
appwrite-influxdb:
|
||||
appwrite-config:
|
||||
appwrite-executor:
|
||||
appwrite-executor:
|
||||
|
|
37
composer.lock
generated
37
composer.lock
generated
|
@ -236,16 +236,16 @@
|
|||
},
|
||||
{
|
||||
"name": "chillerlan/php-settings-container",
|
||||
"version": "2.1.2",
|
||||
"version": "2.1.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/chillerlan/php-settings-container.git",
|
||||
"reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5"
|
||||
"reference": "125dd573b45ffc7cabecf385986a356ba2c6f602"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/ec834493a88682dd69652a1eeaf462789ed0c5f5",
|
||||
"reference": "ec834493a88682dd69652a1eeaf462789ed0c5f5",
|
||||
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/125dd573b45ffc7cabecf385986a356ba2c6f602",
|
||||
"reference": "125dd573b45ffc7cabecf385986a356ba2c6f602",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -253,7 +253,7 @@
|
|||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phan/phan": "^4.0",
|
||||
"phan/phan": "^5.3",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"type": "library",
|
||||
|
@ -278,6 +278,7 @@
|
|||
"keywords": [
|
||||
"PHP7",
|
||||
"Settings",
|
||||
"configuration",
|
||||
"container",
|
||||
"helper"
|
||||
],
|
||||
|
@ -295,7 +296,7 @@
|
|||
"type": "ko_fi"
|
||||
}
|
||||
],
|
||||
"time": "2021-09-06T15:17:01+00:00"
|
||||
"time": "2022-03-09T13:18:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "colinmollenhour/credis",
|
||||
|
@ -2129,16 +2130,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.15.3",
|
||||
"version": "0.15.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "726e3b04fb1f1b3b654bc1d3114deaf1481cb008"
|
||||
"reference": "166365d9c39c4d70b1267af4562f4327e8930f79"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/726e3b04fb1f1b3b654bc1d3114deaf1481cb008",
|
||||
"reference": "726e3b04fb1f1b3b654bc1d3114deaf1481cb008",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/166365d9c39c4d70b1267af4562f4327e8930f79",
|
||||
"reference": "166365d9c39c4d70b1267af4562f4327e8930f79",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2186,9 +2187,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.15.3"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.15.4"
|
||||
},
|
||||
"time": "2022-03-07T11:59:51+00:00"
|
||||
"time": "2022-03-15T17:20:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
@ -3191,16 +3192,16 @@
|
|||
},
|
||||
{
|
||||
"name": "composer/semver",
|
||||
"version": "3.2.9",
|
||||
"version": "3.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/composer/semver.git",
|
||||
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649"
|
||||
"reference": "f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/a951f614bd64dcd26137bc9b7b2637ddcfc57649",
|
||||
"reference": "a951f614bd64dcd26137bc9b7b2637ddcfc57649",
|
||||
"url": "https://api.github.com/repos/composer/semver/zipball/f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b",
|
||||
"reference": "f79c90ad4e9b41ac4dfc5d77bf398cf61fbd718b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3252,7 +3253,7 @@
|
|||
"support": {
|
||||
"irc": "irc://irc.freenode.org/composer",
|
||||
"issues": "https://github.com/composer/semver/issues",
|
||||
"source": "https://github.com/composer/semver/tree/3.2.9"
|
||||
"source": "https://github.com/composer/semver/tree/3.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3268,7 +3269,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-04T13:58:43+00:00"
|
||||
"time": "2022-03-15T08:35:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "composer/xdebug-handler",
|
||||
|
|
|
@ -1 +1 @@
|
|||
Delete a document by its unique ID. This endpoint deletes only the parent documents, its attributes and relations to other documents. Child documents **will not** be deleted.
|
||||
Delete a document by its unique ID.
|
|
@ -1,6 +1,6 @@
|
|||
The Database service allows you to create structured collections of documents, query and filter lists of documents, and manage an advanced set of read and write access permissions.
|
||||
|
||||
All the data in the database service is stored in structured JSON documents. The Appwrite database service also allows you to nest child documents in parent documents and use deep filters to both search and query your data.
|
||||
All the data in the database service is stored in structured JSON documents.
|
||||
|
||||
Each database document structure in your project is defined using the Appwrite [collection attributes](/docs/database#attributes). The collection attributes help you ensure all your user-submitted data is validated and stored according to the collection structure.
|
||||
|
||||
|
|
2
public/dist/scripts/app-all.js
vendored
2
public/dist/scripts/app-all.js
vendored
|
@ -3672,7 +3672,7 @@ if(!match){return fail}
|
|||
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
|
||||
return(date.getTime()/1000)}
|
||||
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){if(value&&Array.isArray(value)&&to!=='array'){value=value.map(element=>cast(element,to));return value;}
|
||||
switch(to){case'int':case'integer':value=parseInt(value);break;case'float':value=parseFloat(parseFloat(value).toFixed(2));break;case'numeric':value=Number(value);break;case'float':value=parseFloat(value);break;case'string':value=value.toString();if(value.length===0){value=null;}
|
||||
switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'float':value=parseFloat(value);break;case'string':value=value.toString();if(value.length===0){value=null;}
|
||||
break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
|
||||
return value;}
|
||||
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if(name.startsWith('[')){let splitName=name.split('.');if(splitName.length>1&&splitName[0].endsWith(']')){name=splitName[splitName.length-1];}}
|
||||
|
|
2
public/dist/scripts/app.js
vendored
2
public/dist/scripts/app.js
vendored
|
@ -622,7 +622,7 @@ if(!match){return fail}
|
|||
for(i=0,len=match.length;i<len;i++){if(!process(match[i])){return fail}}
|
||||
return(date.getTime()/1000)}
|
||||
return{format:format,strtotime:strtotime}}(),true);})(window);(function(window){"use strict";window.ls.container.set('env',function(){return APP_ENV;},true);})(window);(function(window){"use strict";window.ls.container.set('form',function(){function cast(value,to){if(value&&Array.isArray(value)&&to!=='array'){value=value.map(element=>cast(element,to));return value;}
|
||||
switch(to){case'int':case'integer':value=parseInt(value);break;case'float':value=parseFloat(parseFloat(value).toFixed(2));break;case'numeric':value=Number(value);break;case'float':value=parseFloat(value);break;case'string':value=value.toString();if(value.length===0){value=null;}
|
||||
switch(to){case'int':case'integer':value=parseInt(value);break;case'numeric':value=Number(value);break;case'float':value=parseFloat(value);break;case'string':value=value.toString();if(value.length===0){value=null;}
|
||||
break;case'json':value=(value)?JSON.parse(value):[];break;case'array':value=(value&&value.constructor&&value.constructor===Array)?value:[value];break;case'array-empty':value=[];break;case'bool':case'boolean':value=(value==='false')?false:value;value=!!value;break;}
|
||||
return value;}
|
||||
function toJson(element,json){json=json||{};let name=element.getAttribute('name');let type=element.getAttribute('type');let castTo=element.getAttribute('data-cast-to');let ref=json;if(name&&'FORM'!==element.tagName){if(name.startsWith('[')){let splitName=name.split('.');if(splitName.length>1&&splitName[0].endsWith(']')){name=splitName[splitName.length-1];}}
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
case 'integer':
|
||||
value = parseInt(value);
|
||||
break;
|
||||
case 'float':
|
||||
value = parseFloat(parseFloat(value).toFixed(2));
|
||||
break;
|
||||
case 'numeric':
|
||||
value = Number(value);
|
||||
break;
|
||||
|
|
|
@ -38,6 +38,7 @@ abstract class Migration
|
|||
'0.13.0' => 'V12',
|
||||
'0.13.1' => 'V12',
|
||||
'0.13.2' => 'V12',
|
||||
'0.13.3' => 'V12',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeBoolean extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'isEnabled',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'boolean',
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeEmail extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'userEmail',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeEnum extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'status',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('elements', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Array of elements in enumerated type.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeFloat extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'percentageCompleted',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'double',
|
||||
])
|
||||
->addRule('min', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Minimum value to enforce for new documents.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeIP extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'ipAddress',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeInteger extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'count',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'integer',
|
||||
])
|
||||
->addRule('min', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Minimum value to enforce for new documents.',
|
||||
|
|
|
@ -12,6 +12,18 @@ class AttributeURL extends Attribute
|
|||
parent::__construct();
|
||||
|
||||
$this
|
||||
->addRule('key', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute Key.',
|
||||
'default' => '',
|
||||
'example' => 'githubUrl',
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Attribute type.',
|
||||
'default' => '',
|
||||
'example' => 'string',
|
||||
])
|
||||
->addRule('format', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'String format.',
|
||||
|
|
|
@ -65,7 +65,7 @@ trait StorageBase
|
|||
]);
|
||||
$this->assertEquals(201, $bucket2['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucket2['body']['$id']);
|
||||
|
||||
|
||||
/**
|
||||
* Chunked Upload
|
||||
*/
|
||||
|
@ -99,7 +99,7 @@ trait StorageBase
|
|||
$id = $largeFile['body']['$id'];
|
||||
}
|
||||
@fclose($handle);
|
||||
|
||||
|
||||
$this->assertEquals(201, $largeFile['headers']['status-code']);
|
||||
$this->assertNotEmpty($largeFile['body']['$id']);
|
||||
$this->assertIsInt($largeFile['body']['dateCreated']);
|
||||
|
@ -107,7 +107,7 @@ trait StorageBase
|
|||
$this->assertEquals('video/mp4', $largeFile['body']['mimeType']);
|
||||
$this->assertEquals($totalSize, $largeFile['body']['sizeOriginal']);
|
||||
$this->assertEquals(md5_file(realpath(__DIR__ . '/../../../resources/disk-a/large-file.mp4')), $largeFile['body']['signature']); // should validate that the file is not encrypted
|
||||
|
||||
|
||||
/**
|
||||
* Failure
|
||||
* Test for Chunk above 5MB
|
||||
|
@ -134,9 +134,9 @@ trait StorageBase
|
|||
'write' => ['role:all'],
|
||||
]);
|
||||
@fclose($handle);
|
||||
|
||||
|
||||
$this->assertEquals(413, $res['headers']['status-code']);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test for FAILURE unknown Bucket
|
||||
|
|
|
@ -17,6 +17,96 @@ class StorageCustomClientTest extends Scope
|
|||
use ProjectCustom;
|
||||
use SideClient;
|
||||
|
||||
public function testBucketPermissions(): void
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$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' => 'unique()',
|
||||
'name' => 'Test Bucket',
|
||||
'permission' => 'bucket',
|
||||
'read' => ['role:all'],
|
||||
'write' => ['role:member'],
|
||||
]);
|
||||
|
||||
$bucketId = $bucket['body']['$id'];
|
||||
$this->assertEquals(201, $bucket['headers']['status-code']);
|
||||
$this->assertNotEmpty($bucketId);
|
||||
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'. $bucketId . '/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'fileId' => 'unique()',
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'),
|
||||
]);
|
||||
|
||||
$fileId = $file['body']['$id'];
|
||||
$this->assertEquals($file['headers']['status-code'], 201);
|
||||
$this->assertNotEmpty($fileId);
|
||||
$this->assertIsInt($file['body']['dateCreated']);
|
||||
$this->assertEquals('permissions.png', $file['body']['name']);
|
||||
$this->assertEquals('image/png', $file['body']['mimeType']);
|
||||
$this->assertEquals(47218, $file['body']['sizeOriginal']);
|
||||
|
||||
$file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
|
||||
$file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
|
||||
$file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/download', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
|
||||
$file = $this->client->call(Client::METHOD_GET, '/storage/buckets/' . $bucketId . '/files/' . $fileId . '/view', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/'. $bucketId . '/files', [
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'fileId' => 'unique()',
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'permissions.png'),
|
||||
]);
|
||||
|
||||
$this->assertEquals($file['headers']['status-code'], 401);
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$file = $this->client->call(Client::METHOD_DELETE, '/storage/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(204, $file['headers']['status-code']);
|
||||
$this->assertEmpty($file['body']);
|
||||
}
|
||||
|
||||
public function testCreateFileDefaultPermissions(): array
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -121,6 +121,18 @@ trait UsersBase
|
|||
$this->assertCount(1, $response['body']['users']);
|
||||
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'cristiano.ronaldo@manchester-united.co.uk'
|
||||
]);
|
||||
$this->assertEquals($response['headers']['status-code'], 200);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['users']);
|
||||
$this->assertCount(1, $response['body']['users']);
|
||||
$this->assertEquals($response['body']['users'][0]['$id'], $data['userId']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
|
|
Loading…
Reference in a new issue