mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge remote-tracking branch 'origin/1.9.x' into bump-database-version
# Conflicts: # src/Appwrite/Event/Message/Usage.php
This commit is contained in:
@@ -150,8 +150,16 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
||||
|
||||
- name: Cache PHPStan result cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .phpstan-cache
|
||||
key: phpstan-${{ github.sha }}
|
||||
restore-keys: |
|
||||
phpstan-
|
||||
|
||||
- name: Run PHPStan
|
||||
run: composer analyze
|
||||
run: composer analyze -- --no-progress
|
||||
|
||||
locale:
|
||||
name: Checks / Locale
|
||||
|
||||
@@ -21,6 +21,7 @@ appwrite.config.json
|
||||
/app/config/specs/
|
||||
/docs/examples/
|
||||
.phpunit.cache
|
||||
.phpstan-cache
|
||||
playwright-report
|
||||
test-results
|
||||
docker-compose.web-installer.yml
|
||||
|
||||
@@ -72,6 +72,7 @@ Before running the installation command, make sure you have [Docker](https://www
|
||||
|
||||
```bash
|
||||
docker run -it --rm \
|
||||
--publish 20080:20080 \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
@@ -84,6 +85,7 @@ docker run -it --rm \
|
||||
|
||||
```cmd
|
||||
docker run -it --rm ^
|
||||
--publish 20080:20080 ^
|
||||
--volume //var/run/docker.sock:/var/run/docker.sock ^
|
||||
--volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^
|
||||
--entrypoint="install" ^
|
||||
@@ -94,6 +96,7 @@ docker run -it --rm ^
|
||||
|
||||
```powershell
|
||||
docker run -it --rm `
|
||||
--publish 20080:20080 `
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock `
|
||||
--volume ${pwd}/appwrite:/usr/src/code/appwrite:rw `
|
||||
--entrypoint="install" `
|
||||
|
||||
+29
-4
@@ -888,7 +888,6 @@ Http::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authori
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
Http::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Document $project, Request $request, UsageContext $usage, Authorization $authorization) {
|
||||
|
||||
return function (Document $database) use ($pools, $cache, $project, $request, $usage, $authorization): Database {
|
||||
$databaseDSN = $database->getAttribute('database', $project->getAttribute('database', ''));
|
||||
$databaseType = $database->getAttribute('type', '');
|
||||
@@ -907,11 +906,12 @@ Http::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Docume
|
||||
$dsn = new DSN('mysql://' . $project->getAttribute('database'));
|
||||
}
|
||||
|
||||
$pool = $pools->get($databaseDSN->getHost());
|
||||
$databaseHost = $databaseDSN->getHost();
|
||||
$pool = $pools->get($databaseHost);
|
||||
|
||||
$adapter = new DatabasePool($pool);
|
||||
$database = new Database($adapter, $cache);
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTables = \array_filter(\explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')));
|
||||
|
||||
$database
|
||||
->setDatabase(APP_DATABASE)
|
||||
@@ -922,7 +922,32 @@ Http::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Docume
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
// inside pools authorization needs to be set first
|
||||
$database->getAdapter()->setSupportForAttributes($databaseType !== DOCUMENTSDB);
|
||||
if (\in_array($dsn->getHost(), $sharedTables)) {
|
||||
|
||||
// For separate pools (documentsdb/vectorsdb), check their own shared tables config
|
||||
if ($databaseHost !== $dsn->getHost()) {
|
||||
$dbTypeSharedTables = match ($databaseType) {
|
||||
DOCUMENTSDB => \array_filter(\explode(',', System::getEnv('_APP_DATABASE_DOCUMENTSDB_SHARED_TABLES', ''))),
|
||||
VECTORSDB => \array_filter(\explode(',', System::getEnv('_APP_DATABASE_VECTORSDB_SHARED_TABLES', ''))),
|
||||
default => [],
|
||||
};
|
||||
|
||||
if (\in_array($databaseHost, $dbTypeSharedTables)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant($project->getSequence())
|
||||
->setNamespace($dsn->getParam('namespace'));
|
||||
} else {
|
||||
$database
|
||||
->setSharedTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $project->getSequence());
|
||||
}
|
||||
|
||||
try {
|
||||
$database->create();
|
||||
} catch (\Utopia\Database\Exception\Duplicate) {
|
||||
}
|
||||
} elseif (\in_array($dsn->getHost(), $sharedTables)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant($project->getSequence())
|
||||
|
||||
+28
-3
@@ -246,7 +246,8 @@ Server::setResource('getDatabasesDB', function (Cache $cache, Registry $register
|
||||
}
|
||||
|
||||
$pools = $register->get('pools');
|
||||
$pool = $pools->get($databaseDSN->getHost());
|
||||
$databaseHost = $databaseDSN->getHost();
|
||||
$pool = $pools->get($databaseHost);
|
||||
|
||||
$adapter = new DatabasePool($pool);
|
||||
$database = new Database($adapter, $cache);
|
||||
@@ -255,9 +256,33 @@ Server::setResource('getDatabasesDB', function (Cache $cache, Registry $register
|
||||
->setAuthorization($authorization);
|
||||
$database->getAdapter()->setSupportForAttributes($databaseType !== DOCUMENTSDB);
|
||||
|
||||
$sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', ''));
|
||||
$sharedTables = \array_filter(\explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')));
|
||||
|
||||
if (\in_array($dsn->getHost(), $sharedTables, true)) {
|
||||
// For separate pools (documentsdb/vectorsdb), check their own shared tables config
|
||||
if ($databaseHost !== $dsn->getHost()) {
|
||||
$dbTypeSharedTables = match ($databaseType) {
|
||||
DOCUMENTSDB => \array_filter(\explode(',', System::getEnv('_APP_DATABASE_DOCUMENTSDB_SHARED_TABLES', ''))),
|
||||
VECTORSDB => \array_filter(\explode(',', System::getEnv('_APP_DATABASE_VECTORSDB_SHARED_TABLES', ''))),
|
||||
default => [],
|
||||
};
|
||||
|
||||
if (\in_array($databaseHost, $dbTypeSharedTables)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant($projectDocument->getSequence())
|
||||
->setNamespace($dsn->getParam('namespace'));
|
||||
} else {
|
||||
$database
|
||||
->setSharedTables(false)
|
||||
->setTenant(null)
|
||||
->setNamespace('_' . $projectDocument->getSequence());
|
||||
}
|
||||
|
||||
try {
|
||||
$database->create();
|
||||
} catch (\Utopia\Database\Exception\Duplicate) {
|
||||
}
|
||||
} elseif (\in_array($dsn->getHost(), $sharedTables, true)) {
|
||||
$database
|
||||
->setSharedTables(true)
|
||||
->setTenant($projectDocument->getSequence())
|
||||
|
||||
@@ -216,102 +216,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Resolvers.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$databaseId might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 5
|
||||
path: src/Appwrite/GraphQL/Schema.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$sdk in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Schema.php
|
||||
|
||||
-
|
||||
message: '#^Method Appwrite\\GraphQL\\Types\:\:assoc\(\) should return Appwrite\\GraphQL\\Types\\Json but returns GraphQL\\Type\\Definition\\Type\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Types.php
|
||||
|
||||
-
|
||||
message: '#^Method Appwrite\\GraphQL\\Types\:\:inputFile\(\) should return Appwrite\\GraphQL\\Types\\InputFile but returns GraphQL\\Type\\Definition\\Type\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Types.php
|
||||
|
||||
-
|
||||
message: '#^Method Appwrite\\GraphQL\\Types\:\:json\(\) should return Appwrite\\GraphQL\\Types\\Json but returns GraphQL\\Type\\Definition\\Type\.$#'
|
||||
identifier: return.type
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Types.php
|
||||
|
||||
-
|
||||
message: '#^Class Appwrite\\Network\\Validator\\CNAME not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Types/Mapper.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Validator\\Origin not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/GraphQL/Types/Mapper.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V15\:\:documentsIterator\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 7
|
||||
path: src/Appwrite/Migration/Version/V15.php
|
||||
|
||||
-
|
||||
message: '#^Method Appwrite\\Migration\\Version\\V15\:\:fixDocument\(\) should return Utopia\\Database\\Document but empty return statement found\.$#'
|
||||
identifier: return.empty
|
||||
count: 1
|
||||
path: src/Appwrite/Migration/Version/V15.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @return with type string\|false is not subtype of native type string\.$#'
|
||||
identifier: return.phpDocType
|
||||
count: 1
|
||||
path: src/Appwrite/Migration/Version/V15.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$tag on left side of \?\? always exists and is always null\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Migration/Version/V15.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V17\:\:documentsIterator\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/Migration/Version/V17.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V18\:\:documentsIterator\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 2
|
||||
path: src/Appwrite/Migration/Version/V18.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V19\:\:documentsIterator\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 4
|
||||
path: src/Appwrite/Migration/Version/V19.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Appwrite\\Migration\\Version\\V20\:\:documentsIterator\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 6
|
||||
path: src/Appwrite/Migration/Version/V20.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$query on left side of \?\? always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Migration/Version/V20.php
|
||||
|
||||
-
|
||||
message: '#^Method Appwrite\\Network\\Cors\:\:headers\(\) should return array\<string, string\> but returns array\<string, int\|string\>\.$#'
|
||||
identifier: return.type
|
||||
@@ -474,18 +378,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Logs/XList.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$device might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 5
|
||||
path: src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$path might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 5
|
||||
path: src/Appwrite/Platform/Modules/Functions/Http/Deployments/Download/Get.php
|
||||
|
||||
-
|
||||
message: '#^Call to method getAttribute\(\) on an unknown class Appwrite\\Platform\\Modules\\Functions\\Http\\Executions\\Utopia\\Database\\Document\.$#'
|
||||
identifier: class.notFound
|
||||
@@ -546,12 +438,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Functions/Http/Functions/Update.php
|
||||
|
||||
-
|
||||
message: '#^Undefined variable\: \$cpus$#'
|
||||
identifier: variable.undefined
|
||||
@@ -600,24 +486,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Proxy/Http/Rules/Verification/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$device might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 5
|
||||
path: src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$path might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 5
|
||||
path: src/Appwrite/Platform/Modules/Sites/Http/Deployments/Download/Get.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Sites/Http/Sites/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$iv might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
@@ -630,30 +498,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Files/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$allowedFileExtensions on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$antivirus on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$enabled on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$transformations on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Storage/Http/Buckets/Update.php
|
||||
|
||||
-
|
||||
message: '#^Caught class Appwrite\\Platform\\Modules\\Teams\\Http\\Memberships\\Throwable not found\.$#'
|
||||
identifier: class.notFound
|
||||
@@ -678,78 +522,6 @@ parameters:
|
||||
count: 14
|
||||
path: src/Appwrite/Platform/Modules/Teams/Http/Memberships/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$logBase might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$previewUrl in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$repositoryName in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$rule in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Authorize/External/Update.php
|
||||
|
||||
-
|
||||
message: '#^Result of method Utopia\\Http\\Response\:\:redirect\(\) \(void\) is used\.$#'
|
||||
identifier: method.void
|
||||
count: 2
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
|
||||
|
||||
-
|
||||
message: '#^Undefined variable\: \$redirectFailure$#'
|
||||
identifier: variable.undefined
|
||||
count: 2
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$redirectFailure in empty\(\) is never defined\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Callback/Get.php
|
||||
|
||||
-
|
||||
message: '#^Result of method Appwrite\\Utopia\\Response\:\:json\(\) \(void\) is used\.$#'
|
||||
identifier: method.void
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$logBase might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$previewUrl in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$repositoryName in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$rule in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/VCS/Http/GitHub/Events/Create.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$providerConfig on left side of \?\? always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
@@ -918,108 +690,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Method.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @param references unknown parameter\: \$services$#'
|
||||
identifier: parameter.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @return with type Appwrite\\SDK\\Specification\\Format is incompatible with native type array\.$#'
|
||||
identifier: return.phpDocType
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format.php
|
||||
|
||||
-
|
||||
message: '#^Cannot unset offset ''schema'' on array\{description\: ''No content'', content\?\: non\-empty\-array\<''''\|''\*/\*''\|''application/json''\|''image/\*''\|''image/png''\|''multipart/form\-data''\|''text/html''\|''text/plain'', array\{schema\: array\{''\$ref''\: non\-falsy\-string\}\}\|array\{schema\: array\{oneOf\: array\<array\{''\$ref''\: non\-falsy\-string\}\>\}\}\>\}\.$#'
|
||||
identifier: unset.offset
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Database\\Validator\\DatetimeValidator not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Validator\\Length not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Validator\\Mock not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Offset ''securityDefinitions'' on array\{openapi\: ''3\.0\.0'', info\: array\{version\: string, title\: string, description\: string, termsOfService\: string, contact\: array\{name\: string, url\: string, email\: string\}, license\: array\{name\: ''BSD\-3\-Clause'', url\: ''https\://raw…''\}\}, servers\: array\{array\{url\: string\}, array\{url\: string\}\}, paths\: array\{\}, tags\: array, components\: array\{schemas\: array\{\}, securitySchemes\: array\}, externalDocs\: array\{description\: string, url\: string\}\} in isset\(\) does not exist\.$#'
|
||||
identifier: isset.offset
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$desc on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$validator in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/OpenAPI3.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Database\\Validator\\DatetimeValidator not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Validator\\Length not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Class Utopia\\Validator\\Mock not found\.$#'
|
||||
identifier: class.notFound
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @var with type Appwrite\\SDK\\Method is not subtype of native type \*NEVER\*\.$#'
|
||||
identifier: varTag.nativeType
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$additionalMethods in empty\(\) always exists and is always falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$desc on left side of \?\?\= always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$sdk in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$validator in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/SDK/Specification/Format/Swagger2.php
|
||||
|
||||
-
|
||||
message: '#^PHPDoc tag @param has invalid value \(Document \$this\)\: Unexpected token "\$this", expected variable at offset 69 on line 4$#'
|
||||
identifier: phpDoc.parseError
|
||||
@@ -1032,196 +702,18 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Utopia/Database/Documents/User.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Databases\\Legacy\\DatabasesStringTypesTest\:\:\$setupCache through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 4
|
||||
path: tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsGuestTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsGuestTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsMemberTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsMemberTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\Databases\\Permissions\\LegacyPermissionsTeamTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/Databases/Permissions/LegacyPermissionsTeamTest.php
|
||||
|
||||
-
|
||||
message: '#^Method PHPUnit\\Framework\\TestCase\:\:addToAssertionCount\(\) invoked with 2 parameters, 1 required\.$#'
|
||||
identifier: arguments.count
|
||||
count: 1
|
||||
path: tests/e2e/Services/Functions/FunctionsCustomClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$largeTag might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 8
|
||||
path: tests/e2e/Services/Functions/FunctionsCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\+" between string and 1 results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: tests/e2e/Services/GraphQL/Legacy/AbuseTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$from in empty\(\) is never defined\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: tests/e2e/Services/GraphQL/MessagingTest.php
|
||||
|
||||
-
|
||||
message: '#^Method Tests\\E2E\\Services\\GraphQL\\StorageClientTest\:\:testGetFileDownload\(\) should return array but return statement is missing\.$#'
|
||||
identifier: return.missing
|
||||
count: 1
|
||||
path: tests/e2e/Services/GraphQL/StorageClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Method Tests\\E2E\\Services\\GraphQL\\StorageServerTest\:\:testGetFileDownload\(\) should return array but return statement is missing\.$#'
|
||||
identifier: return.missing
|
||||
count: 1
|
||||
path: tests/e2e/Services/GraphQL/StorageServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Binary operation "\+" between string and 1 results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: tests/e2e/Services/GraphQL/TablesDB/AbuseTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$from in empty\(\) is never defined\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: tests/e2e/Services/Messaging/MessagingConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$from in empty\(\) is never defined\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: tests/e2e/Services/Messaging/MessagingCustomClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$from in empty\(\) is never defined\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: tests/e2e/Services/Messaging/MessagingCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has an unused use \$databaseId\.$#'
|
||||
identifier: closure.unusedUse
|
||||
count: 6
|
||||
path: tests/e2e/Services/Migrations/MigrationsConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has an unused use \$tableId\.$#'
|
||||
identifier: closure.unusedUse
|
||||
count: 6
|
||||
path: tests/e2e/Services/Migrations/MigrationsConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$largeFile might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 8
|
||||
path: tests/e2e/Services/Storage/StorageConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$largeFile might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 8
|
||||
path: tests/e2e/Services/Storage/StorageCustomClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$largeFile might not be defined\.$#'
|
||||
identifier: variable.undefined
|
||||
count: 8
|
||||
path: tests/e2e/Services/Storage/StorageCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\TablesDB\\DatabasesStringTypesTest\:\:\$setupCache through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 4
|
||||
path: tests/e2e/Services/TablesDB/DatabasesStringTypesTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsGuestTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsGuestTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsMemberTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsMemberTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Tests\\E2E\\Services\\TablesDB\\Permissions\\TablesDBPermissionsTeamTest\:\:getIndexUrl\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
count: 1
|
||||
path: tests/e2e/Services/TablesDB/Permissions/TablesDBPermissionsTeamTest.php
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedHashedPasswordUsers through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 2
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedUser through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 7
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$cachedUserTarget through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 7
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userEmailUpdated through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 3
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userNameUpdated through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 3
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\Users\\UsersCustomServerTest\:\:\$userNumberUpdated through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 3
|
||||
path: tests/e2e/Services/Users/UsersCustomServerTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\VCS\\VCSConsoleClientTest\:\:\$cachedFunctionData through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 4
|
||||
path: tests/e2e/Services/VCS/VCSConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe access to private property Tests\\E2E\\Services\\VCS\\VCSConsoleClientTest\:\:\$cachedInstallationId through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateProperty
|
||||
count: 4
|
||||
path: tests/e2e/Services/VCS/VCSConsoleClientTest.php
|
||||
|
||||
-
|
||||
message: '#^Unsafe call to private method Tests\\Unit\\Auth\\KeyTest\:\:generateKey\(\) through static\:\:\.$#'
|
||||
identifier: staticClassAccess.privateMethod
|
||||
count: 3
|
||||
path: tests/unit/Auth/KeyTest.php
|
||||
|
||||
-
|
||||
message: '#^Call to an undefined method Utopia\\Queue\\Publisher\:\:getEvents\(\)\.$#'
|
||||
identifier: method.notFound
|
||||
|
||||
@@ -3,6 +3,7 @@ includes:
|
||||
|
||||
parameters:
|
||||
level: 3
|
||||
tmpDir: .phpstan-cache
|
||||
paths:
|
||||
- src
|
||||
- app
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Appwrite\Event\Message;
|
||||
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Usage extends Base
|
||||
final class Usage extends Base
|
||||
{
|
||||
/**
|
||||
* @param Document $project
|
||||
@@ -40,8 +40,7 @@ class Usage extends Base
|
||||
*/
|
||||
public static function fromArray(array $data): static
|
||||
{
|
||||
/** @phpstan-ignore new.static */
|
||||
return new static(
|
||||
return new self(
|
||||
project: new Document($data['project'] ?? []),
|
||||
metrics: $data['metrics'] ?? [],
|
||||
reduce: array_map(fn (array $doc) => new Document($doc), $data['reduce'] ?? []),
|
||||
|
||||
@@ -98,10 +98,9 @@ class Schema
|
||||
foreach ($routes as $route) {
|
||||
/** @var Route $route */
|
||||
|
||||
/** @var \Appwrite\SDK\Method $sdk */
|
||||
$sdk = $route->getLabel('sdk', false);
|
||||
|
||||
if (empty($sdk)) {
|
||||
if ($sdk === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -177,7 +176,7 @@ class Schema
|
||||
$required = $attr['required'];
|
||||
$default = $attr['default'];
|
||||
$escapedKey = str_replace('$', '', $key);
|
||||
$collections[$collectionId][$escapedKey] = [
|
||||
$collections[$databaseId][$collectionId][$escapedKey] = [
|
||||
'type' => Mapper::attribute(
|
||||
$type,
|
||||
$array,
|
||||
@@ -187,80 +186,82 @@ class Schema
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($collections as $collectionId => $attributes) {
|
||||
$objectType = new ObjectType([
|
||||
'name' => $collectionId,
|
||||
'fields' => \array_merge(
|
||||
["_id" => ['type' => Type::string()]],
|
||||
$attributes
|
||||
),
|
||||
]);
|
||||
$attributes = \array_merge(
|
||||
$attributes,
|
||||
Mapper::args('mutate')
|
||||
);
|
||||
|
||||
$queryFields[$collectionId . 'Get'] = [
|
||||
'type' => $objectType,
|
||||
'args' => Mapper::args('id'),
|
||||
'resolve' => Resolvers::documentGet(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['get'],
|
||||
)
|
||||
];
|
||||
$queryFields[$collectionId . 'List'] = [
|
||||
'type' => Type::listOf($objectType),
|
||||
'args' => Mapper::args('list'),
|
||||
'resolve' => Resolvers::documentList(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['list'],
|
||||
$params['list'],
|
||||
),
|
||||
'complexity' => $complexity,
|
||||
];
|
||||
|
||||
$mutationFields[$collectionId . 'Create'] = [
|
||||
'type' => $objectType,
|
||||
'args' => $attributes,
|
||||
'resolve' => Resolvers::documentCreate(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['create'],
|
||||
$params['create'],
|
||||
)
|
||||
];
|
||||
$mutationFields[$collectionId . 'Update'] = [
|
||||
'type' => $objectType,
|
||||
'args' => \array_merge(
|
||||
Mapper::args('id'),
|
||||
\array_map(
|
||||
fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']),
|
||||
foreach ($collections as $databaseId => $databaseCollections) {
|
||||
foreach ($databaseCollections as $collectionId => $attributes) {
|
||||
$objectType = new ObjectType([
|
||||
'name' => $collectionId,
|
||||
'fields' => \array_merge(
|
||||
["_id" => ['type' => Type::string()]],
|
||||
$attributes
|
||||
),
|
||||
]);
|
||||
$attributes = \array_merge(
|
||||
$attributes,
|
||||
Mapper::args('mutate')
|
||||
);
|
||||
|
||||
$queryFields[$collectionId . 'Get'] = [
|
||||
'type' => $objectType,
|
||||
'args' => Mapper::args('id'),
|
||||
'resolve' => Resolvers::documentGet(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['get'],
|
||||
)
|
||||
),
|
||||
'resolve' => Resolvers::documentUpdate(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['update'],
|
||||
$params['update'],
|
||||
)
|
||||
];
|
||||
$mutationFields[$collectionId . 'Delete'] = [
|
||||
'type' => Mapper::model('none'),
|
||||
'args' => Mapper::args('id'),
|
||||
'resolve' => Resolvers::documentDelete(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['delete'],
|
||||
)
|
||||
];
|
||||
];
|
||||
$queryFields[$collectionId . 'List'] = [
|
||||
'type' => Type::listOf($objectType),
|
||||
'args' => Mapper::args('list'),
|
||||
'resolve' => Resolvers::documentList(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['list'],
|
||||
$params['list'],
|
||||
),
|
||||
'complexity' => $complexity,
|
||||
];
|
||||
|
||||
$mutationFields[$collectionId . 'Create'] = [
|
||||
'type' => $objectType,
|
||||
'args' => $attributes,
|
||||
'resolve' => Resolvers::documentCreate(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['create'],
|
||||
$params['create'],
|
||||
)
|
||||
];
|
||||
$mutationFields[$collectionId . 'Update'] = [
|
||||
'type' => $objectType,
|
||||
'args' => \array_merge(
|
||||
Mapper::args('id'),
|
||||
\array_map(
|
||||
fn ($attr) => $attr['type'] = Type::getNullableType($attr['type']),
|
||||
$attributes
|
||||
)
|
||||
),
|
||||
'resolve' => Resolvers::documentUpdate(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['update'],
|
||||
$params['update'],
|
||||
)
|
||||
];
|
||||
$mutationFields[$collectionId . 'Delete'] = [
|
||||
'type' => Mapper::model('none'),
|
||||
'args' => Mapper::args('id'),
|
||||
'resolve' => Resolvers::documentDelete(
|
||||
$utopia,
|
||||
$databaseId,
|
||||
$collectionId,
|
||||
$urls['delete'],
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
$offset += $limit;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,13 @@ class Types
|
||||
*
|
||||
* @return Json
|
||||
*/
|
||||
public static function json(): Type
|
||||
public static function json(): Json
|
||||
{
|
||||
if (Registry::has(Json::class)) {
|
||||
return Registry::get(Json::class);
|
||||
$type = Registry::get(Json::class);
|
||||
if ($type instanceof Json) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
$type = new Json();
|
||||
Registry::set(Json::class, $type);
|
||||
@@ -28,12 +31,15 @@ class Types
|
||||
/**
|
||||
* Get the JSON type.
|
||||
*
|
||||
* @return Json
|
||||
* @return Assoc
|
||||
*/
|
||||
public static function assoc(): Type
|
||||
public static function assoc(): Assoc
|
||||
{
|
||||
if (Registry::has(Assoc::class)) {
|
||||
return Registry::get(Assoc::class);
|
||||
$type = Registry::get(Assoc::class);
|
||||
if ($type instanceof Assoc) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
$type = new Assoc();
|
||||
Registry::set(Assoc::class, $type);
|
||||
@@ -45,10 +51,13 @@ class Types
|
||||
*
|
||||
* @return InputFile
|
||||
*/
|
||||
public static function inputFile(): Type
|
||||
public static function inputFile(): InputFile
|
||||
{
|
||||
if (Registry::has(InputFile::class)) {
|
||||
return Registry::get(InputFile::class);
|
||||
$type = Registry::get(InputFile::class);
|
||||
if ($type instanceof InputFile) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
$type = new InputFile();
|
||||
Registry::set(InputFile::class, $type);
|
||||
|
||||
@@ -273,11 +273,9 @@ class Mapper
|
||||
case \Appwrite\Auth\Validator\Password::class:
|
||||
case \Appwrite\Event\Validator\Event::class:
|
||||
case \Appwrite\Event\Validator\FunctionEvent::class:
|
||||
case \Appwrite\Network\Validator\CNAME::class:
|
||||
case \Utopia\Emails\Validator\Email::class:
|
||||
case \Appwrite\Network\Validator\Redirect::class:
|
||||
case \Appwrite\Network\Validator\DNS::class:
|
||||
case \Appwrite\Network\Validator\Origin::class:
|
||||
case \Appwrite\Task\Validator\Cron::class:
|
||||
case \Appwrite\Utopia\Database\Validator\CustomId::class:
|
||||
case \Utopia\Database\Validator\Key::class:
|
||||
@@ -286,7 +284,7 @@ class Mapper
|
||||
case \Utopia\Validator\HexColor::class:
|
||||
case \Utopia\Validator\Host::class:
|
||||
case \Utopia\Validator\IP::class:
|
||||
case \Utopia\Validator\Origin::class:
|
||||
case \Appwrite\Network\Validator\Origin::class:
|
||||
case \Utopia\Validator\Text::class:
|
||||
case \Utopia\Validator\URL::class:
|
||||
case \Utopia\Validator\WhiteList::class:
|
||||
|
||||
@@ -13,6 +13,7 @@ use Utopia\Database\Exception\Limit;
|
||||
use Utopia\Database\Exception\Structure;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\PDO;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
abstract class Migration
|
||||
@@ -204,6 +205,30 @@ abstract class Migration
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Query> $queries
|
||||
* @return \Generator<int, Document>
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function documentsIterator(string $collection, array $queries = []): \Generator
|
||||
{
|
||||
$offset = 0;
|
||||
|
||||
do {
|
||||
$documents = $this->dbForProject->find($collection, [
|
||||
...$queries,
|
||||
Query::limit($this->limit),
|
||||
Query::offset($offset),
|
||||
]);
|
||||
|
||||
foreach ($documents as $document) {
|
||||
yield $document;
|
||||
}
|
||||
|
||||
$offset += \count($documents);
|
||||
} while (\count($documents) === $this->limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates collection from the config collection.
|
||||
*
|
||||
|
||||
@@ -1224,7 +1224,7 @@ class V15 extends Migration
|
||||
* @param \Utopia\Database\Document $document
|
||||
* @return \Utopia\Database\Document
|
||||
*/
|
||||
protected function fixDocument(Document $document)
|
||||
protected function fixDocument(Document $document): Document
|
||||
{
|
||||
switch ($document->getCollection()) {
|
||||
case 'cache':
|
||||
@@ -1234,7 +1234,7 @@ class V15 extends Migration
|
||||
* skipping migration for 'cache' and 'variables'.
|
||||
* 'users' already migrated.
|
||||
*/
|
||||
return;
|
||||
return $document;
|
||||
|
||||
case '_metadata':
|
||||
/**
|
||||
@@ -1480,7 +1480,6 @@ class V15 extends Migration
|
||||
* Filter from the 'encrypt' filter.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string|false
|
||||
*/
|
||||
protected function encryptFilter(string $value): string
|
||||
{
|
||||
@@ -1492,8 +1491,8 @@ class V15 extends Migration
|
||||
'data' => OpenSSL::encrypt($value, OpenSSL::CIPHER_AES_128_GCM, $key, 0, $iv, $tag),
|
||||
'method' => OpenSSL::CIPHER_AES_128_GCM,
|
||||
'iv' => \bin2hex($iv),
|
||||
'tag' => \bin2hex($tag ?? ''),
|
||||
'tag' => \bin2hex($tag),
|
||||
'version' => '1',
|
||||
]);
|
||||
]) ?: '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,7 +452,7 @@ class V20 extends Migration
|
||||
Query::equal('period', ['1d']),
|
||||
]);
|
||||
|
||||
$value = $query ?? 0;
|
||||
$value = $query;
|
||||
$this->createInfMetric($to, $value);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,16 +88,11 @@ class Get extends Action
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'output':
|
||||
$path = $deployment->getAttribute('buildPath', '');
|
||||
$device = $deviceForBuilds;
|
||||
break;
|
||||
case 'source':
|
||||
$path = $deployment->getAttribute('sourcePath', '');
|
||||
$device = $deviceForFunctions;
|
||||
break;
|
||||
}
|
||||
[$path, $device] = match ($type) {
|
||||
'output' => [$deployment->getAttribute('buildPath', ''), $deviceForBuilds],
|
||||
'source' => [$deployment->getAttribute('sourcePath', ''), $deviceForFunctions],
|
||||
default => throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid deployment download type.'),
|
||||
};
|
||||
|
||||
if (!$device->exists($path)) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
|
||||
@@ -170,8 +170,6 @@ class Update extends Base
|
||||
$runtime = $function->getAttribute('runtime');
|
||||
}
|
||||
|
||||
$enabled ??= $function->getAttribute('enabled', true);
|
||||
|
||||
$repositoryId = $function->getAttribute('repositoryId', '');
|
||||
$repositoryInternalId = $function->getAttribute('repositoryInternalId', '');
|
||||
|
||||
|
||||
@@ -87,16 +87,11 @@ class Get extends Action
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
case 'output':
|
||||
$path = $deployment->getAttribute('buildPath', '');
|
||||
$device = $deviceForBuilds;
|
||||
break;
|
||||
case 'source':
|
||||
$path = $deployment->getAttribute('sourcePath', '');
|
||||
$device = $deviceForSites;
|
||||
break;
|
||||
}
|
||||
[$path, $device] = match ($type) {
|
||||
'output' => [$deployment->getAttribute('buildPath', ''), $deviceForBuilds],
|
||||
'source' => [$deployment->getAttribute('sourcePath', ''), $deviceForSites],
|
||||
default => throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Invalid deployment download type.'),
|
||||
};
|
||||
|
||||
if (!$device->exists($path)) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
|
||||
@@ -172,8 +172,6 @@ class Update extends Base
|
||||
$framework = $site->getAttribute('framework');
|
||||
}
|
||||
|
||||
$enabled ??= $site->getAttribute('enabled', true);
|
||||
|
||||
$repositoryId = $site->getAttribute('repositoryId', '');
|
||||
$repositoryInternalId = $site->getAttribute('repositoryInternalId', '');
|
||||
|
||||
|
||||
@@ -99,12 +99,8 @@ class Update extends Action
|
||||
|
||||
$permissions ??= $bucket->getPermissions();
|
||||
$maximumFileSize ??= $bucket->getAttribute('maximumFileSize', (int) System::getEnv('_APP_STORAGE_LIMIT', 0));
|
||||
$allowedFileExtensions ??= $bucket->getAttribute('allowedFileExtensions', []);
|
||||
$enabled ??= $bucket->getAttribute('enabled', true);
|
||||
$encryption ??= $bucket->getAttribute('encryption', true);
|
||||
$antivirus ??= $bucket->getAttribute('antivirus', true);
|
||||
$compression ??= $bucket->getAttribute('compression', Compression::NONE);
|
||||
$transformations ??= $bucket->getAttribute('transformations', true);
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
$permissions = Permission::aggregate($permissions);
|
||||
|
||||
+1
-4
@@ -110,10 +110,7 @@ class Update extends Action
|
||||
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
|
||||
|
||||
try {
|
||||
$providerRepositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
||||
if (empty($providerRepositoryName)) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
$providerRepositoryName = $github->getRepositoryName($providerRepositoryId);
|
||||
} catch (RepositoryNotFound $e) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ class Get extends Action
|
||||
}
|
||||
|
||||
$state = \json_decode($state, true);
|
||||
$redirectFailure = $state['failure'] ?? '';
|
||||
$projectId = $state['projectId'] ?? '';
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
@@ -74,10 +75,11 @@ class Get extends Action
|
||||
|
||||
if (!empty($redirectFailure)) {
|
||||
$separator = \str_contains($redirectFailure, '?') ? '&' : ':';
|
||||
return $response
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($redirectFailure . $separator . \http_build_query(['error' => $error]));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND, $error);
|
||||
@@ -165,10 +167,11 @@ class Get extends Action
|
||||
|
||||
if (!empty($redirectFailure)) {
|
||||
$separator = \str_contains($redirectFailure, '?') ? '&' : ':';
|
||||
return $response
|
||||
$response
|
||||
->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
->addHeader('Pragma', 'no-cache')
|
||||
->redirect($redirectFailure . $separator . \http_build_query(['error' => $error]));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $error);
|
||||
|
||||
@@ -49,6 +49,8 @@ trait Deployment
|
||||
) {
|
||||
$errors = [];
|
||||
foreach ($repositories as $repository) {
|
||||
$logBase = 'vcs.github.event.repo.unknown';
|
||||
|
||||
try {
|
||||
$repositoryId = $repository->getId();
|
||||
$projectId = $repository->getAttribute('projectId');
|
||||
@@ -107,18 +109,11 @@ trait Deployment
|
||||
|
||||
$owner = $github->getOwnerName($providerInstallationId) ?? '';
|
||||
try {
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
||||
if (empty($repositoryName)) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId);
|
||||
} catch (RepositoryNotFound $e) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (empty($repositoryName)) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isAuthorized = !$external;
|
||||
|
||||
if (!$isAuthorized && !empty($providerPullRequestId)) {
|
||||
@@ -291,10 +286,7 @@ trait Deployment
|
||||
|
||||
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
|
||||
try {
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
||||
if (empty($repositoryName)) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId);
|
||||
} catch (RepositoryNotFound $e) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
@@ -501,7 +493,7 @@ trait Deployment
|
||||
$rule = $authorization->skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId));
|
||||
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
|
||||
$previewUrl = !$rule->isEmpty() ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
|
||||
|
||||
if (!empty($previewUrl)) {
|
||||
$comment = new Comment($platform);
|
||||
@@ -524,10 +516,7 @@ trait Deployment
|
||||
|
||||
$providerRepositoryId = $repository->getAttribute('providerRepositoryId');
|
||||
try {
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
||||
if (empty($repositoryName)) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
$repositoryName = $github->getRepositoryName($providerRepositoryId);
|
||||
} catch (RepositoryNotFound $e) {
|
||||
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ class Create extends Action
|
||||
default => null,
|
||||
};
|
||||
|
||||
return $response->json($parsedPayload);
|
||||
$response->json($parsedPayload);
|
||||
}
|
||||
|
||||
protected function preprocessEvent(Request $request)
|
||||
|
||||
@@ -204,9 +204,6 @@ abstract class Format
|
||||
*
|
||||
* Get services value
|
||||
*
|
||||
* @param array $services
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function getServices(): array
|
||||
{
|
||||
|
||||
@@ -79,8 +79,8 @@ class OpenAPI3 extends Format
|
||||
$output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '<YOUR_API_KEY>'];
|
||||
}
|
||||
|
||||
if (isset($output['securityDefinitions']['JWT'])) {
|
||||
$output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => '<YOUR_JWT>'];
|
||||
if (isset($output['components']['securitySchemes']['JWT'])) {
|
||||
$output['components']['securitySchemes']['JWT']['x-appwrite'] = ['demo' => '<YOUR_JWT>'];
|
||||
}
|
||||
|
||||
if (isset($output['components']['securitySchemes']['Locale'])) {
|
||||
@@ -99,7 +99,7 @@ class OpenAPI3 extends Format
|
||||
|
||||
$sdk = $route->getLabel('sdk', false);
|
||||
|
||||
if (empty($sdk)) {
|
||||
if ($sdk === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -125,7 +125,9 @@ class OpenAPI3 extends Format
|
||||
|
||||
$namespace = $sdk->getNamespace() ?? 'default';
|
||||
|
||||
$desc ??= '';
|
||||
if ($desc === null) {
|
||||
$desc = '';
|
||||
}
|
||||
$descContents = \str_ends_with($desc, '.md') ? \file_get_contents($desc) : $desc;
|
||||
|
||||
$temp = [
|
||||
@@ -163,7 +165,7 @@ class OpenAPI3 extends Format
|
||||
];
|
||||
}
|
||||
|
||||
if (!empty($additionalMethods)) {
|
||||
if (\is_array($additionalMethods) && \count($additionalMethods) > 0) {
|
||||
$temp['x-appwrite']['methods'] = [];
|
||||
foreach ($additionalMethods as $methodObj) {
|
||||
/** @var Method $methodObj */
|
||||
@@ -329,7 +331,7 @@ class OpenAPI3 extends Format
|
||||
|
||||
if (($response->getCode() ?? 500) === 204) {
|
||||
$temp['responses'][(string)$response->getCode() ?? '500']['description'] = 'No content';
|
||||
unset($temp['responses'][(string)$response->getCode() ?? '500']['schema']);
|
||||
unset($temp['responses'][(string)$response->getCode() ?? '500']['content']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,7 +385,7 @@ class OpenAPI3 extends Format
|
||||
$validator = $validator->getValidator();
|
||||
}
|
||||
|
||||
$class = !empty($validator)
|
||||
$class = $validator instanceof Validator
|
||||
? \get_class($validator)
|
||||
: '';
|
||||
|
||||
@@ -431,7 +433,7 @@ class OpenAPI3 extends Format
|
||||
$node['schema']['type'] = $validator->getType();
|
||||
$node['schema']['x-example'] = ($param['example'] ?? '') ?: '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
|
||||
break;
|
||||
case \Utopia\Database\Validator\DatetimeValidator::class:
|
||||
case \Utopia\Database\Validator\Datetime::class:
|
||||
$node['schema']['type'] = $validator->getType();
|
||||
$node['schema']['format'] = 'datetime';
|
||||
$node['schema']['x-example'] = ($param['example'] ?? '') ?: Model::TYPE_DATETIME_EXAMPLE;
|
||||
@@ -463,7 +465,6 @@ class OpenAPI3 extends Format
|
||||
$node['schema']['x-example'] = ($param['example'] ?? '') ?: 'https://example.com';
|
||||
break;
|
||||
case \Utopia\Validator\JSON::class:
|
||||
case \Utopia\Validator\Mock::class:
|
||||
case \Utopia\Validator\Assoc::class:
|
||||
$param['default'] = (empty($param['default'])) ? new \stdClass() : $param['default'];
|
||||
$node['schema']['type'] = 'object';
|
||||
@@ -563,12 +564,6 @@ class OpenAPI3 extends Format
|
||||
$node['schema']['x-example'] = $param['example'];
|
||||
}
|
||||
break;
|
||||
case \Utopia\Validator\Length::class:
|
||||
$node['schema']['type'] = $validator->getType();
|
||||
if (!empty($param['example'])) {
|
||||
$node['schema']['x-example'] = $param['example'];
|
||||
}
|
||||
break;
|
||||
case \Utopia\Validator\WhiteList::class:
|
||||
if ($array) {
|
||||
$validator = $validator->getValidator();
|
||||
|
||||
@@ -96,10 +96,9 @@ class Swagger2 extends Format
|
||||
|
||||
$scope = $route->getLabel('scope', '');
|
||||
|
||||
/** @var Method $sdk */
|
||||
$sdk = $route->getLabel('sdk', false);
|
||||
|
||||
if (empty($sdk)) {
|
||||
if ($sdk === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -127,7 +126,9 @@ class Swagger2 extends Format
|
||||
$sdkPlatforms = array_values(array_unique($sdkPlatforms));
|
||||
$namespace = $sdk->getNamespace() ?? 'default';
|
||||
|
||||
$desc ??= '';
|
||||
if ($desc === null) {
|
||||
$desc = '';
|
||||
}
|
||||
$descContents = \str_ends_with($desc, '.md') ? \file_get_contents($desc) : $desc;
|
||||
|
||||
$temp = [
|
||||
@@ -171,7 +172,7 @@ class Swagger2 extends Format
|
||||
$temp['produces'][] = $produces;
|
||||
}
|
||||
|
||||
if (!empty($additionalMethods)) {
|
||||
if (\is_array($additionalMethods) && \count($additionalMethods) > 0) {
|
||||
$temp['x-appwrite']['methods'] = [];
|
||||
foreach ($additionalMethods as $methodObj) {
|
||||
/** @var Method $methodObj */
|
||||
@@ -388,7 +389,7 @@ class Swagger2 extends Format
|
||||
$validator = $validator->getValidator();
|
||||
}
|
||||
|
||||
$class = !empty($validator)
|
||||
$class = $validator instanceof Validator
|
||||
? \get_class($validator)
|
||||
: '';
|
||||
|
||||
@@ -436,7 +437,7 @@ class Swagger2 extends Format
|
||||
$node['type'] = $validator->getType();
|
||||
$node['x-example'] = ($param['example'] ?? '') ?: '<' . \strtoupper(Template::fromCamelCaseToSnake($node['name'])) . '>';
|
||||
break;
|
||||
case \Utopia\Database\Validator\DatetimeValidator::class:
|
||||
case \Utopia\Database\Validator\Datetime::class:
|
||||
$node['type'] = $validator->getType();
|
||||
$node['format'] = 'datetime';
|
||||
$node['x-example'] = ($param['example'] ?? '') ?: Model::TYPE_DATETIME_EXAMPLE;
|
||||
@@ -479,7 +480,6 @@ class Swagger2 extends Format
|
||||
}
|
||||
break;
|
||||
case \Utopia\Validator\JSON::class:
|
||||
case \Utopia\Validator\Mock::class:
|
||||
case \Utopia\Validator\Assoc::class:
|
||||
$node['type'] = 'object';
|
||||
$node['default'] = (empty($param['default'])) ? new \stdClass() : $param['default'];
|
||||
@@ -552,12 +552,6 @@ class Swagger2 extends Format
|
||||
$node['x-example'] = $param['example'];
|
||||
}
|
||||
break;
|
||||
case \Utopia\Validator\Length::class:
|
||||
$node['type'] = $validator->getType();
|
||||
if (!empty($param['example'])) {
|
||||
$node['x-example'] = $param['example'];
|
||||
}
|
||||
break;
|
||||
case \Utopia\Validator\WhiteList::class:
|
||||
if ($array) {
|
||||
$validator = $validator->getValidator();
|
||||
|
||||
@@ -29,8 +29,8 @@ class DatabasesStringTypesTest extends Scope
|
||||
protected function setupDatabaseAndCollection(): array
|
||||
{
|
||||
$cacheKey = $this->getProject()['$id'] ?? 'default';
|
||||
if (!empty(static::$setupCache[$cacheKey])) {
|
||||
return static::$setupCache[$cacheKey];
|
||||
if (!empty(self::$setupCache[$cacheKey])) {
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
@@ -135,12 +135,12 @@ class DatabasesStringTypesTest extends Scope
|
||||
// Wait for all attributes to be available
|
||||
$this->waitForAllAttributes($databaseId, $collectionId);
|
||||
|
||||
static::$setupCache[$cacheKey] = [
|
||||
self::$setupCache[$cacheKey] = [
|
||||
'databaseId' => $databaseId,
|
||||
'collectionId' => $collectionId,
|
||||
];
|
||||
|
||||
return static::$setupCache[$cacheKey];
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
public function testCreateDatabase(): void
|
||||
|
||||
@@ -45,6 +45,12 @@ trait DatabasesPermissionsBase
|
||||
return $recordId ? "{$base}/{$recordId}" : $base;
|
||||
}
|
||||
|
||||
protected function getIndexUrl(string $databaseId, string $containerId, string $indexId = ''): string
|
||||
{
|
||||
$base = "{$this->getContainerUrl($databaseId, $containerId)}/indexes";
|
||||
return $indexId ? "{$base}/{$indexId}" : $base;
|
||||
}
|
||||
|
||||
// User Management Methods
|
||||
public function createUser(string $id, string $email, string $password = 'test123!'): array
|
||||
{
|
||||
|
||||
@@ -414,7 +414,7 @@ class FunctionsCustomClientTest extends Scope
|
||||
'offset' => 2
|
||||
]);
|
||||
$this->assertEquals(200, $templatesOffset['headers']['status-code']);
|
||||
$this->addToAssertionCount(1, $templatesOffset['body']['templates']);
|
||||
$this->addToAssertionCount(1);
|
||||
$this->assertEquals($templates['body']['templates'][2]['id'], $templatesOffset['body']['templates'][0]['id']);
|
||||
|
||||
// List templates with filters
|
||||
|
||||
@@ -1003,6 +1003,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
];
|
||||
$id = '';
|
||||
$largeTag = null;
|
||||
while (!feof($handle)) {
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-fx.tar.gz');
|
||||
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
|
||||
|
||||
@@ -409,7 +409,7 @@ class MessagingTest extends Scope
|
||||
$apiKey = $emailDSN->getPassword();
|
||||
$domain = $emailDSN->getUser();
|
||||
|
||||
if (empty($to) || empty($from) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
|
||||
if (empty($to) || empty($fromName) || empty($fromEmail) || empty($apiKey) || empty($domain) || empty($isEuRegion)) {
|
||||
$this->markTestSkipped('Email provider not configured');
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +229,8 @@ class StorageClientTest extends Scope
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertEquals(47218, \strlen($file['body']));
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -291,6 +291,8 @@ class StorageServerTest extends Scope
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertEquals(47218, \strlen($file['body']));
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2241,7 +2241,7 @@ trait MessagingBase
|
||||
$authKey = $smsDSN->getPassword();
|
||||
$templateId = $smsDSN->getParam('templateId');
|
||||
|
||||
if (empty($to) || empty($from) || empty($senderId) || empty($authKey)) {
|
||||
if (empty($to) || empty($senderId) || empty($authKey)) {
|
||||
$this->markTestSkipped('SMS provider not configured');
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ trait MigrationsBase
|
||||
*/
|
||||
protected function setupMigrationDatabase(): array
|
||||
{
|
||||
if (!empty(static::$cachedDatabaseData)) {
|
||||
return static::$cachedDatabaseData;
|
||||
if (!empty(self::$cachedDatabaseData)) {
|
||||
return self::$cachedDatabaseData;
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/databases', [
|
||||
@@ -81,11 +81,11 @@ trait MigrationsBase
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
static::$cachedDatabaseData = [
|
||||
self::$cachedDatabaseData = [
|
||||
'databaseId' => $response['body']['$id'],
|
||||
];
|
||||
|
||||
return static::$cachedDatabaseData;
|
||||
return self::$cachedDatabaseData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,8 +94,8 @@ trait MigrationsBase
|
||||
*/
|
||||
protected function setupMigrationTable(): array
|
||||
{
|
||||
if (!empty(static::$cachedTableData)) {
|
||||
return static::$cachedTableData;
|
||||
if (!empty(self::$cachedTableData)) {
|
||||
return self::$cachedTableData;
|
||||
}
|
||||
|
||||
// Ensure database exists first
|
||||
@@ -141,12 +141,12 @@ trait MigrationsBase
|
||||
$this->assertEquals('available', $response['body']['status']);
|
||||
}, 5000, 500);
|
||||
|
||||
static::$cachedTableData = [
|
||||
self::$cachedTableData = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
|
||||
return static::$cachedTableData;
|
||||
return self::$cachedTableData;
|
||||
}
|
||||
|
||||
public function performMigrationSync(array $body): array
|
||||
@@ -670,7 +670,7 @@ trait MigrationsBase
|
||||
]);
|
||||
|
||||
// Clear the cache since we cleaned up
|
||||
static::$cachedDatabaseData = [];
|
||||
self::$cachedDatabaseData = [];
|
||||
}
|
||||
|
||||
public function testAppwriteMigrationDatabasesRow(): void
|
||||
@@ -757,8 +757,8 @@ trait MigrationsBase
|
||||
]);
|
||||
|
||||
// Clear the caches since we cleaned up
|
||||
static::$cachedDatabaseData = [];
|
||||
static::$cachedTableData = [];
|
||||
self::$cachedDatabaseData = [];
|
||||
self::$cachedTableData = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1331,7 +1331,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($missingColumn) {
|
||||
$migrationId = $missingColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1363,7 +1363,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($missingColumn, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($missingColumn) {
|
||||
$migrationId = $missingColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1395,7 +1395,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($irrelevantColumn, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($irrelevantColumn) {
|
||||
$migrationId = $irrelevantColumn['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1422,7 +1422,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($migration) {
|
||||
$migrationId = $migration['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -1464,7 +1464,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($migration) {
|
||||
$migrationId = $migration['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
@@ -4018,7 +4018,7 @@ trait MigrationsBase
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEventually(function () use ($migration, $databaseId, $tableId) {
|
||||
$this->assertEventually(function () use ($migration) {
|
||||
$migrationId = $migration['body']['$id'];
|
||||
$migration = $this->client->call(Client::METHOD_GET, '/migrations/'.$migrationId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
||||
@@ -3045,7 +3045,11 @@ class RealtimeCustomClientTest extends Scope
|
||||
$event = null;
|
||||
$deadline = \time() + 10;
|
||||
while (\time() < $deadline) {
|
||||
$raw = $client->receive();
|
||||
try {
|
||||
$raw = $client->receive();
|
||||
} catch (\WebSocket\ConnectionException) {
|
||||
break;
|
||||
}
|
||||
$msg = json_decode($raw, true);
|
||||
if (($msg['type'] ?? '') === 'event' && \in_array($updateEvent, $msg['data']['events'] ?? [])) {
|
||||
$event = $msg;
|
||||
|
||||
@@ -97,6 +97,7 @@ trait StorageBase
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
];
|
||||
$id = '';
|
||||
$largeFile = null;
|
||||
while (!feof($handle)) {
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4');
|
||||
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
|
||||
@@ -132,7 +133,7 @@ trait StorageBase
|
||||
self::$cachedBucketFile[$cacheKey] = [
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $file['body']['$id'],
|
||||
'largeFileId' => $largeFile['body']['$id'],
|
||||
'largeFileId' => $largeFile['body']['$id'] ?? '',
|
||||
'largeBucketId' => $bucket2['body']['$id'],
|
||||
'webpFileId' => $webpFile['body']['$id']
|
||||
];
|
||||
@@ -261,6 +262,7 @@ trait StorageBase
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
];
|
||||
$id = '';
|
||||
$largeFile = null;
|
||||
while (!feof($handle)) {
|
||||
$curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4');
|
||||
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size;
|
||||
|
||||
@@ -29,8 +29,8 @@ class DatabasesStringTypesTest extends Scope
|
||||
protected function setupDatabaseAndTable(): array
|
||||
{
|
||||
$cacheKey = $this->getProject()['$id'] ?? 'default';
|
||||
if (!empty(static::$setupCache[$cacheKey])) {
|
||||
return static::$setupCache[$cacheKey];
|
||||
if (!empty(self::$setupCache[$cacheKey])) {
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
$projectId = $this->getProject()['$id'];
|
||||
@@ -131,7 +131,7 @@ class DatabasesStringTypesTest extends Scope
|
||||
|
||||
// Cache before waiting so that if waitForAllAttributes times out,
|
||||
// subsequent calls don't try to re-create the same columns (causing 409)
|
||||
static::$setupCache[$cacheKey] = [
|
||||
self::$setupCache[$cacheKey] = [
|
||||
'databaseId' => $databaseId,
|
||||
'tableId' => $tableId,
|
||||
];
|
||||
@@ -139,7 +139,7 @@ class DatabasesStringTypesTest extends Scope
|
||||
// Wait for all columns to be available
|
||||
$this->waitForAllAttributes($databaseId, $tableId);
|
||||
|
||||
return static::$setupCache[$cacheKey];
|
||||
return self::$setupCache[$cacheKey];
|
||||
}
|
||||
|
||||
public function testCreateDatabase(): void
|
||||
|
||||
@@ -28,8 +28,8 @@ trait UsersBase
|
||||
protected function setupUser(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
if (!empty(static::$cachedUser[$projectId])) {
|
||||
return static::$cachedUser[$projectId];
|
||||
if (!empty(self::$cachedUser[$projectId])) {
|
||||
return self::$cachedUser[$projectId];
|
||||
}
|
||||
|
||||
$user = $this->client->call(Client::METHOD_POST, '/users', array_merge([
|
||||
@@ -52,16 +52,16 @@ trait UsersBase
|
||||
]);
|
||||
|
||||
if (!empty($response['body']['users'])) {
|
||||
static::$cachedUser[$projectId] = ['userId' => $response['body']['users'][0]['$id']];
|
||||
return static::$cachedUser[$projectId];
|
||||
self::$cachedUser[$projectId] = ['userId' => $response['body']['users'][0]['$id']];
|
||||
return self::$cachedUser[$projectId];
|
||||
}
|
||||
}
|
||||
|
||||
if ($user['headers']['status-code'] === 201) {
|
||||
static::$cachedUser[$projectId] = ['userId' => $user['body']['$id']];
|
||||
self::$cachedUser[$projectId] = ['userId' => $user['body']['$id']];
|
||||
}
|
||||
|
||||
return static::$cachedUser[$projectId];
|
||||
return self::$cachedUser[$projectId];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +90,7 @@ trait UsersBase
|
||||
protected function setupHashedPasswordUsers(): void
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
if (!empty(static::$cachedHashedPasswordUsers[$projectId])) {
|
||||
if (!empty(self::$cachedHashedPasswordUsers[$projectId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ trait UsersBase
|
||||
'passwordSignerKey' => 'XyEKE9RcTDeLEsL/RjwPDBv/RqDl8fb3gpYEOQaPihbxf1ZAtSOHCjuAAa7Q3oHpCYhXSN9tizHgVOwn6krflQ==',
|
||||
]);
|
||||
|
||||
static::$cachedHashedPasswordUsers[$projectId] = true;
|
||||
self::$cachedHashedPasswordUsers[$projectId] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,8 +189,8 @@ trait UsersBase
|
||||
protected function setupUserTarget(): array
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
if (!empty(static::$cachedUserTarget[$projectId])) {
|
||||
return static::$cachedUserTarget[$projectId];
|
||||
if (!empty(self::$cachedUserTarget[$projectId])) {
|
||||
return self::$cachedUserTarget[$projectId];
|
||||
}
|
||||
|
||||
$data = $this->setupUser();
|
||||
@@ -233,10 +233,10 @@ trait UsersBase
|
||||
]);
|
||||
|
||||
if ($response['headers']['status-code'] === 201) {
|
||||
static::$cachedUserTarget[$projectId] = $response['body'];
|
||||
self::$cachedUserTarget[$projectId] = $response['body'];
|
||||
}
|
||||
|
||||
return static::$cachedUserTarget[$projectId] ?? [];
|
||||
return self::$cachedUserTarget[$projectId] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +247,7 @@ trait UsersBase
|
||||
$data = $this->setupUser();
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
if (static::$userNameUpdated) {
|
||||
if (self::$userNameUpdated) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ trait UsersBase
|
||||
'name' => 'Updated name',
|
||||
]);
|
||||
|
||||
static::$userNameUpdated = true;
|
||||
self::$userNameUpdated = true;
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ trait UsersBase
|
||||
$data = $this->setupUser();
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
if (static::$userEmailUpdated) {
|
||||
if (self::$userEmailUpdated) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ trait UsersBase
|
||||
'email' => 'users.service@updated.com',
|
||||
]);
|
||||
|
||||
static::$userEmailUpdated = true;
|
||||
self::$userEmailUpdated = true;
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ trait UsersBase
|
||||
$data = $this->setupUser();
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
if (static::$userNumberUpdated) {
|
||||
if (self::$userNumberUpdated) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ trait UsersBase
|
||||
'number' => '+910000000000',
|
||||
]);
|
||||
|
||||
static::$userNumberUpdated = true;
|
||||
self::$userNumberUpdated = true;
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ trait UsersBase
|
||||
|
||||
// Cache the user ID for other tests
|
||||
$projectId = $this->getProject()['$id'];
|
||||
static::$cachedUser[$projectId] = ['userId' => $body['$id']];
|
||||
self::$cachedUser[$projectId] = ['userId' => $body['$id']];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1274,7 +1274,7 @@ trait UsersBase
|
||||
$this->assertEquals($user['body']['name'], 'Updated name');
|
||||
|
||||
// Mark name as updated for search tests
|
||||
static::$userNameUpdated = true;
|
||||
self::$userNameUpdated = true;
|
||||
}
|
||||
|
||||
public function testUpdateUserNameSearch(): void
|
||||
@@ -1357,7 +1357,7 @@ trait UsersBase
|
||||
$this->assertEquals($user['body']['email'], 'users.service@updated.com');
|
||||
|
||||
// Mark email as updated for search tests
|
||||
static::$userEmailUpdated = true;
|
||||
self::$userEmailUpdated = true;
|
||||
}
|
||||
|
||||
public function testUpdateUserEmailSearch(): void
|
||||
@@ -1645,7 +1645,7 @@ trait UsersBase
|
||||
$this->assertEquals($response['body']['type'], $errorType);
|
||||
|
||||
// Mark phone as updated for search tests
|
||||
static::$userNumberUpdated = true;
|
||||
self::$userNumberUpdated = true;
|
||||
}
|
||||
|
||||
public function testUpdateTwoUsersPhoneToEmpty(): void
|
||||
@@ -1954,7 +1954,7 @@ trait UsersBase
|
||||
|
||||
// Cache for other tests
|
||||
$projectId = $this->getProject()['$id'];
|
||||
static::$cachedUserTarget[$projectId] = $response['body'];
|
||||
self::$cachedUserTarget[$projectId] = $response['body'];
|
||||
}
|
||||
|
||||
public function testUpdateUserTarget(): void
|
||||
@@ -1973,7 +1973,7 @@ trait UsersBase
|
||||
|
||||
// Update cache with new data
|
||||
$projectId = $this->getProject()['$id'];
|
||||
static::$cachedUserTarget[$projectId] = $response['body'];
|
||||
self::$cachedUserTarget[$projectId] = $response['body'];
|
||||
}
|
||||
|
||||
public function testListUserTarget(): void
|
||||
@@ -2014,7 +2014,7 @@ trait UsersBase
|
||||
|
||||
// Clear cached target since it was deleted
|
||||
$projectId = $this->getProject()['$id'];
|
||||
unset(static::$cachedUserTarget[$projectId]);
|
||||
unset(self::$cachedUserTarget[$projectId]);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/users/' . $data['userId'] . '/targets', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
||||
@@ -37,8 +37,8 @@ class VCSConsoleClientTest extends Scope
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
if (!empty(static::$cachedInstallationId[$projectId])) {
|
||||
return static::$cachedInstallationId[$projectId];
|
||||
if (!empty(self::$cachedInstallationId[$projectId])) {
|
||||
return self::$cachedInstallationId[$projectId];
|
||||
}
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/mock/github/callback', array_merge([
|
||||
@@ -48,8 +48,8 @@ class VCSConsoleClientTest extends Scope
|
||||
'projectId' => $projectId,
|
||||
]);
|
||||
|
||||
static::$cachedInstallationId[$projectId] = $response['body']['installationId'];
|
||||
return static::$cachedInstallationId[$projectId];
|
||||
self::$cachedInstallationId[$projectId] = $response['body']['installationId'];
|
||||
return self::$cachedInstallationId[$projectId];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,8 +60,8 @@ class VCSConsoleClientTest extends Scope
|
||||
{
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
if (!empty(static::$cachedFunctionData[$projectId])) {
|
||||
return static::$cachedFunctionData[$projectId];
|
||||
if (!empty(self::$cachedFunctionData[$projectId])) {
|
||||
return self::$cachedFunctionData[$projectId];
|
||||
}
|
||||
|
||||
$installationId = $this->setupInstallation();
|
||||
@@ -86,12 +86,12 @@ class VCSConsoleClientTest extends Scope
|
||||
'providerBranch' => 'main',
|
||||
]);
|
||||
|
||||
static::$cachedFunctionData[$projectId] = [
|
||||
self::$cachedFunctionData[$projectId] = [
|
||||
'installationId' => $installationId,
|
||||
'functionId' => $function['body']['$id']
|
||||
];
|
||||
|
||||
return static::$cachedFunctionData[$projectId];
|
||||
return self::$cachedFunctionData[$projectId];
|
||||
}
|
||||
|
||||
public function testGitHubAuthorize(): void
|
||||
|
||||
@@ -25,7 +25,7 @@ class KeyTest extends TestCase
|
||||
$roleScopes = Config::getParam('roles', [])[User::ROLE_APPS]['scopes'];
|
||||
$guestRoleScopes = Config::getParam('roles', [])[User::ROLE_GUESTS]['scopes'];
|
||||
|
||||
$key = static::generateKey($projectId, $usage, $scopes);
|
||||
$key = self::generateKey($projectId, $usage, $scopes);
|
||||
$decoded = Key::decode(
|
||||
project: new Document(['$id' => $projectId]),
|
||||
team: new Document(),
|
||||
@@ -50,7 +50,7 @@ class KeyTest extends TestCase
|
||||
'previewAuthDisabled' => true,
|
||||
'deploymentStatusIgnored' => true,
|
||||
];
|
||||
$key = static::generateKey($projectId, $usage, $scopes, extra: $extra);
|
||||
$key = self::generateKey($projectId, $usage, $scopes, extra: $extra);
|
||||
$decoded = Key::decode(
|
||||
project: new Document(['$id' => $projectId]),
|
||||
team: new Document(),
|
||||
@@ -88,7 +88,7 @@ class KeyTest extends TestCase
|
||||
$this->assertEquals('UNKNOWN', $decoded->getName());
|
||||
|
||||
// Decode expired dynamic key
|
||||
$expiredKey = static::generateKey($projectId, $usage, $scopes, maxAge: 1, timestamp: time() - 60);
|
||||
$expiredKey = self::generateKey($projectId, $usage, $scopes, maxAge: 1, timestamp: time() - 60);
|
||||
\sleep(2);
|
||||
$decoded = Key::decode(
|
||||
project: new Document(['$id' => $projectId]),
|
||||
|
||||
Reference in New Issue
Block a user