Merge branch '1.6.x' into pla-1883

This commit is contained in:
Chirag Aggarwal 2025-02-14 07:16:43 +00:00
commit 4c7917687d
9 changed files with 283 additions and 74 deletions

View file

@ -8,9 +8,33 @@ env:
IMAGE: appwrite-dev
CACHE_KEY: appwrite-dev-${{ github.event.pull_request.head.sha }}
on: [pull_request]
on: [ pull_request ]
jobs:
check_database_changes:
name: Check if utopia-php/database changed
runs-on: ubuntu-latest
outputs:
database_changed: ${{ steps.check.outputs.database_changed }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Fetch base branch
run: git fetch origin ${{ github.event.pull_request.base.ref }}
- name: Check for utopia-php/database changes
id: check
run: |
if git diff origin/${{ github.event.pull_request.base.ref }} HEAD -- composer.lock | grep -q '"name": "utopia-php/database"'; then
echo "Database version changed, going to run all mode tests."
echo "database_changed=true" >> "$GITHUB_ENV"
echo "database_changed=true" >> "$GITHUB_OUTPUT"
else
echo "database_changed=false" >> "$GITHUB_ENV"
echo "database_changed=false" >> "$GITHUB_OUTPUT"
fi
setup:
name: Setup & Build Appwrite Image
runs-on: ubuntu-latest
@ -103,6 +127,62 @@ jobs:
name: E2E Service Test
runs-on: ubuntu-latest
needs: setup
strategy:
fail-fast: false
matrix:
service: [
Account,
Avatars,
Console,
Databases,
Functions,
FunctionsSchedule,
GraphQL,
Health,
Locale,
Projects,
Realtime,
Storage,
Teams,
Users,
Webhooks,
VCS,
Messaging,
Migrations
]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Load Cache
uses: actions/cache@v4
with:
key: ${{ env.CACHE_KEY }}
path: /tmp/${{ env.IMAGE }}.tar
fail-on-cache-miss: true
- name: Load and Start Appwrite
run: |
docker load --input /tmp/${{ env.IMAGE }}.tar
docker compose up -d
sleep 30
- name: Run ${{ matrix.service }} tests with Project table mode
run: |
echo "Using project tables"
export _APP_DATABASE_SHARED_TABLES=
export _APP_DATABASE_SHARED_TABLES_V1=
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
appwrite test /usr/src/code/tests/e2e/Services/${{ matrix.service }} --debug
e2e_shared_mode_test:
name: E2E Shared Mode Service Test
runs-on: ubuntu-latest
needs: [ setup, check_database_changes ]
if: needs.check_database_changes.outputs.database_changed == 'true'
strategy:
fail-fast: false
matrix:
@ -128,7 +208,6 @@ jobs:
Migrations
]
tables-mode: [
'Project',
'Shared V1',
'Shared V2',
]
@ -160,12 +239,8 @@ jobs:
echo "Using shared tables V2"
export _APP_DATABASE_SHARED_TABLES=database_db_main
export _APP_DATABASE_SHARED_TABLES_V1=
else
echo "Using project tables"
export _APP_DATABASE_SHARED_TABLES=
export _APP_DATABASE_SHARED_TABLES_V1=
fi
docker compose exec -T \
-e _APP_DATABASE_SHARED_TABLES \
-e _APP_DATABASE_SHARED_TABLES_V1 \
@ -251,4 +326,4 @@ jobs:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: benchmark.txt
edit-mode: replace
edit-mode: replace

View file

@ -27,6 +27,7 @@ use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Conflict as ConflictException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\Index as IndexException;
use Utopia\Database\Exception\Limit as LimitException;
use Utopia\Database\Exception\NotFound as NotFoundException;
use Utopia\Database\Exception\Query as QueryException;
@ -393,6 +394,8 @@ function updateAttribute(
throw new Exception(Exception::ATTRIBUTE_NOT_FOUND);
} catch (LimitException) {
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED);
} catch (IndexException $e) {
throw new Exception(Exception::INDEX_INVALID, $e->getMessage());
}
}

View file

@ -45,13 +45,13 @@
"ext-sockets": "*",
"appwrite/php-runtimes": "0.16.*",
"appwrite/php-clamav": "2.0.*",
"utopia-php/abuse": "0.49.*",
"utopia-php/abuse": "0.50.*",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.49.*",
"utopia-php/audit": "0.51.*",
"utopia-php/cache": "0.11.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.58.4",
"utopia-php/database": "0.59.0",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",

80
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "232691925e05350c7a3831a4e43d79d1",
"content-hash": "ed36bf1392e79d1b1bb07fb2a81f03bf",
"packages": [
{
"name": "adhocore/jwt",
@ -3377,16 +3377,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.49.0",
"version": "0.50.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99"
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/76612c274b895aa3d4d1fa27557a6402463eea99",
"reference": "76612c274b895aa3d4d1fa27557a6402463eea99",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/3ff67819e9de61506c5ca070a70552f7ebe99f80",
"reference": "3ff67819e9de61506c5ca070a70552f7ebe99f80",
"shasum": ""
},
"require": {
@ -3394,7 +3394,7 @@
"ext-pdo": "*",
"ext-redis": "*",
"php": ">=8.0",
"utopia-php/database": "0.58.*"
"utopia-php/database": "0.59.*"
},
"require-dev": {
"laravel/pint": "1.*",
@ -3422,9 +3422,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.49.0"
"source": "https://github.com/utopia-php/abuse/tree/0.50.0"
},
"time": "2025-02-04T07:33:59+00:00"
"time": "2025-02-12T09:13:59+00:00"
},
{
"name": "utopia-php/analytics",
@ -3474,21 +3474,21 @@
},
{
"name": "utopia-php/audit",
"version": "0.49.0",
"version": "0.51.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d"
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"reference": "9d5c5e0cf0f6d9157b911fc3971da4331d71c96d",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
"reference": "a5a4b73a57e27a0fac8025b1d6038e145a1ca04e",
"shasum": ""
},
"require": {
"php": ">=8.0",
"utopia-php/database": "0.58.*"
"utopia-php/database": "0.59.*"
},
"require-dev": {
"laravel/pint": "1.*",
@ -3515,9 +3515,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.49.0"
"source": "https://github.com/utopia-php/audit/tree/0.51.0"
},
"time": "2025-02-04T07:27:18+00:00"
"time": "2025-02-12T09:12:44+00:00"
},
{
"name": "utopia-php/cache",
@ -3717,16 +3717,16 @@
},
{
"name": "utopia-php/database",
"version": "0.58.4",
"version": "0.59.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe"
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe",
"reference": "ff3fd22e4fe757cc2a78f17169f6dcc45c96d0fe",
"url": "https://api.github.com/repos/utopia-php/database/zipball/0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
"reference": "0eed7f1ad3eb66ff4a7d73b68dd9d3e05089eb18",
"shasum": ""
},
"require": {
@ -3767,9 +3767,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.58.4"
"source": "https://github.com/utopia-php/database/tree/0.59.0"
},
"time": "2025-02-05T02:51:02+00:00"
"time": "2025-02-12T08:08:29+00:00"
},
{
"name": "utopia-php/domains",
@ -4170,16 +4170,16 @@
},
{
"name": "utopia-php/migration",
"version": "0.6.17",
"version": "0.6.19",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b"
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/677a5c4688d7f54d1631a91f76a35d51346cf96b",
"reference": "677a5c4688d7f54d1631a91f76a35d51346cf96b",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/3c9497f7a54ef88b1077c48d8326893133ad78eb",
"reference": "3c9497f7a54ef88b1077c48d8326893133ad78eb",
"shasum": ""
},
"require": {
@ -4187,7 +4187,7 @@
"ext-curl": "*",
"ext-openssl": "*",
"php": ">=8.1",
"utopia-php/database": "0.58.*",
"utopia-php/database": "0.59.*",
"utopia-php/dsn": "0.2.*",
"utopia-php/framework": "0.33.*",
"utopia-php/storage": "0.18.*"
@ -4220,9 +4220,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/0.6.17"
"source": "https://github.com/utopia-php/migration/tree/0.6.19"
},
"time": "2025-02-05T05:27:29+00:00"
"time": "2025-02-13T07:50:21+00:00"
},
{
"name": "utopia-php/mongo",
@ -4607,16 +4607,16 @@
},
{
"name": "utopia-php/storage",
"version": "0.18.8",
"version": "0.18.9",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/storage.git",
"reference": "84737afa634e6a833fc4f8b0c967553234d3f215"
"reference": "1cf455404e8700b3093fd73d74a38d41cdced90c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/84737afa634e6a833fc4f8b0c967553234d3f215",
"reference": "84737afa634e6a833fc4f8b0c967553234d3f215",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/1cf455404e8700b3093fd73d74a38d41cdced90c",
"reference": "1cf455404e8700b3093fd73d74a38d41cdced90c",
"shasum": ""
},
"require": {
@ -4656,9 +4656,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/storage/issues",
"source": "https://github.com/utopia-php/storage/tree/0.18.8"
"source": "https://github.com/utopia-php/storage/tree/0.18.9"
},
"time": "2024-12-04T08:30:35+00:00"
"time": "2025-02-11T13:10:40+00:00"
},
{
"name": "utopia-php/swoole",
@ -5560,16 +5560,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.12.1",
"version": "1.13.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"shasum": ""
},
"require": {
@ -5608,7 +5608,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
},
"funding": [
{
@ -5616,7 +5616,7 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-02-12T12:17:51+00:00"
},
{
"name": "nikic/php-parser",

View file

@ -6,15 +6,33 @@ use Appwrite\Auth\Auth;
use Exception;
use Throwable;
use Utopia\Audit\Audit;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization;
use Utopia\Database\Exception\Structure;
use Utopia\Platform\Action;
use Utopia\Queue\Message;
use Utopia\System\System;
class Audits extends Action
{
private const BATCH_SIZE_DEVELOPMENT = 1; // smaller batch size for development
private const BATCH_SIZE_PRODUCTION = 5_000;
private const BATCH_AGGREGATION_INTERVAL = 60; // in seconds
private int $lastTriggeredTime = 0;
private array $logs = [];
private function getBatchSize(): int
{
return System::getEnv('_APP_ENV', 'development') === 'development'
? self::BATCH_SIZE_DEVELOPMENT
: self::BATCH_SIZE_PRODUCTION;
}
public static function getName(): string
{
return 'audits';
@ -30,6 +48,8 @@ class Audits extends Action
->inject('message')
->inject('dbForProject')
->callback(fn ($message, $dbForProject) => $this->action($message, $dbForProject));
$this->lastTriggeredTime = time();
}
@ -44,13 +64,14 @@ class Audits extends Action
*/
public function action(Message $message, Database $dbForProject): void
{
$payload = $message->getPayload() ?? [];
if (empty($payload)) {
throw new Exception('Missing payload');
}
Console::info('Aggregating audit logs');
$event = $payload['event'] ?? '';
$auditPayload = $payload['payload'] ?? '';
$mode = $payload['mode'] ?? '';
@ -63,23 +84,48 @@ class Audits extends Action
$userEmail = $user->getAttribute('email', '');
$userType = $user->getAttribute('type', Auth::ACTIVITY_TYPE_USER);
$audit = new Audit($dbForProject);
$audit->log(
userId: $user->getInternalId(),
// Pass first, most verbose event pattern
event: $event,
resource: $resource,
userAgent: $userAgent,
ip: $ip,
location: '',
data: [
// Create event data
$eventData = [
'userId' => $user->getInternalId(),
'event' => $event,
'resource' => $resource,
'userAgent' => $userAgent,
'ip' => $ip,
'location' => '',
'data' => [
'userId' => $user->getId(),
'userName' => $userName,
'userEmail' => $userEmail,
'userType' => $userType,
'mode' => $mode,
'data' => $auditPayload,
]
);
],
'timestamp' => DateTime::formatTz(DateTime::now())
];
$this->logs[] = $eventData;
// Check if we should process the batch by checking both for the batch size and the elapsed time
$batchSize = $this->getBatchSize();
$shouldProcessBatch = count($this->logs) >= $batchSize;
if (!$shouldProcessBatch && count($this->logs) > 0) {
$shouldProcessBatch = (time() - $this->lastTriggeredTime) >= self::BATCH_AGGREGATION_INTERVAL;
}
if ($shouldProcessBatch) {
Console::log('Processing batch with ' . count($this->logs) . ' events');
$audit = new Audit($dbForProject);
try {
$audit->logBatch($this->logs);
Console::success('Audit logs processed successfully');
} catch (Throwable $e) {
Console::error('Error processing audit logs: ' . $e->getMessage());
} finally {
// Clear the pending events after successful batch processing
$this->logs = [];
$this->lastTriggeredTime = time();
}
}
}
}

View file

@ -55,8 +55,10 @@ class Builds extends Action
->inject('cache')
->inject('dbForProject')
->inject('deviceForFunctions')
->inject('isResourceBlocked')
->inject('log')
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log) => $this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $queueForRealtime, $usage, $cache, $dbForProject, $deviceForFunctions, $log));
->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log) =>
$this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForFunctions, $queueForRealtime, $usage, $cache, $dbForProject, $deviceForFunctions, $isResourceBlocked, $log));
}
/**
@ -74,7 +76,7 @@ class Builds extends Action
* @return void
* @throws \Utopia\Database\Exception
*/
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, Log $log): void
public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log): void
{
$payload = $message->getPayload() ?? [];
@ -95,7 +97,7 @@ class Builds extends Action
case BUILD_TYPE_RETRY:
Console::info('Creating build for deployment: ' . $deployment->getId());
$github = new GitHub($cache);
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $log);
$this->buildDeployment($deviceForFunctions, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $isResourceBlocked, $log);
break;
default:
@ -121,7 +123,7 @@ class Builds extends Action
* @throws \Utopia\Database\Exception
* @throws Exception
*/
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, Log $log): void
protected function buildDeployment(Device $deviceForFunctions, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, callable $isResourceBlocked, Log $log): void
{
$executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST'));
@ -130,7 +132,11 @@ class Builds extends Action
$function = $dbForProject->getDocument('functions', $functionId);
if ($function->isEmpty()) {
throw new \Exception('Function not found', 404);
throw new \Exception('Function not found');
}
if ($isResourceBlocked($project, RESOURCE_TYPE_FUNCTIONS, $functionId)) {
throw new \Exception('Function blocked');
}
$deploymentId = $deployment->getId();
@ -138,11 +144,11 @@ class Builds extends Action
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
if ($deployment->isEmpty()) {
throw new \Exception('Deployment not found', 404);
throw new \Exception('Deployment not found');
}
if (empty($deployment->getAttribute('entrypoint', ''))) {
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".', 500);
throw new \Exception('Entrypoint for your Appwrite Function is missing. Please specify it when making deployment or update the entrypoint under your function\'s "Settings" > "Configuration" > "Entrypoint".');
}
$version = $function->getAttribute('version', 'v2');
@ -560,7 +566,7 @@ class Builds extends Action
$build = $dbForProject->getDocument('builds', $build->getId());
if ($build->isEmpty()) {
throw new \Exception('Build not found', 404);
throw new \Exception('Build not found');
}
if ($build->getAttribute('status') === 'canceled') {

View file

@ -7,6 +7,7 @@ use Appwrite\Certificates\Adapter as CertificatesAdapter;
use Appwrite\Extend\Exception;
use Executor\Executor;
use Throwable;
use Utopia\Abuse\Adapters\TimeLimit\Database as AbuseDatabase;
use Utopia\Audit\Audit;
use Utopia\Cache\Adapter\Filesystem;
use Utopia\Cache\Cache;
@ -505,7 +506,8 @@ class Deletes extends Action
$projectCollectionIds = [
...\array_keys(Config::getParam('collections', [])['projects']),
Audit::COLLECTION
Audit::COLLECTION,
AbuseDatabase::COLLECTION,
];
$limit = \count($projectCollectionIds) + 25;

View file

@ -160,6 +160,12 @@ class StatsResources extends Action
call_user_func_array($this->logError, [$th, "StatsResources", "count_for_buckets_{$project->getId()}"]);
}
try {
$this->countImageTransformations($dbForProject, $dbForLogs, $region);
} catch (Throwable $th) {
call_user_func_array($this->logError, [$th, "StatsResources", "count_for_buckets_{$project->getId()}"]);
}
try {
$this->countForDatabase($dbForProject, $dbForLogs, $region);
} catch (Throwable $th) {
@ -246,6 +252,8 @@ class StatsResources extends Action
});
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalImageTransformations, 'inf');
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalDailyImageTransformations, '1d');
$this->createStatsDocuments($region, METRIC_FILES_IMAGES_TRANSFORMED, $totalHourlyImageTransformations, '1h');
}
@ -346,10 +354,11 @@ class StatsResources extends Action
'period' => $period,
'region' => $region,
'value' => $value,
'time' => $time,
]);
}
} else {
$time = 'inf' === $period ? null : \date($this->periods[$period], \time());
$time = $period === 'inf' ? null : \date($this->periods[$period], \time());
$id = \md5("{$time}_{$period}_{$metric}");
$this->documents[] = new Document([
'$id' => $id,
@ -357,6 +366,7 @@ class StatsResources extends Action
'period' => $period,
'region' => $region,
'value' => $value,
'time' => $time,
]);
}
}

View file

@ -399,6 +399,73 @@ trait DatabasesBase
$this->assertEquals(400, $response['headers']['status-code']);
}
/**
* @depends testCreateDatabase
*/
public function testPatchAttribute(array $data): void
{
$databaseId = $data['databaseId'];
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'collectionId' => ID::unique(),
'name' => 'patch',
'documentSecurity' => true,
'permissions' => [
Permission::create(Role::user($this->getUser()['$id'])),
],
]);
$this->assertEquals(201, $collection['headers']['status-code']);
$this->assertEquals($collection['body']['name'], 'patch');
$attribute = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection['body']['$id'].'/attributes/string', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'title',
'required' => true,
'size' => 100,
]);
$this->assertEquals(202, $attribute['headers']['status-code']);
$this->assertEquals($attribute['body']['size'], 100);
sleep(1);
$index = $this->client->call(Client::METHOD_POST, '/databases/'.$databaseId.'/collections/'.$collection['body']['$id'].'/indexes', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey']
]), [
'key' => 'titleIndex',
'type' => 'key',
'attributes' => ['title'],
]);
$this->assertEquals(202, $index['headers']['status-code']);
sleep(1);
/**
* Update attribute size to exceed Index maximum length
*/
$attribute = $this->client->call(Client::METHOD_PATCH, '/databases/'.$databaseId.'/collections/'.$collection['body']['$id'].'/attributes/string/'.$attribute['body']['key'], array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]), [
'size' => 1000,
'required' => true,
'default' => null,
]);
$this->assertEquals(400, $attribute['headers']['status-code']);
$this->assertStringContainsString('Index length is longer than the maximum: 76', $attribute['body']['message']);
}
public function testUpdateAttributeEnum(): void
{
$database = $this->client->call(Client::METHOD_POST, '/databases', [