diff --git a/.github/workflows/php-stan-qality.yml b/.github/workflows/php-stan-qality.yml new file mode 100644 index 0000000000..57729d1297 --- /dev/null +++ b/.github/workflows/php-stan-qality.yml @@ -0,0 +1,16 @@ +name: "PHP Stan - CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" \ No newline at end of file diff --git a/app/init.php b/app/init.php index b4ab772e0e..496b43e29d 100644 --- a/app/init.php +++ b/app/init.php @@ -781,7 +781,7 @@ $register->set('logger', function () { }; } - if (empty($providerName) || empty($providerConfig)) { + if (empty($providerName)) { return; } @@ -1028,6 +1028,7 @@ $register->set('smtp', function () { return $mail; }); $register->set('geodb', function () { + // @phpstan-ignore class.notFound return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-09.mmdb'); }); $register->set('passwordsDictionary', function () { diff --git a/app/realtime.php b/app/realtime.php index b8fdb2cf21..b491219243 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -266,7 +266,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $attempts = 0; $start = time(); - Timer::tick(5000, function () use ($server, $register, $realtime, $stats, $logError) { + Timer::tick(5000, function () use ($server, $register, $realtime, $stats) { /** * Sending current connections to project channels on the console project every 5 seconds. */ diff --git a/app/worker.php b/app/worker.php index 9bcdae78e6..3de106608b 100644 --- a/app/worker.php +++ b/app/worker.php @@ -39,6 +39,7 @@ use Utopia\System\System; Authorization::disable(); Runtime::enableCoroutine(SWOOLE_HOOK_ALL); + // @phpstan-ignore variable.undefined Server::setResource('register', fn () => $register); Server::setResource('dbForConsole', function (Cache $cache, Registry $register) { @@ -272,7 +273,7 @@ Server::setResource('deviceForCache', function (Document $project) { return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId()); }, ['project']); - +// @phpstan-ignore variable.undefined $pools = $register->get('pools'); $platform = new Appwrite(); $args = $platform->getEnv('argv'); diff --git a/composer.json b/composer.json index 91ff1eeb92..26ac756bbe 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "test": "vendor/bin/phpunit", "lint": "vendor/bin/pint --test", "format": "vendor/bin/pint", - "bench": "vendor/bin/phpbench run --report=benchmark" + "bench": "vendor/bin/phpbench run --report=benchmark", + "check": "./vendor/bin/phpstan analyse --level 1 -c phpstan.neon app src tests" }, "autoload": { "psr-4": { @@ -88,7 +89,8 @@ "swoole/ide-helper": "5.1.2", "textalk/websocket": "1.5.7", "laravel/pint": "^1.14", - "phpbench/phpbench": "^1.2" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "1.8.*" }, "provide": { "ext-phpiredis": "*" diff --git a/composer.lock b/composer.lock index 147800df32..d6b8cd3d49 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "b6820da26239716cf14a445697902a03", + "content-hash": "0f051dc943ac8ba7a8777a1442bc64e2", "packages": [ { "name": "adhocore/jwt", @@ -2069,16 +2069,16 @@ }, { "name": "utopia-php/logger", - "version": "0.6.0", + "version": "0.6.1", "source": { "type": "git", "url": "https://github.com/utopia-php/logger.git", - "reference": "a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9" + "reference": "7e8ff512c6f04577aba1df67c7b9628971946f9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/logger/zipball/a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9", - "reference": "a2d1daeeb8f61fdec6d851950d9a021a3d05c9f9", + "url": "https://api.github.com/repos/utopia-php/logger/zipball/7e8ff512c6f04577aba1df67c7b9628971946f9c", + "reference": "7e8ff512c6f04577aba1df67c7b9628971946f9c", "shasum": "" }, "require": { @@ -2117,9 +2117,9 @@ ], "support": { "issues": "https://github.com/utopia-php/logger/issues", - "source": "https://github.com/utopia-php/logger/tree/0.6.0" + "source": "https://github.com/utopia-php/logger/tree/0.6.1" }, - "time": "2024-05-23T13:37:54+00:00" + "time": "2024-09-20T14:02:12+00:00" }, { "name": "utopia-php/messaging", @@ -3314,16 +3314,16 @@ }, { "name": "laravel/pint", - "version": "v1.17.3", + "version": "v1.18.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "9d77be916e145864f10788bb94531d03e1f7b482" + "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/9d77be916e145864f10788bb94531d03e1f7b482", - "reference": "9d77be916e145864f10788bb94531d03e1f7b482", + "url": "https://api.github.com/repos/laravel/pint/zipball/35c00c05ec43e6b46d295efc0f4386ceb30d50d9", + "reference": "35c00c05ec43e6b46d295efc0f4386ceb30d50d9", "shasum": "" }, "require": { @@ -3376,7 +3376,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-09-03T15:00:28+00:00" + "time": "2024-09-24T17:22:50+00:00" }, { "name": "matthiasmullie/minify", @@ -4185,16 +4185,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.30.1", + "version": "1.32.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "51b95ec8670af41009e2b2b56873bad96682413e" + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/51b95ec8670af41009e2b2b56873bad96682413e", - "reference": "51b95ec8670af41009e2b2b56873bad96682413e", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6ca22b154efdd9e3c68c56f5d94670920a1c19a4", + "reference": "6ca22b154efdd9e3c68c56f5d94670920a1c19a4", "shasum": "" }, "require": { @@ -4226,9 +4226,68 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.30.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.32.0" }, - "time": "2024-09-07T20:13:05+00:00" + "time": "2024-09-26T07:23:32+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.8.11", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "46e223dd68a620da18855c23046ddb00940b4014" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", + "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-10-24T15:45:13+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5865,16 +5924,16 @@ }, { "name": "symfony/console", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111" + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1eed7af6961d763e7832e874d7f9b21c3ea9c111", - "reference": "1eed7af6961d763e7832e874d7f9b21c3ea9c111", + "url": "https://api.github.com/repos/symfony/console/zipball/0fa539d12b3ccf068a722bbbffa07ca7079af9ee", + "reference": "0fa539d12b3ccf068a722bbbffa07ca7079af9ee", "shasum": "" }, "require": { @@ -5938,7 +5997,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.4" + "source": "https://github.com/symfony/console/tree/v7.1.5" }, "funding": [ { @@ -5954,7 +6013,7 @@ "type": "tidelift" } ], - "time": "2024-08-15T22:48:53+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6025,16 +6084,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.1.2", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c" + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/92a91985250c251de9b947a14bb2c9390b1a562c", - "reference": "92a91985250c251de9b947a14bb2c9390b1a562c", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/61fe0566189bf32e8cfee78335d8776f64a66f5a", + "reference": "61fe0566189bf32e8cfee78335d8776f64a66f5a", "shasum": "" }, "require": { @@ -6071,7 +6130,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.1.2" + "source": "https://github.com/symfony/filesystem/tree/v7.1.5" }, "funding": [ { @@ -6087,7 +6146,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T10:03:55+00:00" + "time": "2024-09-17T09:16:35+00:00" }, { "name": "symfony/finder", @@ -6536,16 +6595,16 @@ }, { "name": "symfony/process", - "version": "v7.1.3", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca" + "reference": "5c03ee6369281177f07f7c68252a280beccba847" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/7f2f542c668ad6c313dc4a5e9c3321f733197eca", - "reference": "7f2f542c668ad6c313dc4a5e9c3321f733197eca", + "url": "https://api.github.com/repos/symfony/process/zipball/5c03ee6369281177f07f7c68252a280beccba847", + "reference": "5c03ee6369281177f07f7c68252a280beccba847", "shasum": "" }, "require": { @@ -6577,7 +6636,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.3" + "source": "https://github.com/symfony/process/tree/v7.1.5" }, "funding": [ { @@ -6593,7 +6652,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:44:47+00:00" + "time": "2024-09-19T21:48:23+00:00" }, { "name": "symfony/service-contracts", @@ -6680,16 +6739,16 @@ }, { "name": "symfony/string", - "version": "v7.1.4", + "version": "v7.1.5", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b" + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/6cd670a6d968eaeb1c77c2e76091c45c56bc367b", - "reference": "6cd670a6d968eaeb1c77c2e76091c45c56bc367b", + "url": "https://api.github.com/repos/symfony/string/zipball/d66f9c343fa894ec2037cc928381df90a7ad4306", + "reference": "d66f9c343fa894ec2037cc928381df90a7ad4306", "shasum": "" }, "require": { @@ -6747,7 +6806,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.1.4" + "source": "https://github.com/symfony/string/tree/v7.1.5" }, "funding": [ { @@ -6763,7 +6822,7 @@ "type": "tidelift" } ], - "time": "2024-08-12T09:59:40+00:00" + "time": "2024-09-20T08:28:38+00:00" }, { "name": "textalk/websocket", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000000..c41461e446 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + scanDirectories: + - vendor/swoole/ide-helper + excludePaths: + - tests/resources \ No newline at end of file diff --git a/src/Appwrite/Auth/Hash/Scrypt.php b/src/Appwrite/Auth/Hash/Scrypt.php index 821b1fba69..4dd3cc2477 100644 --- a/src/Appwrite/Auth/Hash/Scrypt.php +++ b/src/Appwrite/Auth/Hash/Scrypt.php @@ -25,6 +25,7 @@ class Scrypt extends Hash { $options = $this->getOptions(); + // @phpstan-ignore function.notFound return \scrypt($password, $options['salt'], $options['costCpu'], $options['costMemory'], $options['costParallel'], $options['length']); } diff --git a/src/Appwrite/Auth/Hash/Scryptmodified.php b/src/Appwrite/Auth/Hash/Scryptmodified.php index 7717f324e5..523bd14d7d 100644 --- a/src/Appwrite/Auth/Hash/Scryptmodified.php +++ b/src/Appwrite/Auth/Hash/Scryptmodified.php @@ -61,7 +61,10 @@ class Scryptmodified extends Hash $saltSeparatorBytes = \base64_decode($options['saltSeparator']); $password = mb_convert_encoding($password, 'UTF-8'); + + // @phpstan-ignore function.notFound $derivedKey = \scrypt($password, $saltBytes . $saltSeparatorBytes, 16384, 8, 1, 64); + $derivedKey = \hex2bin($derivedKey); return $derivedKey; diff --git a/src/Appwrite/Event/Func.php b/src/Appwrite/Event/Func.php index 0cbaf17b60..1fb86e1d33 100644 --- a/src/Appwrite/Event/Func.php +++ b/src/Appwrite/Event/Func.php @@ -170,16 +170,6 @@ class Func extends Event return $this; } - /** - * Returns set custom data for the function event. - * - * @return string - */ - public function getData(): string - { - return $this->data; - } - /** * Sets JWT for the function event. * diff --git a/src/Appwrite/GraphQL/Resolvers.php b/src/Appwrite/GraphQL/Resolvers.php index 8bc72af2f8..b81e7a9c39 100644 --- a/src/Appwrite/GraphQL/Resolvers.php +++ b/src/Appwrite/GraphQL/Resolvers.php @@ -25,7 +25,7 @@ class Resolvers ?Route $route, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $route, $args, $context, $info) { + function (callable $resolve, callable $reject) use ($utopia, $route, $args) { /** @var App $utopia */ /** @var Response $response */ /** @var Request $request */ @@ -96,7 +96,7 @@ class Resolvers callable $url, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -127,7 +127,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -163,7 +163,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -195,7 +195,7 @@ class Resolvers callable $params, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $params, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); @@ -225,7 +225,7 @@ class Resolvers callable $url, ): callable { return static fn ($type, $args, $context, $info) => new Swoole( - function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) { + function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $args) { $utopia = $utopia->getResource('utopia:graphql', true); $request = $utopia->getResource('request', true); $response = $utopia->getResource('response', true); diff --git a/src/Appwrite/GraphQL/Schema.php b/src/Appwrite/GraphQL/Schema.php index 833ea9d032..d39cc95549 100644 --- a/src/Appwrite/GraphQL/Schema.php +++ b/src/Appwrite/GraphQL/Schema.php @@ -156,6 +156,7 @@ class Schema $offset = 0; while (!empty($attrs = $attributes($limit, $offset))) { + $databaseId = ''; foreach ($attrs as $attr) { if ($attr['status'] !== 'available') { continue; diff --git a/src/Appwrite/Migration/Version/V20.php b/src/Appwrite/Migration/Version/V20.php index 5a0807cedf..58829409f8 100644 --- a/src/Appwrite/Migration/Version/V20.php +++ b/src/Appwrite/Migration/Version/V20.php @@ -453,7 +453,7 @@ class V20 extends Migration Query::equal('period', ['1d']), ]); - $value = $query ?? 0; + $value = $query; $this->createInfMetric($to, $value); } diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index 5dd2f7f886..ee76641374 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -197,6 +197,7 @@ class Builds extends Action $isVcsEnabled = !empty($providerRepositoryId); $owner = ''; $repositoryName = ''; + $providerInstallationId = ''; if ($isVcsEnabled) { $installation = $dbForConsole->getDocument('installations', $installationId); @@ -359,7 +360,7 @@ class Builds extends Action $providerCommitHash = \trim($stdout); $authorUrl = "https://github.com/$cloneOwner"; - $deployment->setAttribute('providerCommitHash', $providerCommitHash ?? ''); + $deployment->setAttribute('providerCommitHash', $providerCommitHash); $deployment->setAttribute('providerCommitAuthorUrl', $authorUrl); $deployment->setAttribute('providerCommitAuthor', 'Appwrite'); $deployment->setAttribute('providerCommitMessage', "Create '" . $function->getAttribute('name', '') . "' function"); diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 56f5f012e8..9aa7503310 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -199,7 +199,7 @@ class Databases extends Action } if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $options['relatedCollection']); } $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index c70d9ca11b..67eaf6d405 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -756,7 +756,7 @@ class Deletes extends Action Query::equal('resourceType', ['function']), Query::equal('resourceInternalId', [$functionInternalId]), Query::equal('projectInternalId', [$project->getInternalId()]) - ], $dbForConsole, function (Document $document) use ($project, $dbForConsole) { + ], $dbForConsole, function (Document $document) use ($dbForConsole) { $this->deleteRule($dbForConsole, $document); }); diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index e60f67416d..afd044850b 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -442,8 +442,8 @@ class Functions extends Action if ($version === 'v2') { $vars = \array_merge($vars, [ 'APPWRITE_FUNCTION_TRIGGER' => $headers['x-appwrite-trigger'] ?? '', - 'APPWRITE_FUNCTION_DATA' => $body ?? '', - 'APPWRITE_FUNCTION_EVENT_DATA' => $body ?? '', + 'APPWRITE_FUNCTION_DATA' => $body, + 'APPWRITE_FUNCTION_EVENT_DATA' => $body, 'APPWRITE_FUNCTION_EVENT' => $headers['x-appwrite-event'] ?? '', 'APPWRITE_FUNCTION_USER_ID' => $headers['x-appwrite-user-id'] ?? '', 'APPWRITE_FUNCTION_JWT' => $headers['x-appwrite-user-jwt'] ?? '' @@ -605,7 +605,7 @@ class Functions extends Action ); if (!empty($error)) { - throw new Exception($error, $errorCode); + throw new Exception($error, $errorCode ?? 0); } } } diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index b0f05522fa..5aede056a8 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -346,32 +346,34 @@ class Messaging extends Action $dbForProject->updateDocument('messages', $message->getId(), $message); // Delete any attachments that were downloaded to local storage - if ($provider->getAttribute('type') === MESSAGE_TYPE_EMAIL) { - if ($deviceForFiles->getType() === Storage::DEVICE_LOCAL) { - return; - } - - $data = $message->getAttribute('data'); - $attachments = $data['attachments'] ?? []; - - foreach ($attachments as $attachment) { - $bucketId = $attachment['bucketId']; - $fileId = $attachment['fileId']; - - $bucket = $dbForProject->getDocument('buckets', $bucketId); - if ($bucket->isEmpty()) { - throw new \Exception('Storage bucket with the requested ID could not be found'); + foreach ($providers as $provider) { + if ($provider->getAttribute('type') === MESSAGE_TYPE_EMAIL) { + if ($deviceForFiles->getType() === Storage::DEVICE_LOCAL) { + return; } - $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); - if ($file->isEmpty()) { - throw new \Exception('Storage file with the requested ID could not be found'); - } + $data = $message->getAttribute('data'); + $attachments = $data['attachments'] ?? []; - $path = $file->getAttribute('path', ''); + foreach ($attachments as $attachment) { + $bucketId = $attachment['bucketId']; + $fileId = $attachment['fileId']; - if ($this->getLocalDevice($project)->exists($path)) { - $this->getLocalDevice($project)->delete($path); + $bucket = $dbForProject->getDocument('buckets', $bucketId); + if ($bucket->isEmpty()) { + throw new \Exception('Storage bucket with the requested ID could not be found'); + } + + $file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId); + if ($file->isEmpty()) { + throw new \Exception('Storage file with the requested ID could not be found'); + } + + $path = $file->getAttribute('path', ''); + + if ($this->getLocalDevice($project)->exists($path)) { + $this->getLocalDevice($project)->delete($path); + } } } } diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php index 88ca7871f2..ffaa2d8ae5 100644 --- a/src/Appwrite/Platform/Workers/Webhooks.php +++ b/src/Appwrite/Platform/Workers/Webhooks.php @@ -202,7 +202,7 @@ class Webhooks extends Action $template->setParam('{{webhook}}', $webhook->getAttribute('name')); $template->setParam('{{project}}', $project->getAttribute('name')); $template->setParam('{{url}}', $webhook->getAttribute('url')); - $template->setParam('{{error}}', $curlError ?? 'The server returned ' . $statusCode . ' status code'); + $template->setParam('{{error}}', 'The server returned ' . $statusCode . ' status code'); $template->setParam('{{path}}', "/console/project-$projectId/settings/webhooks/$webhookId"); $template->setParam('{{attempts}}', $attempts); diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 3074d59b7c..f376bcdd40 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -103,10 +103,6 @@ class OpenAPI3 extends Format $output['components']['securitySchemes']['Key']['x-appwrite'] = ['demo' => '']; } - if (isset($output['securityDefinitions']['JWT'])) { - $output['securityDefinitions']['JWT']['x-appwrite'] = ['demo' => '']; - } - if (isset($output['components']['securitySchemes']['Locale'])) { $output['components']['securitySchemes']['Locale']['x-appwrite'] = ['demo' => 'en']; } @@ -239,7 +235,6 @@ class OpenAPI3 extends Format if ($route->getLabel('sdk.response.code', 500) === 204) { $temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['description'] = 'No content'; - unset($temp['responses'][(string)$route->getLabel('sdk.response.code', '500')]['schema']); } if ((!empty($scope))) { // && 'public' != $scope @@ -287,7 +282,7 @@ class OpenAPI3 extends Format $validator = $validator->getValidator(); } - switch ((!empty($validator)) ? \get_class($validator) : '') { + switch (get_class($validator)) { case 'Utopia\Database\Validator\UID': case 'Utopia\Validator\Text': $node['schema']['type'] = $validator->getType(); diff --git a/src/Appwrite/Specification/Format/Swagger2.php b/src/Appwrite/Specification/Format/Swagger2.php index 2eab7807b3..3edeb1dbe5 100644 --- a/src/Appwrite/Specification/Format/Swagger2.php +++ b/src/Appwrite/Specification/Format/Swagger2.php @@ -286,7 +286,7 @@ class Swagger2 extends Format $validator = $validator->getValidator(); } - $validatorClass = (!empty($validator)) ? \get_class($validator) : ''; + $validatorClass = \get_class($validator); if ($validatorClass === 'Utopia\Validator\AnyOf') { $validator = $param['validator']->getValidators()[0]; $validatorClass = \get_class($validator); diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index a2c07d34b0..537707bb5a 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -650,6 +650,10 @@ class Response extends SwooleResponse $ruleType = $rule['type']; } + if(!isset($ruleType)) { + continue; + } + if (!array_key_exists($ruleType, $this->models)) { throw new Exception('Missing model for rule: ' . $ruleType); } diff --git a/src/Appwrite/Vcs/Comment.php b/src/Appwrite/Vcs/Comment.php index 18379f1099..2f56192e38 100644 --- a/src/Appwrite/Vcs/Comment.php +++ b/src/Appwrite/Vcs/Comment.php @@ -67,15 +67,21 @@ class Comment ]; } + $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; + $hostname = System::getEnv('_APP_DOMAIN'); + + $lastFunctionId = ''; + $lastProjectId = ''; + foreach ($projects as $projectId => $project) { + $lastProjectId = $projectId; + $text .= "**{$project['name']}** `{$projectId}`\n\n"; $text .= "| Function | ID | Status | Action |\n"; $text .= "| :- | :- | :- | :- |\n"; - $protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') == 'disabled' ? 'http' : 'https'; - $hostname = System::getEnv('_APP_DOMAIN'); - foreach ($project['functions'] as $functionId => $function) { + $lastFunctionId = $functionId; if ($function['status'] === 'waiting' || $function['status'] === 'processing' || $function['status'] === 'building') { $text .= "**Your function deployment is in progress. Please check back in a few minutes for the updated status.**\n\n"; } elseif ($function['status'] === 'ready') { @@ -115,9 +121,11 @@ class Comment $text .= "\n\n"; } - $functionUrl = $protocol . '://' . $hostname . '/console/project-' . $projectId . '/functions/function-' . $functionId; + + $functionUrl = $protocol . '://' . $hostname . '/console/project-' . $lastProjectId . '/functions/function-' . $lastFunctionId; $text .= "Only deployments on the production branch are activated automatically. If you'd like to activate this deployment, navigate to [your deployments]($functionUrl). Learn more about Appwrite [Function deployments](https://appwrite.io/docs/functions).\n\n"; + $tip = $this->tips[array_rand($this->tips)]; $text .= "> **💡 Did you know?** \n " . $tip . "\n\n"; diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 2958e6cb5f..740831e4e9 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -766,6 +766,7 @@ class FunctionsCustomServerTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'] ]; $id = ''; + $largeTag = []; while (!feof($handle)) { $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'php-large-fx.tar.gz'); $headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size - 1) . '/' . $size; diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index fecb1692a9..351d186c7b 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -560,7 +560,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'); } diff --git a/tests/e2e/Services/GraphQL/StorageClientTest.php b/tests/e2e/Services/GraphQL/StorageClientTest.php index 9896598c2d..8363f323cf 100644 --- a/tests/e2e/Services/GraphQL/StorageClientTest.php +++ b/tests/e2e/Services/GraphQL/StorageClientTest.php @@ -183,7 +183,7 @@ class StorageClientTest extends Scope /** * @depends testCreateFile * @param $file - * @return array + * @return void * @throws \Exception */ public function testGetFileDownload($file) diff --git a/tests/e2e/Services/GraphQL/StorageServerTest.php b/tests/e2e/Services/GraphQL/StorageServerTest.php index 7fea895b1c..58d800ab3c 100644 --- a/tests/e2e/Services/GraphQL/StorageServerTest.php +++ b/tests/e2e/Services/GraphQL/StorageServerTest.php @@ -232,7 +232,7 @@ class StorageServerTest extends Scope /** * @depends testCreateFile * @param $file - * @return array + * @return void * @throws \Exception */ public function testGetFileDownload($file) diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index dc5ddb9d70..8dc6647c28 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -1429,7 +1429,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'); } diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index d2d75409b8..05a987abc2 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -96,6 +96,7 @@ trait StorageBase 'content-type' => 'multipart/form-data', 'x-appwrite-project' => $this->getProject()['$id'] ]; + $largeFile = []; $id = ''; while (!feof($handle)) { $curlFile = new \CURLFile('data://' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'large-file.mp4');