mirror of
https://github.com/appwrite/appwrite
synced 2026-05-21 16:08:22 +00:00
Merge branch 'main' into update-sdks-devkeys
This commit is contained in:
commit
760f26e044
20 changed files with 197 additions and 60 deletions
|
|
@ -72,7 +72,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
|
@ -84,7 +84,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
|
@ -94,7 +94,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。
|
||||
|
|
|
|||
|
|
@ -78,7 +78,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
|
@ -90,7 +90,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
|
@ -100,7 +100,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.7.2
|
||||
appwrite/appwrite:1.7.3
|
||||
```
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1352,6 +1352,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
|||
if ($encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string attributes are not available on your plan. Please upgrade to create encrypted string attributes.');
|
||||
}
|
||||
if ($encrypt && $size < APP_DATABASE_ENCRYPT_SIZE_MIN) {
|
||||
throw new Exception(
|
||||
Exception::GENERAL_BAD_REQUEST,
|
||||
"Size too small. Encrypted strings require a minimum size of " . APP_DATABASE_ENCRYPT_SIZE_MIN . " characters."
|
||||
);
|
||||
}
|
||||
// Ensure attribute default is within required size
|
||||
$validator = new Text($size, 0);
|
||||
if (!is_null($default) && !$validator->isValid($default)) {
|
||||
|
|
@ -1372,7 +1378,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
|||
'array' => $array,
|
||||
'filters' => $filters,
|
||||
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
|
||||
|
||||
$attribute->setAttribute('encrypt', $encrypt);
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||
->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING);
|
||||
|
|
@ -2051,6 +2057,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes')
|
|||
throw new Exception(Exception::GENERAL_QUERY_INVALID);
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($attribute->getAttribute('type') === Database::VAR_STRING) {
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'attributes' => $attributes,
|
||||
'total' => $total,
|
||||
|
|
@ -2115,7 +2128,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
|
|||
$type = $attribute->getAttribute('type');
|
||||
$format = $attribute->getAttribute('format');
|
||||
$options = $attribute->getAttribute('options', []);
|
||||
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
foreach ($options as $key => $option) {
|
||||
$attribute->setAttribute($key, $option);
|
||||
}
|
||||
|
|
@ -2135,7 +2148,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key')
|
|||
},
|
||||
default => Response::MODEL_ATTRIBUTE,
|
||||
};
|
||||
|
||||
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
|
||||
$response->dynamic($attribute, $model);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours
|
|||
const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours
|
||||
const APP_CACHE_BUSTER = 4319;
|
||||
const APP_VERSION_STABLE = '1.7.2';
|
||||
const APP_VERSION_STABLE = '1.7.3';
|
||||
const APP_DATABASE_ATTRIBUTE_EMAIL = 'email';
|
||||
const APP_DATABASE_ATTRIBUTE_ENUM = 'enum';
|
||||
const APP_DATABASE_ATTRIBUTE_IP = 'ip';
|
||||
|
|
@ -51,6 +51,7 @@ const APP_DATABASE_TIMEOUT_MILLISECONDS_API = 15 * 1000; // 15 seconds
|
|||
const APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER = 300 * 1000; // 5 minutes
|
||||
const APP_DATABASE_TIMEOUT_MILLISECONDS_TASK = 300 * 1000; // 5 minutes
|
||||
const APP_DATABASE_QUERY_MAX_VALUES = 500;
|
||||
const APP_DATABASE_ENCRYPT_SIZE_MIN = 150;
|
||||
const APP_STORAGE_UPLOADS = '/storage/uploads';
|
||||
const APP_STORAGE_SITES = '/storage/sites';
|
||||
const APP_STORAGE_FUNCTIONS = '/storage/functions';
|
||||
|
|
|
|||
|
|
@ -77,12 +77,21 @@ Database::addFilter(
|
|||
]);
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
|
||||
$options = $attribute->getAttribute('options');
|
||||
foreach ($options as $key => $value) {
|
||||
$attribute->setAttribute($key, $value);
|
||||
}
|
||||
$attribute->removeAttribute('options');
|
||||
$attributeType = $attribute->getAttribute('type');
|
||||
|
||||
switch ($attributeType) {
|
||||
case Database::VAR_RELATIONSHIP:
|
||||
$options = $attribute->getAttribute('options');
|
||||
foreach ($options as $key => $value) {
|
||||
$attribute->setAttribute($key, $value);
|
||||
}
|
||||
$attribute->removeAttribute('options');
|
||||
break;
|
||||
|
||||
case Database::VAR_STRING:
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ use Utopia\Storage\Device\S3;
|
|||
use Utopia\Storage\Device\Wasabi;
|
||||
use Utopia\Storage\Storage;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Telemetry\Adapter as Telemetry;
|
||||
use Utopia\Telemetry\Adapter\None as NoTelemetry;
|
||||
use Utopia\Validator\Hostname;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
|
@ -487,10 +486,9 @@ App::setResource('timelimit', function (\Redis $redis) {
|
|||
};
|
||||
}, ['redis']);
|
||||
|
||||
App::setResource('deviceForLocal', function (Telemetry $telemetry) {
|
||||
App::setResource('deviceForLocal', function () {
|
||||
return new Local();
|
||||
}, ['telemetry']);
|
||||
|
||||
});
|
||||
App::setResource('deviceForFiles', function ($project) {
|
||||
return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId());
|
||||
}, ['project']);
|
||||
|
|
@ -534,7 +532,8 @@ function getDevice(string $root, string $connection = ''): Device
|
|||
switch ($device) {
|
||||
case Storage::DEVICE_S3:
|
||||
if (!empty($url)) {
|
||||
return new S3($root, $accessKey, $accessSecret, $url, $region, $acl);
|
||||
$bucketRoot = (!empty($bucket) ? $bucket . '/' : '') . \ltrim($root, '/');
|
||||
return new S3($bucketRoot, $accessKey, $accessSecret, $url, $region, $acl);
|
||||
} else {
|
||||
return new AWS($root, $accessKey, $accessSecret, $bucket, $region, $acl);
|
||||
}
|
||||
|
|
@ -566,7 +565,8 @@ function getDevice(string $root, string $connection = ''): Device
|
|||
$s3Acl = 'private';
|
||||
$s3EndpointUrl = System::getEnv('_APP_STORAGE_S3_ENDPOINT', '');
|
||||
if (!empty($s3EndpointUrl)) {
|
||||
return new S3($root, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl);
|
||||
$bucketRoot = (!empty($s3Bucket) ? $s3Bucket . '/' : '') . \ltrim($root, '/');
|
||||
return new S3($bucketRoot, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl);
|
||||
} else {
|
||||
return new AWS($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ $image = $this->getParam('image', '');
|
|||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: <?php echo $organization; ?>/console:6.0.8
|
||||
image: <?php echo $organization; ?>/console:6.0.11
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ Server::setResource('timelimit', function (\Redis $redis) {
|
|||
|
||||
Server::setResource('log', fn () => new Log());
|
||||
|
||||
|
||||
Server::setResource('publisher', function (Group $pools) {
|
||||
return new BrokerPool(publisher: $pools->get('publisher'));
|
||||
}, ['pools']);
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ services:
|
|||
appwrite-console:
|
||||
<<: *x-logging
|
||||
container_name: appwrite-console
|
||||
image: appwrite/console:6.0.8
|
||||
image: appwrite/console:6.0.11
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
# Change Log
|
||||
|
||||
## 16.0.1
|
||||
## 16.1.1
|
||||
|
||||
* Update `flutter_web_auth_2` dependency to version 4.1.0
|
||||
* Update `auth.html` example in README.md to align with `flutter_web_auth_2` documentation
|
||||
|
||||
## 16.1.0
|
||||
|
||||
* Add `setDevKey` method to Client service
|
||||
* Add `upsertDocument` method to Databases service
|
||||
|
|
|
|||
|
|
@ -56,13 +56,25 @@ For web in order to capture the OAuth2 callback URL and send it to the applicati
|
|||
```html
|
||||
<!DOCTYPE html>
|
||||
<title>Authentication complete</title>
|
||||
<p>Authentication is complete. If this does not happen automatically, please
|
||||
close the window.
|
||||
<p>Authentication is complete. If this does not happen automatically, please close the window.</p>
|
||||
<script>
|
||||
window.opener.postMessage({
|
||||
'flutter-web-auth-2': window.location.href
|
||||
}, window.location.origin);
|
||||
window.close();
|
||||
function postAuthenticationMessage() {
|
||||
const message = {
|
||||
'flutter-web-auth-2': window.location.href
|
||||
};
|
||||
|
||||
if (window.opener) {
|
||||
window.opener.postMessage(message, window.location.origin);
|
||||
window.close();
|
||||
} else if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage(message, window.location.origin);
|
||||
} else {
|
||||
localStorage.setItem('flutter-web-auth-2', window.location.href);
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
postAuthenticationMessage();
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ abstract class Migration
|
|||
'1.7.0' => 'V22',
|
||||
'1.7.1' => 'V22',
|
||||
'1.7.2' => 'V22',
|
||||
'1.7.3' => 'V22',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use Utopia\Database\Exception\Conflict;
|
|||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Database\Exception\Timeout;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\System\System;
|
||||
|
||||
class V22 extends Migration
|
||||
{
|
||||
|
|
@ -324,7 +325,9 @@ class V22 extends Migration
|
|||
4. Fill "trigger" with "manual"
|
||||
5. Fill "deploymentResourceType". If "resourceType" is "function", set "deploymentResourceType" to "function"
|
||||
6. Fill "search" with "{$id} {domain}"
|
||||
7. Fill "deploymentId" and "deploymentInternalId". If "deploymentResourceType" is "function", get project DB, and find function with ID "resourceId". Then fill rule's "deploymentId" with function's "deployment", and "deploymentId" as backup
|
||||
7. Set "region" to project region
|
||||
8. Fill "owner" with "Appwrite" if "domain" ends with "functions" or "sites"
|
||||
9. Fill "deploymentId" and "deploymentInternalId". If "deploymentResourceType" is "function", get project DB, and find function with ID "resourceId". Then fill rule's "deploymentId" with function's "deployment", and "deploymentId" as backup
|
||||
*/
|
||||
|
||||
$deploymentResourceType = null;
|
||||
|
|
@ -346,14 +349,29 @@ class V22 extends Migration
|
|||
->setAttribute('deploymentResourceType', $document->getAttribute('deploymentResourceType', $deploymentResourceType))
|
||||
->setAttribute('search', \implode(' ', [$document->getId(), $document->getAttribute('domain', '')]));
|
||||
|
||||
$project = $this->dbForProject->getDocument('projects', $document->getAttribute('projectId'));
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
Console::warning("Project \"{$document->getAttribute('projectId')}\" not found for rule \"{$document->getId()}\"");
|
||||
$document->setAttribute('region', System::getEnv('_APP_REGION', 'default'));
|
||||
break;
|
||||
}
|
||||
|
||||
$document->setAttribute('region', $project->getAttribute('region', System::getEnv('_APP_REGION', 'default')));
|
||||
|
||||
$domain = $document->getAttribute('domain', '');
|
||||
$functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$owner = $document->getAttribute('owner', '');
|
||||
if (
|
||||
empty($owner) &&
|
||||
(!empty($functionsDomain) && \str_ends_with($domain, $functionsDomain)) ||
|
||||
(!empty($sitesDomain) && \str_ends_with($domain, $sitesDomain))
|
||||
) {
|
||||
$document->setAttribute('owner', 'Appwrite');
|
||||
}
|
||||
|
||||
if ($deploymentResourceType === 'function') {
|
||||
$project = $this->dbForProject->getDocument('projects', $document->getAttribute('projectId'));
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
Console::warning("Project \"{$document->getAttribute('projectId')}\" not found for rule \"{$document->getId()}\"");
|
||||
break;
|
||||
}
|
||||
|
||||
$dbForOwnerProject = ($this->getProjectDB)($project);
|
||||
$function = $dbForOwnerProject->getDocument('functions', $resourceId);
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ class Create extends Action
|
|||
->inject('deviceForFunctions')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->inject('plan')
|
||||
->callback([$this, 'action']);
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +103,8 @@ class Create extends Action
|
|||
Document $project,
|
||||
Device $deviceForFunctions,
|
||||
Device $deviceForLocal,
|
||||
Build $queueForBuilds
|
||||
Build $queueForBuilds,
|
||||
array $plan
|
||||
) {
|
||||
$activate = \strval($activate) === 'true' || \strval($activate) === '1';
|
||||
|
||||
|
|
@ -135,8 +137,14 @@ class Create extends Action
|
|||
throw new Exception(Exception::STORAGE_FILE_EMPTY, 'No file sent');
|
||||
}
|
||||
|
||||
$functionSizeLimit = (int) System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000');
|
||||
|
||||
if (isset($plan['deploymentSize'])) {
|
||||
$functionSizeLimit = $plan['deploymentSize'] * 1000 * 1000;
|
||||
}
|
||||
|
||||
$fileExt = new FileExt([FileExt::TYPE_GZIP]);
|
||||
$fileSizeValidator = new FileSize(System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000'));
|
||||
$fileSizeValidator = new FileSize($functionSizeLimit);
|
||||
$upload = new Upload();
|
||||
|
||||
// Make sure we handle a single file and multiple files the same way
|
||||
|
|
@ -174,7 +182,7 @@ class Create extends Action
|
|||
}
|
||||
}
|
||||
|
||||
if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
if (!$fileSizeValidator->isValid($fileSize) && $functionSizeLimit !== 0) { // Check if file size is exceeding allowed limit
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class Builds extends Action
|
|||
{
|
||||
$this
|
||||
->desc('Builds worker')
|
||||
->groups(['builds'])
|
||||
->inject('message')
|
||||
->inject('project')
|
||||
->inject('dbForPlatform')
|
||||
|
|
@ -73,6 +74,7 @@ class Builds extends Action
|
|||
->inject('deviceForFiles')
|
||||
->inject('log')
|
||||
->inject('executor')
|
||||
->inject('plan')
|
||||
->callback([$this, 'action']);
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +94,7 @@ class Builds extends Action
|
|||
* @param Device $deviceForFiles
|
||||
* @param Log $log
|
||||
* @param Executor $executor
|
||||
* @param array $plan
|
||||
* @return void
|
||||
* @throws \Utopia\Database\Exception
|
||||
*/
|
||||
|
|
@ -111,7 +114,8 @@ class Builds extends Action
|
|||
callable $isResourceBlocked,
|
||||
Device $deviceForFiles,
|
||||
Log $log,
|
||||
Executor $executor
|
||||
Executor $executor,
|
||||
array $plan
|
||||
): void {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
|
||||
|
|
@ -150,7 +154,8 @@ class Builds extends Action
|
|||
$template,
|
||||
$isResourceBlocked,
|
||||
$log,
|
||||
$executor
|
||||
$executor,
|
||||
$plan
|
||||
);
|
||||
break;
|
||||
|
||||
|
|
@ -177,6 +182,7 @@ class Builds extends Action
|
|||
* @param Document $template
|
||||
* @param Log $log
|
||||
* @param Executor $executor
|
||||
* @param array $plan
|
||||
* @return void
|
||||
* @throws \Utopia\Database\Exception
|
||||
*
|
||||
|
|
@ -200,7 +206,8 @@ class Builds extends Action
|
|||
Document $template,
|
||||
callable $isResourceBlocked,
|
||||
Log $log,
|
||||
Executor $executor
|
||||
Executor $executor,
|
||||
array $plan
|
||||
): void {
|
||||
$resourceKey = match ($resource->getCollection()) {
|
||||
'functions' => 'functionId',
|
||||
|
|
@ -476,8 +483,12 @@ class Builds extends Action
|
|||
$directorySize = $localDevice->getDirectorySize($tmpDirectory);
|
||||
$sizeLimit = (int)System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000');
|
||||
|
||||
if ($directorySize > $sizeLimit) {
|
||||
throw new \Exception('Repository directory size should be less than ' . number_format($sizeLimit / 1048576, 2) . ' MBs.');
|
||||
if (isset($plan['deploymentSize'])) {
|
||||
$sizeLimit = (int) $plan['deploymentSize'] * 1000 * 1000;
|
||||
}
|
||||
|
||||
if ($directorySize > $sizeLimit && $sizeLimit !== 0) {
|
||||
throw new \Exception('Repository directory size should be less than ' . number_format($sizeLimit / (1000 * 1000), 2) . ' MBs.');
|
||||
}
|
||||
|
||||
Console::execute('find ' . \escapeshellarg($tmpDirectory) . ' -type d -name ".git" -exec rm -rf {} +', '', $stdout, $stderr);
|
||||
|
|
@ -803,8 +814,11 @@ class Builds extends Action
|
|||
$durationEnd = \microtime(true);
|
||||
|
||||
$buildSizeLimit = (int)System::getEnv('_APP_COMPUTE_BUILD_SIZE_LIMIT', '2000000000');
|
||||
if ($response['size'] > $buildSizeLimit) {
|
||||
throw new \Exception('Build size should be less than ' . number_format($buildSizeLimit / 1048576, 2) . ' MBs.');
|
||||
if (isset($plan['buildSize'])) {
|
||||
$buildSizeLimit = $plan['buildSize'] * 1000 * 1000;
|
||||
}
|
||||
if ($response['size'] > $buildSizeLimit && $buildSizeLimit !== 0) {
|
||||
throw new \Exception('Build size should be less than ' . number_format($buildSizeLimit / (1000 * 1000), 2) . ' MBs.');
|
||||
}
|
||||
|
||||
/** Update the build document */
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ class Create extends Action
|
|||
->inject('deviceForSites')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->inject('plan')
|
||||
->callback([$this, 'action']);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +104,8 @@ class Create extends Action
|
|||
Event $queueForEvents,
|
||||
Device $deviceForSites,
|
||||
Device $deviceForLocal,
|
||||
Build $queueForBuilds
|
||||
Build $queueForBuilds,
|
||||
array $plan
|
||||
) {
|
||||
$activate = \strval($activate) === 'true' || \strval($activate) === '1';
|
||||
|
||||
|
|
@ -136,8 +138,14 @@ class Create extends Action
|
|||
throw new Exception(Exception::STORAGE_FILE_EMPTY, 'No file sent');
|
||||
}
|
||||
|
||||
$siteSizeLimit = (int) System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000');
|
||||
|
||||
if (isset($plan['deploymentSize'])) {
|
||||
$siteSizeLimit = $plan['deploymentSize'] * 1000 * 1000;
|
||||
}
|
||||
|
||||
$fileExt = new FileExt([FileExt::TYPE_GZIP]);
|
||||
$fileSizeValidator = new FileSize(System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000'));
|
||||
$fileSizeValidator = new FileSize($siteSizeLimit);
|
||||
$upload = new Upload();
|
||||
|
||||
// Make sure we handle a single file and multiple files the same way
|
||||
|
|
@ -175,7 +183,7 @@ class Create extends Action
|
|||
}
|
||||
}
|
||||
|
||||
if (!$fileSizeValidator->isValid($fileSize)) { // Check if file size is exceeding allowed limit
|
||||
if (!$fileSizeValidator->isValid($fileSize) && $siteSizeLimit !== 0) { // Check if file size is exceeding allowed limit
|
||||
throw new Exception(Exception::STORAGE_INVALID_FILE_SIZE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ class AttributeString extends Attribute
|
|||
'required' => false,
|
||||
'example' => 'default',
|
||||
])
|
||||
->addRule('encrypt', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Defines whether this attribute is encrypted or not.',
|
||||
'default' => false,
|
||||
'required' => false,
|
||||
'example' => false,
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class Comment
|
|||
$this->builds[$id] = [
|
||||
'projectName' => $project->getAttribute('name'),
|
||||
'projectId' => $project->getId(),
|
||||
'region' => $project->getAttribute('region', 'default'),
|
||||
'resourceName' => $resource->getAttribute('name'),
|
||||
'resourceId' => $resource->getId(),
|
||||
'resourceType' => $resourceType,
|
||||
|
|
@ -66,6 +67,7 @@ class Comment
|
|||
if ($build['resourceType'] === 'site') {
|
||||
$projects[$build['projectId']]['site'][$build['resourceId']] = [
|
||||
'name' => $build['resourceName'],
|
||||
'region' => $build['region'],
|
||||
'status' => $build['buildStatus'],
|
||||
'deploymentId' => $build['deploymentId'],
|
||||
'action' => $build['action'],
|
||||
|
|
@ -74,6 +76,7 @@ class Comment
|
|||
} elseif ($build['resourceType'] === 'function') {
|
||||
$projects[$build['projectId']]['function'][$build['resourceId']] = [
|
||||
'name' => $build['resourceName'],
|
||||
'region' => $build['region'],
|
||||
'status' => $build['buildStatus'],
|
||||
'deploymentId' => $build['deploymentId'],
|
||||
'action' => $build['action'],
|
||||
|
|
@ -114,7 +117,7 @@ class Comment
|
|||
};
|
||||
|
||||
if ($site['action']['type'] === 'logs') {
|
||||
$action = '[View Logs](' . $protocol . '://' . $hostname . '/console/project-' . $projectId . '/sites/site-' . $siteId . '/deployments/deployment-' . $site['deploymentId'] . ')';
|
||||
$action = '[View Logs](' . $protocol . '://' . $hostname . '/console/project-' . $site['region'] . '-' . $projectId . '/sites/site-' . $siteId . '/deployments/deployment-' . $site['deploymentId'] . ')';
|
||||
} else {
|
||||
$action = '[Authorize](' . $site['action']['url'] . ')';
|
||||
}
|
||||
|
|
@ -146,12 +149,12 @@ class Comment
|
|||
$text .= "| :- | :- | :- | :- |\n";
|
||||
|
||||
foreach ($project['function'] as $functionId => $function) {
|
||||
$extension = $site['status'] === 'building' ? 'gif' : 'png';
|
||||
$extension = $function['status'] === 'building' ? 'gif' : 'png';
|
||||
|
||||
$pathLight = '/images/vcs/status-' . $site['status'] . '-light.' . $extension;
|
||||
$pathDark = '/images/vcs/status-' . $site['status'] . '-dark.' . $extension;
|
||||
$pathLight = '/images/vcs/status-' . $function['status'] . '-light.' . $extension;
|
||||
$pathDark = '/images/vcs/status-' . $function['status'] . '-dark.' . $extension;
|
||||
|
||||
$status = match ($site['status']) {
|
||||
$status = match ($function['status']) {
|
||||
'waiting' => $this->generatImage($pathLight, $pathDark, 'Queued', 85) . ' _Queued_',
|
||||
'processing' => $this->generatImage($pathLight, $pathDark, 'Processing', 85) . ' _Processing_',
|
||||
'building' => $this->generatImage($pathLight, $pathDark, 'Building', 85) . ' _Building_',
|
||||
|
|
@ -160,7 +163,7 @@ class Comment
|
|||
};
|
||||
|
||||
if ($function['action']['type'] === 'logs') {
|
||||
$action = '[View Logs](' . $protocol . '://' . $hostname . '/console/project-' . $projectId . '/functions/function-' . $functionId . '/deployment-' . $function['deploymentId'] . ')';
|
||||
$action = '[View Logs](' . $protocol . '://' . $hostname . '/console/project-' . $function['region'] . '-' . $projectId . '/functions/function-' . $functionId . '/deployment-' . $function['deploymentId'] . ')';
|
||||
} else {
|
||||
$action = '[Authorize](' . $function['action']['url'] . ')';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ trait DatabasesBase
|
|||
$this->assertEquals($title['body']['type'], 'string');
|
||||
$this->assertEquals($title['body']['size'], 256);
|
||||
$this->assertEquals($title['body']['required'], true);
|
||||
|
||||
$this->assertFalse($title['body']['encrypt']);
|
||||
$this->assertEquals(202, $description['headers']['status-code']);
|
||||
$this->assertEquals($description['body']['key'], 'description');
|
||||
$this->assertEquals($description['body']['type'], 'string');
|
||||
|
|
|
|||
|
|
@ -686,6 +686,18 @@ class DatabasesCustomServerTest extends Scope
|
|||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
// checking size test
|
||||
$lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'lastName',
|
||||
'size' => 149,
|
||||
'required' => true,
|
||||
'encrypt' => true
|
||||
]);
|
||||
$this->assertEquals("Size too small. Encrypted strings require a minimum size of " . APP_DATABASE_ENCRYPT_SIZE_MIN . " characters.", $lastName['body']['message']);
|
||||
|
||||
$lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
|
@ -697,7 +709,14 @@ class DatabasesCustomServerTest extends Scope
|
|||
'required' => true,
|
||||
'encrypt' => true
|
||||
]);
|
||||
|
||||
$this->assertTrue($lastName['body']['encrypt']);
|
||||
sleep(1);
|
||||
$response = $this->client->call(Client::METHOD_GET, $attributesPath . '/lastName', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]));
|
||||
$this->assertTrue($response['body']['encrypt']);
|
||||
|
||||
/**
|
||||
* Check status of every attribute
|
||||
|
|
@ -741,6 +760,24 @@ class DatabasesCustomServerTest extends Scope
|
|||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Jonah', $document['body']['firstName']);
|
||||
$this->assertEquals('Jameson', $document['body']['lastName']);
|
||||
|
||||
|
||||
$actors = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), []);
|
||||
$attributes = $actors['body']['attributes'];
|
||||
foreach ($attributes as $attribute) {
|
||||
$this->assertArrayHasKey('encrypt', $attribute);
|
||||
if ($attribute['key'] === 'firstName') {
|
||||
$this->assertFalse($attribute['encrypt']);
|
||||
}
|
||||
if ($attribute['key'] === 'lastName') {
|
||||
$this->assertTrue($attribute['encrypt']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testDeleteAttribute(): array
|
||||
|
|
|
|||
Loading…
Reference in a new issue