Merge branch 'main' into update-sdks-devkeys

This commit is contained in:
Chirag Aggarwal 2025-05-26 09:30:09 +05:30 committed by GitHub
commit 760f26e044
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 197 additions and 60 deletions

View file

@ -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 的本机主机上完成安装后,服务器可能需要几分钟才能启动。

View file

@ -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.

View file

@ -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);
});

View file

@ -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';

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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']);

View file

@ -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

View file

@ -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

View file

@ -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>
```

View file

@ -87,6 +87,7 @@ abstract class Migration
'1.7.0' => 'V22',
'1.7.1' => 'V22',
'1.7.2' => 'V22',
'1.7.3' => 'V22',
];
/**

View file

@ -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);

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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,
])
;
}

View file

@ -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'] . ')';
}

View file

@ -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');

View file

@ -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