mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.9.x' into revert-11585-revert-11402-sync-mongodb
This commit is contained in:
@@ -394,7 +394,8 @@ jobs:
|
||||
Webhooks,
|
||||
VCS,
|
||||
Messaging,
|
||||
Migrations
|
||||
Migrations,
|
||||
Project
|
||||
]
|
||||
include:
|
||||
- service: Databases
|
||||
|
||||
@@ -62,6 +62,8 @@ $admins = [
|
||||
'devKeys.write',
|
||||
'webhooks.read',
|
||||
'webhooks.write',
|
||||
'project.read',
|
||||
'project.write',
|
||||
'locale.read',
|
||||
'avatars.read',
|
||||
'health.read',
|
||||
|
||||
@@ -31,12 +31,4 @@ return [
|
||||
"description" =>
|
||||
"Access to create, update, and delete project\'s development keys",
|
||||
],
|
||||
"webhooks.read" => [
|
||||
"description" =>
|
||||
"Access to read project\'s webhooks",
|
||||
],
|
||||
"webhooks.write" => [
|
||||
"description" =>
|
||||
"Access to create, update, and delete project\'s webhooks",
|
||||
],
|
||||
];
|
||||
|
||||
@@ -180,4 +180,12 @@ return [ // List of publicly visible scopes
|
||||
"description" =>
|
||||
"Access to create, update, and delete project\'s webhooks",
|
||||
],
|
||||
"project.read" => [
|
||||
"description" =>
|
||||
"Access to read project\'s information",
|
||||
],
|
||||
"project.write" => [
|
||||
"description" =>
|
||||
"Access to update project\'s information",
|
||||
],
|
||||
];
|
||||
|
||||
@@ -209,6 +209,22 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, arr
|
||||
|
||||
$createSession = function (string $userId, string $secret, Request $request, Response $response, User $user, Database $dbForProject, Document $project, array $platform, Locale $locale, Reader $geodb, Event $queueForEvents, Mail $queueForMails, Store $store, ProofsToken $proofForToken, ProofsCode $proofForCode, Authorization $authorization) {
|
||||
|
||||
// Attempt to decode secret as a JWT (used by OAuth2 token flow to carry provider info)
|
||||
$oauthProvider = null;
|
||||
try {
|
||||
$jwtDecoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 60, 0);
|
||||
$payload = $jwtDecoder->decode($secret);
|
||||
|
||||
if (empty($payload['provider'])) {
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
$oauthProvider = $payload['provider'];
|
||||
$secret = $payload['secret'];
|
||||
} catch (\Ahc\Jwt\JWTException) {
|
||||
// Not a JWT — use secret as-is (non-OAuth flows)
|
||||
}
|
||||
|
||||
/** @var Appwrite\Utopia\Database\Documents\User $userFromRequest */
|
||||
$userFromRequest = $authorization->skip(fn () => $dbForProject->getDocument('users', $userId));
|
||||
|
||||
@@ -220,6 +236,12 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
||||
?: $userFromRequest->tokenVerify(null, $secret, $proofForCode);
|
||||
|
||||
if (!$verifiedToken) {
|
||||
// Could mean invalid/expired JWT, or expired secret
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
// OAuth2 tokens must have a provider from the JWT
|
||||
if ($verifiedToken->getAttribute('type') === TOKEN_TYPE_OAUTH2 && $oauthProvider === null) {
|
||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||
}
|
||||
|
||||
@@ -245,7 +267,7 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
||||
TOKEN_TYPE_INVITE => SESSION_PROVIDER_EMAIL,
|
||||
TOKEN_TYPE_MAGIC_URL => SESSION_PROVIDER_MAGIC_URL,
|
||||
TOKEN_TYPE_PHONE => SESSION_PROVIDER_PHONE,
|
||||
TOKEN_TYPE_OAUTH2 => SESSION_PROVIDER_OAUTH2,
|
||||
TOKEN_TYPE_OAUTH2 => $oauthProvider,
|
||||
default => SESSION_PROVIDER_TOKEN,
|
||||
};
|
||||
$session = new Document(array_merge(
|
||||
@@ -1899,7 +1921,12 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
->setParam('tokenId', $token->getId())
|
||||
;
|
||||
|
||||
$query['secret'] = $secret;
|
||||
// Wrap secret in a JWT that also carries the provider name
|
||||
$jwtEncoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 60, 0);
|
||||
$query['secret'] = $jwtEncoder->encode([
|
||||
'secret' => $secret,
|
||||
'provider' => $provider,
|
||||
]);
|
||||
$query['userId'] = $user->getId();
|
||||
|
||||
// If the `token` param is not set, we persist the session in a cookie
|
||||
|
||||
@@ -1,25 +1,15 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Datetime as DateTimeValidator;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
Http::get('/v1/project/usage')
|
||||
@@ -442,228 +432,3 @@ Http::get('/v1/project/usage')
|
||||
'embeddingsTextErrorsTotal' => $total[METRIC_EMBEDDINGS_TEXT_TOTAL_ERROR] ?? 0,
|
||||
]), Response::MODEL_USAGE_PROJECT);
|
||||
});
|
||||
|
||||
|
||||
// Variables
|
||||
Http::post('/v1/project/variables')
|
||||
->desc('Create variable')
|
||||
->groups(['api'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('audits.event', 'variable.create')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: null,
|
||||
name: 'createVariable',
|
||||
description: '/docs/references/project/create-variable.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false)
|
||||
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false)
|
||||
->param('secret', true, new Boolean(), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $key, string $value, bool $secret, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
|
||||
$variableId = ID::unique();
|
||||
|
||||
$variable = new Document([
|
||||
'$id' => $variableId,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'resourceInternalId' => '',
|
||||
'resourceId' => '',
|
||||
'resourceType' => 'project',
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'secret' => $secret,
|
||||
'search' => implode(' ', [$variableId, $key, 'project']),
|
||||
]);
|
||||
|
||||
try {
|
||||
$variable = $dbForProject->createDocument('variables', $variable);
|
||||
} catch (DuplicateException $th) {
|
||||
throw new Exception(Exception::VARIABLE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]);
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false));
|
||||
}
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
});
|
||||
|
||||
Http::get('/v1/project/variables')
|
||||
->desc('List variables')
|
||||
->groups(['api'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: null,
|
||||
name: 'listVariables',
|
||||
description: '/docs/references/project/list-variables.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE_LIST,
|
||||
)
|
||||
]
|
||||
))
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (Response $response, Database $dbForProject) {
|
||||
$variables = $dbForProject->find('variables', [
|
||||
Query::equal('resourceType', ['project']),
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]);
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'variables' => $variables,
|
||||
'total' => \count($variables),
|
||||
]), Response::MODEL_VARIABLE_LIST);
|
||||
});
|
||||
|
||||
Http::get('/v1/project/variables/:variableId')
|
||||
->desc('Get variable')
|
||||
->groups(['api'])
|
||||
->label('scope', 'projects.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: null,
|
||||
name: 'getVariable',
|
||||
description: '/docs/references/project/get-variable.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $variableId, Response $response, Document $project, Database $dbForProject) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
});
|
||||
|
||||
Http::put('/v1/project/variables/:variableId')
|
||||
->desc('Update variable')
|
||||
->groups(['api'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: null,
|
||||
name: 'updateVariable',
|
||||
description: '/docs/references/project/update-variable.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->param('key', null, new Text(255), 'Variable key. Max length: 255 chars.', false)
|
||||
->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true)
|
||||
->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $variableId, string $key, ?string $value, ?bool $secret, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($variable->getAttribute('secret') === true && $secret === false) {
|
||||
throw new Exception(Exception::VARIABLE_CANNOT_UNSET_SECRET);
|
||||
}
|
||||
|
||||
$variable
|
||||
->setAttribute('key', $key)
|
||||
->setAttribute('value', $value ?? $variable->getAttribute('value'))
|
||||
->setAttribute('secret', $secret ?? $variable->getAttribute('secret'))
|
||||
->setAttribute('search', implode(' ', [$variableId, $key, 'project']));
|
||||
|
||||
try {
|
||||
$dbForProject->updateDocument('variables', $variable->getId(), $variable);
|
||||
} catch (DuplicateException $th) {
|
||||
throw new Exception(Exception::VARIABLE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]);
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false));
|
||||
}
|
||||
|
||||
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
});
|
||||
|
||||
Http::delete('/v1/project/variables/:variableId')
|
||||
->desc('Delete variable')
|
||||
->groups(['api'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: null,
|
||||
name: 'deleteVariable',
|
||||
description: '/docs/references/project/delete-variable.md',
|
||||
auth: [AuthType::ADMIN],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_NOCONTENT,
|
||||
model: Response::MODEL_NONE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable unique ID.', false, ['dbForProject'])
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function (string $variableId, Document $project, Response $response, Database $dbForProject) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceType') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$dbForProject->deleteDocument('variables', $variable->getId());
|
||||
|
||||
$functions = $dbForProject->find('functions', [
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]);
|
||||
|
||||
foreach ($functions as $function) {
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function->setAttribute('live', false));
|
||||
}
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
+3
-3
@@ -13,9 +13,9 @@
|
||||
"test": "vendor/bin/phpunit",
|
||||
"lint": "vendor/bin/pint --test --config pint.json",
|
||||
"format": "vendor/bin/pint --config pint.json",
|
||||
"analyze": "./vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=1G",
|
||||
"analyze": "./vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=1G",
|
||||
"bench": "vendor/bin/phpbench run --report=benchmark",
|
||||
"check": "./vendor/bin/phpstan analyse -c phpstan.neon",
|
||||
"check": "./vendor/bin/phpstan analyse -c phpstan.neon --memory-limit=1G",
|
||||
"installer:clean": "php src/Appwrite/Platform/Installer/Server.php --clean",
|
||||
"installer:dev": "docker compose build && composer installer:clean && php src/Appwrite/Platform/Installer/Server.php --docker"
|
||||
},
|
||||
@@ -84,7 +84,7 @@
|
||||
"utopia-php/storage": "1.0.*",
|
||||
"utopia-php/system": "0.10.*",
|
||||
"utopia-php/telemetry": "0.2.*",
|
||||
"utopia-php/vcs": "2.*",
|
||||
"utopia-php/vcs": "3.*",
|
||||
"utopia-php/websocket": "1.0.*",
|
||||
"matomo/device-detector": "6.4.*",
|
||||
"dragonmantank/cron-expression": "3.4.*",
|
||||
|
||||
Generated
+8
-7
@@ -5216,22 +5216,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "2.0.2",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "5769679308bad498f2777547d48ab332166c4c0b"
|
||||
"reference": "0efe842d695acb4b184f5306a836169c771fbcea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/5769679308bad498f2777547d48ab332166c4c0b",
|
||||
"reference": "5769679308bad498f2777547d48ab332166c4c0b",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/0efe842d695acb4b184f5306a836169c771fbcea",
|
||||
"reference": "0efe842d695acb4b184f5306a836169c771fbcea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"adhocore/jwt": "^1.1",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cache": "1.0.*"
|
||||
"utopia-php/cache": "1.0.*",
|
||||
"utopia-php/fetch": "0.5.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*.*",
|
||||
@@ -5258,9 +5259,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/2.0.2"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/3.0.1"
|
||||
},
|
||||
"time": "2026-03-13T15:25:16+00:00"
|
||||
"time": "2026-03-23T15:58:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<directory>./tests/e2e/Services/ProjectWebhooks</directory>
|
||||
<directory>./tests/e2e/Services/Messaging</directory>
|
||||
<directory>./tests/e2e/Services/Migrations</directory>
|
||||
<directory>./tests/e2e/Services/Project</directory>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
|
||||
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Appwrite\Event;
|
||||
|
||||
use Appwrite\Messaging\Adapter;
|
||||
use Appwrite\Messaging\Adapter\Realtime as RealtimeAdapter;
|
||||
use Utopia\Console;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception;
|
||||
|
||||
@@ -96,17 +97,21 @@ class Realtime extends Event
|
||||
: [$target['projectId'] ?? $this->getProject()->getId()];
|
||||
|
||||
foreach ($projectIds as $projectId) {
|
||||
$this->realtime->send(
|
||||
projectId: $projectId,
|
||||
payload: $this->getRealtimePayload(),
|
||||
events: $allEvents,
|
||||
channels: $target['channels'],
|
||||
roles: $target['roles'],
|
||||
options: [
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'userId' => $this->getParam('userId')
|
||||
]
|
||||
);
|
||||
try {
|
||||
$this->realtime->send(
|
||||
projectId: $projectId,
|
||||
payload: $this->getRealtimePayload(),
|
||||
events: $allEvents,
|
||||
channels: $target['channels'],
|
||||
roles: $target['roles'],
|
||||
options: [
|
||||
'permissionsChanged' => $target['permissionsChanged'],
|
||||
'userId' => $this->getParam('userId')
|
||||
]
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
Console::error('Realtime send failed: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -9,6 +9,7 @@ use Appwrite\Platform\Modules\Core;
|
||||
use Appwrite\Platform\Modules\Databases;
|
||||
use Appwrite\Platform\Modules\Functions;
|
||||
use Appwrite\Platform\Modules\Health;
|
||||
use Appwrite\Platform\Modules\Project;
|
||||
use Appwrite\Platform\Modules\Projects;
|
||||
use Appwrite\Platform\Modules\Proxy;
|
||||
use Appwrite\Platform\Modules\Sites;
|
||||
@@ -38,5 +39,6 @@ class Appwrite extends Platform
|
||||
$this->addModule(new Storage\Module());
|
||||
$this->addModule(new VCS\Module());
|
||||
$this->addModule(new Webhooks\Module());
|
||||
$this->addModule(new Project\Module());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Platform\Action;
|
||||
|
||||
class Init extends Action
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'init';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setType(Action::TYPE_INIT)
|
||||
->groups(['project'])
|
||||
->inject('project')
|
||||
->callback(function (Document $project) {
|
||||
if ($project->getId() === 'console') {
|
||||
throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN);
|
||||
}
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\Variables;
|
||||
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Create extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'createProjectVariable';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
|
||||
->setHttpPath('/v1/project/variables')
|
||||
->desc('Create project variable')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'project.write')
|
||||
->label('event', 'variables.[variableId].create')
|
||||
->label('audits.event', 'project.variable.create')
|
||||
->label('audits.resource', 'project.variable/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'variables',
|
||||
name: 'createVariable',
|
||||
description: <<<EOT
|
||||
Create a new project environment variable. These variables can be accessed by all functions and sites in the project.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_CREATED,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
],
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Variable ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', false, ['dbForProject'])
|
||||
->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.')
|
||||
->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.')
|
||||
->param('secret', true, new Boolean(), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
|
||||
->inject('response')
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $variableId,
|
||||
string $key,
|
||||
string $value,
|
||||
bool $secret,
|
||||
Response $response,
|
||||
QueueEvent $queueForEvents,
|
||||
Database $dbForProject,
|
||||
) {
|
||||
$variableId = ($variableId == 'unique()') ? ID::unique() : $variableId;
|
||||
|
||||
$variable = new Document([
|
||||
'$id' => $variableId,
|
||||
'$permissions' => [],
|
||||
'resourceInternalId' => '', // Already in project DB anyway
|
||||
'resourceId' => '', // Already in project DB anyway
|
||||
'resourceType' => 'project',
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
'secret' => $secret,
|
||||
'search' => implode(' ', [$variableId, $key, 'project']),
|
||||
]);
|
||||
|
||||
try {
|
||||
$variable = $dbForProject->createDocument('variables', $variable);
|
||||
} catch (DuplicateException $th) {
|
||||
throw new Exception(Exception::VARIABLE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
foreach (['functions', 'sites'] as $collection) {
|
||||
$dbForProject->updateDocuments($collection, new Document([
|
||||
'live' => false
|
||||
]));
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('variableId', $variable->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_CREATED)
|
||||
->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\Variables;
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
class Delete extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'deleteProjectVariable';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_DELETE)
|
||||
->setHttpPath('/v1/project/variables/:variableId')
|
||||
->desc('Delete project variable')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'project.write')
|
||||
->label('event', 'variables.[variableId].delete')
|
||||
->label('audits.event', 'project.variable.delete')
|
||||
->label('audits.resource', 'project.variable/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'variables',
|
||||
name: 'deleteVariable',
|
||||
description: <<<EOT
|
||||
Delete a variable by its unique ID.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_NOCONTENT,
|
||||
model: Response::MODEL_NONE,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::NONE
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $variableId,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Event $queueForEvents,
|
||||
) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
|
||||
if ($variable->isEmpty() || $variable->getAttribute('resourceType', '') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (!$dbForProject->deleteDocument('variables', $variable->getId())) {
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove document from DB');
|
||||
};
|
||||
|
||||
foreach (['functions', 'sites'] as $collection) {
|
||||
$dbForProject->updateDocuments($collection, new Document([
|
||||
'live' => false
|
||||
]));
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('variableId', $variable->getId());
|
||||
|
||||
$response->noContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\Variables;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
|
||||
class Get extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'getProjectVariable';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/project/variables/:variableId')
|
||||
->desc('Get project variable')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'project.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'variables',
|
||||
name: 'getVariable',
|
||||
description: <<<EOT
|
||||
Get a variable by its unique ID.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable ID.', false, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $variableId,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
|
||||
if ($variable->isEmpty() || $variable->getAttribute('resourceType', '') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\Variables;
|
||||
|
||||
use Appwrite\Event\Event as QueueEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Update extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'updateProjectVariable';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PUT)
|
||||
->setHttpPath('/v1/project/variables/:variableId')
|
||||
->desc('Update project variable')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'project.write')
|
||||
->label('event', 'variables.[variableId].update')
|
||||
->label('audits.event', 'project.variable.update')
|
||||
->label('audits.resource', 'project.variable/{response.$id}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'variables',
|
||||
name: 'updateVariable',
|
||||
description: <<<EOT
|
||||
Update variable by its unique ID.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('variableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Variable ID.', false, ['dbForProject'])
|
||||
->param('key', null, new Nullable(new Text(255, 0)), 'Variable key. Max length: 255 chars.', true)
|
||||
->param('value', null, new Nullable(new Text(8192, 0)), 'Variable value. Max length: 8192 chars.', true)
|
||||
->param('secret', null, new Nullable(new Boolean()), 'Secret variables can be updated or deleted, but only projects can read them during build and runtime.', true)
|
||||
->inject('response')
|
||||
->inject('queueForEvents')
|
||||
->inject('dbForProject')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(
|
||||
string $variableId,
|
||||
?string $key,
|
||||
?string $value,
|
||||
?bool $secret,
|
||||
Response $response,
|
||||
QueueEvent $queueForEvents,
|
||||
Database $dbForProject,
|
||||
) {
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
|
||||
if ($variable->isEmpty() || $variable->getAttribute('resourceType', '') !== 'project') {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$isSecretVariable = $variable->getAttribute('secret', false) === true;
|
||||
if ($isSecretVariable && $secret === false) {
|
||||
throw new Exception(Exception::VARIABLE_CANNOT_UNSET_SECRET);
|
||||
}
|
||||
|
||||
if (\is_null($key) && \is_null($value) && \is_null($secret)) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID);
|
||||
}
|
||||
|
||||
$updates = new Document();
|
||||
|
||||
if (!\is_null($key)) {
|
||||
$updates->setAttribute('key', $key);
|
||||
$updates->setAttribute('search', implode(' ', [$variableId, $key, 'project']));
|
||||
}
|
||||
|
||||
if (!\is_null($value)) {
|
||||
$updates->setAttribute('value', $value);
|
||||
}
|
||||
|
||||
if (!\is_null($secret)) {
|
||||
$updates->setAttribute('secret', $secret);
|
||||
}
|
||||
|
||||
try {
|
||||
$variable = $dbForProject->updateDocument('variables', $variable->getId(), $updates);
|
||||
} catch (Duplicate $th) {
|
||||
throw new Exception(Exception::VARIABLE_ALREADY_EXISTS);
|
||||
}
|
||||
|
||||
foreach (['functions', 'sites'] as $collection) {
|
||||
$dbForProject->updateDocuments($collection, new Document([
|
||||
'live' => false
|
||||
]));
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('variableId', $variable->getId());
|
||||
|
||||
$response->dynamic($variable, Response::MODEL_VARIABLE);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Http\Project\Variables;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Variables;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Order as OrderException;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
||||
class XList extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'listProjectVariables';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
|
||||
->setHttpPath('/v1/project/variables')
|
||||
->desc('List project variables')
|
||||
->groups(['api', 'project'])
|
||||
->label('scope', 'project.read')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'project',
|
||||
group: 'variables',
|
||||
name: 'listVariables',
|
||||
description: <<<EOT
|
||||
Get a list of all project environment variables.
|
||||
EOT,
|
||||
auth: [AuthType::ADMIN, AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_VARIABLE_LIST,
|
||||
)
|
||||
]
|
||||
))
|
||||
->param('queries', [], new Variables(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Variables::ALLOWED_ATTRIBUTES), true)
|
||||
->param('total', true, new Boolean(true), 'When set to false, the total count returned will be 0 and will not be calculated.', true)
|
||||
->inject('project')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $queries
|
||||
*/
|
||||
public function action(
|
||||
array $queries,
|
||||
bool $includeTotal,
|
||||
Document $project,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$queries[] = Query::equal('resourceType', ['project']);
|
||||
|
||||
$cursor = Query::getCursorQueries($queries, false);
|
||||
$cursor = \reset($cursor);
|
||||
|
||||
if ($cursor !== false) {
|
||||
$validator = new Cursor();
|
||||
if (!$validator->isValid($cursor)) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
|
||||
}
|
||||
|
||||
$variableId = $cursor->getValue();
|
||||
$cursorDocument = $dbForProject->findOne('variables', [
|
||||
Query::equal('$id', [$variableId]),
|
||||
Query::equal('resourceType', ['project']),
|
||||
]);
|
||||
|
||||
if ($cursorDocument->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Variable '{$variableId}' for the 'cursor' value not found.");
|
||||
}
|
||||
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
|
||||
try {
|
||||
$variables = $dbForProject->find('variables', $queries);
|
||||
$total = $includeTotal ? $dbForProject->count('variables', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
} catch (OrderException $e) {
|
||||
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.");
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'variables' => $variables,
|
||||
'total' => $total,
|
||||
]), Response::MODEL_VARIABLE_LIST);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project;
|
||||
|
||||
use Appwrite\Platform\Modules\Project\Services\Http;
|
||||
use Utopia\Platform;
|
||||
|
||||
class Module extends Platform\Module
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->addService('http', new Http());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Project\Services;
|
||||
|
||||
use Appwrite\Platform\Modules\Project\Http\Init;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Variables\Create as CreateVariable;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Variables\Delete as DeleteVariable;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Variables\Get as GetVariable;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Variables\Update as UpdateVariable;
|
||||
use Appwrite\Platform\Modules\Project\Http\Project\Variables\XList as ListVariables;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class Http extends Service
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->type = Service::TYPE_HTTP;
|
||||
|
||||
// Hooks
|
||||
$this->addAction(Init::getName(), new Init());
|
||||
|
||||
// Project
|
||||
$this->addAction(CreateVariable::getName(), new CreateVariable());
|
||||
$this->addAction(ListVariables::getName(), new ListVariables());
|
||||
$this->addAction(GetVariable::getName(), new GetVariable());
|
||||
$this->addAction(DeleteVariable::getName(), new DeleteVariable());
|
||||
$this->addAction(UpdateVariable::getName(), new UpdateVariable());
|
||||
}
|
||||
}
|
||||
@@ -85,14 +85,16 @@ class Get extends Action
|
||||
|
||||
$repository = $github->getRepository($owner, $repositoryName);
|
||||
|
||||
$authorized = false;
|
||||
try {
|
||||
$installationRepository = $github->getInstallationRepository($repositoryName);
|
||||
if (!empty($installationRepository)) {
|
||||
$authorized = true;
|
||||
$authorized = $github->hasAccessToAllRepositories();
|
||||
if (!$authorized) {
|
||||
try {
|
||||
$installationRepository = $github->getInstallationRepository($repositoryName);
|
||||
if (!empty($installationRepository)) {
|
||||
$authorized = true;
|
||||
}
|
||||
} catch (RepositoryNotFound $e) {
|
||||
$authorized = false;
|
||||
}
|
||||
} catch (RepositoryNotFound $e) {
|
||||
$authorized = false;
|
||||
}
|
||||
|
||||
$repository['id'] = \strval($repository['id']) ?? '';
|
||||
|
||||
@@ -141,7 +141,7 @@ class XList extends Action
|
||||
|
||||
$page = ($offset / $limit) + 1;
|
||||
$owner = $github->getOwnerName($providerInstallationId);
|
||||
['items' => $repos, 'total' => $total] = $github->searchRepositories($providerInstallationId, $owner, $page, $limit, $search);
|
||||
['items' => $repos, 'total' => $total] = $github->searchRepositories($owner, $page, $limit, $search);
|
||||
|
||||
$repos = \array_map(function ($repo) use ($installation) {
|
||||
$repo['id'] = \strval($repo['id'] ?? '');
|
||||
|
||||
@@ -362,7 +362,9 @@ class Migrations extends Action
|
||||
'targets.read',
|
||||
'targets.write',
|
||||
'webhooks.read',
|
||||
'webhooks.write'
|
||||
'webhooks.write',
|
||||
'project.read',
|
||||
'project.write'
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ class Variables extends Base
|
||||
public const ALLOWED_ATTRIBUTES = [
|
||||
'key',
|
||||
'resourceType',
|
||||
'resourceId'
|
||||
'resourceId',
|
||||
'secret',
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Appwrite\Utopia\Request\Filters;
|
||||
|
||||
use Appwrite\Query;
|
||||
use Appwrite\Utopia\Request\Filter;
|
||||
|
||||
class V21 extends Filter
|
||||
@@ -13,6 +14,12 @@ class V21 extends Filter
|
||||
case 'webhooks.create':
|
||||
$content = $this->fillWebhookid($content);
|
||||
break;
|
||||
case 'project.createVariable':
|
||||
$content = $this->fillVariableId($content);
|
||||
break;
|
||||
case 'project.listVariables':
|
||||
$content = $this->preserveVariablesQueries($content);
|
||||
break;
|
||||
case 'functions.createTemplateDeployment':
|
||||
case 'sites.createTemplateDeployment':
|
||||
$content = $this->convertVersionToTypeAndReference($content);
|
||||
@@ -57,4 +64,19 @@ class V21 extends Filter
|
||||
$content['webhookId'] = $content['webhookId'] ?? 'unique()';
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function fillVariableId(array $content): array
|
||||
{
|
||||
$content['variableId'] = $content['variableId'] ?? 'unique()';
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function preserveVariablesQueries(array $content): array
|
||||
{
|
||||
$content['queries'] = $content['queries'] ?? [
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
];
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@ trait ProjectCustom
|
||||
'tokens.write',
|
||||
'webhooks.read',
|
||||
'webhooks.write',
|
||||
'project.read',
|
||||
'project.write'
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
@@ -2182,11 +2182,138 @@ class AccountCustomClientTest extends Scope
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
]);
|
||||
], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://localhost/v1/mock/tests/general/oauth2', $response['headers']['location']);
|
||||
|
||||
$oauthClient = new Client();
|
||||
$oauthClient->setEndpoint('');
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/callback/mock/' . $this->getProject()['$id'] . '?code=', $response['headers']['location']);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/mock/redirect?code=', $response['headers']['location']);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
|
||||
$this->assertArrayHasKey('a_session_' . $this->getProject()['$id'] . '_legacy', $response['cookies']);
|
||||
$this->assertArrayHasKey('a_session_' . $this->getProject()['$id'], $response['cookies']);
|
||||
|
||||
$oauthUserCookie = $response['cookies']['a_session_' . $this->getProject()['$id']];
|
||||
$this->assertNotEmpty($oauthUserCookie);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('success', $response['body']['result']);
|
||||
|
||||
// Ensure user is authenticated
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', [
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $oauthUserCookie,
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('useroauth@localhost.test', $response['body']['email']);
|
||||
|
||||
$oauthUserId = $response['body']['$id'];
|
||||
$this->assertNotEmpty($oauthUserId);
|
||||
|
||||
// Ensure session looks as expected
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/current', [
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $oauthUserCookie,
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($oauthUserId, $response['body']['userId']);
|
||||
$this->assertEquals('mock', $response['body']['provider']);
|
||||
|
||||
// Same sign-in again, but this time with oauth2 token flow
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/tokens/oauth2/' . $provider, array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'success' => 'http://localhost/v1/mock/tests/general/oauth2/success',
|
||||
'failure' => 'http://localhost/v1/mock/tests/general/oauth2/failure',
|
||||
], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://localhost/v1/mock/tests/general/oauth2', $response['headers']['location']);
|
||||
|
||||
$oauthClient = new Client();
|
||||
$oauthClient->setEndpoint('');
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/callback/mock/' . $this->getProject()['$id'] . '?code=', $response['headers']['location']);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/mock/redirect?code=', $response['headers']['location']);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(301, $response['headers']['status-code']);
|
||||
$this->assertStringStartsWith('http://localhost/v1/mock/tests/general/oauth2/success?secret=', $response['headers']['location']);
|
||||
|
||||
$oauthParamsString = \parse_url($response['headers']['location'], PHP_URL_QUERY);
|
||||
$oauthParams = [];
|
||||
\parse_str($oauthParamsString, $oauthParams);
|
||||
|
||||
$this->assertNotEmpty($oauthParams['secret']);
|
||||
$this->assertNotEmpty($oauthParams['userId']);
|
||||
|
||||
$response = $oauthClient->call(Client::METHOD_GET, $response['headers']['location'], followRedirects: false);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('success', $response['body']['result']);
|
||||
|
||||
// Claim session
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/token', [
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], [
|
||||
'userId' => $oauthParams['userId'],
|
||||
'secret' => $oauthParams['secret'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertEquals('mock', $response['body']['provider']);
|
||||
|
||||
$this->assertArrayHasKey('a_session_' . $this->getProject()['$id'] . '_legacy', $response['cookies']);
|
||||
$this->assertArrayHasKey('a_session_' . $this->getProject()['$id'], $response['cookies']);
|
||||
|
||||
$oauthUserCookie = $response['cookies']['a_session_' . $this->getProject()['$id']];
|
||||
$this->assertNotEmpty($oauthUserCookie);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account', [
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $oauthUserCookie,
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals('useroauth@localhost.test', $response['body']['email']);
|
||||
|
||||
$oauthUserId = $response['body']['$id'];
|
||||
$this->assertNotEmpty($oauthUserId);
|
||||
|
||||
// Ensure session looks as expected
|
||||
$response = $this->client->call(Client::METHOD_GET, '/account/sessions/current', [
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $oauthUserCookie,
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals($oauthUserId, $response['body']['userId']);
|
||||
$this->assertEquals('mock', $response['body']['provider']);
|
||||
|
||||
/**
|
||||
* Test for Failure when disabled
|
||||
*/
|
||||
|
||||
@@ -264,7 +264,7 @@ trait FunctionsBase
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
|
||||
@@ -991,7 +991,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
*/
|
||||
$folder = 'large';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/$folder/code.tar.gz";
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
$chunkSize = 5 * 1024 * 1024;
|
||||
$handle = @fopen($code, "rb");
|
||||
|
||||
@@ -3464,7 +3464,7 @@ trait Base
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
|
||||
@@ -1188,7 +1188,7 @@ trait MigrationsBase
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Project;
|
||||
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
|
||||
class VariablesConsoleClientTest extends Scope
|
||||
{
|
||||
use VariablesBase;
|
||||
use ProjectCustom;
|
||||
use SideConsole;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\E2E\Services\Project;
|
||||
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
|
||||
class VariablesCustomServerTest extends Scope
|
||||
{
|
||||
use VariablesBase;
|
||||
use ProjectCustom;
|
||||
use SideServer;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$stdout = '';
|
||||
$folder = 'timeout';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
// Create variable first
|
||||
$this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/variables', array_merge([
|
||||
@@ -734,7 +734,7 @@ class WebhooksCustomServerTest extends Scope
|
||||
$stdout = '';
|
||||
$folder = 'timeout';
|
||||
$code = realpath(__DIR__ . '/../../../resources/functions') . "/{$folder}/code.tar.gz";
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/{$folder} && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
|
||||
@@ -274,6 +274,7 @@ trait ProjectsBase
|
||||
'x-appwrite-project' => $projectData['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST',
|
||||
'value' => 'TESTINGVALUE',
|
||||
'secret' => false
|
||||
@@ -288,6 +289,7 @@ trait ProjectsBase
|
||||
'x-appwrite-project' => $projectData['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_1',
|
||||
'value' => 'TESTINGVALUE_1',
|
||||
'secret' => true
|
||||
|
||||
@@ -4686,6 +4686,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_CREATE',
|
||||
'value' => 'TESTINGVALUE',
|
||||
'secret' => false
|
||||
@@ -4702,6 +4703,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_CREATE_1',
|
||||
'value' => 'TESTINGVALUE_1',
|
||||
'secret' => true
|
||||
@@ -4720,6 +4722,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_CREATE',
|
||||
'value' => 'ANOTHERTESTINGVALUE'
|
||||
]);
|
||||
@@ -4732,6 +4735,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => str_repeat("A", 256),
|
||||
'value' => 'TESTINGVALUE'
|
||||
]);
|
||||
@@ -4744,6 +4748,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'LONGKEY',
|
||||
'value' => str_repeat("#", 8193),
|
||||
]);
|
||||
@@ -4889,18 +4894,6 @@ class ProjectsConsoleClientTest extends Scope
|
||||
$this->assertContains("APP_TEST_UPDATE", $variableKeys);
|
||||
$this->assertContains("APP_TEST_UPDATE_1", $variableKeys);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
@@ -4909,6 +4902,19 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'value' => 'TESTINGVALUEUPDATED_2'
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertSame('TESTINGVALUEUPDATED_2', $response['body']['value']);
|
||||
$this->assertSame('APP_TEST_UPDATE', $response['body']['key']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['variableId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $data['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
$longKey = str_repeat("A", 256);
|
||||
@@ -4958,6 +4964,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $projectData['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_DELETE',
|
||||
'value' => 'TESTINGVALUE',
|
||||
'secret' => false
|
||||
@@ -4972,6 +4979,7 @@ class ProjectsConsoleClientTest extends Scope
|
||||
'x-appwrite-project' => $projectData['projectId'],
|
||||
'x-appwrite-mode' => 'admin',
|
||||
], $this->getHeaders()), [
|
||||
'variableId' => 'unique()',
|
||||
'key' => 'APP_TEST_DELETE_1',
|
||||
'value' => 'TESTINGVALUE_1',
|
||||
'secret' => true
|
||||
|
||||
@@ -271,7 +271,7 @@ trait ProxyBase
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
@@ -288,7 +288,7 @@ trait ProxyBase
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/functions') . "/$function";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $stdout, $stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
|
||||
@@ -241,7 +241,7 @@ trait SitesBase
|
||||
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
|
||||
$tarPath = "$folderPath/code.tar.gz";
|
||||
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
Console::execute("cd $folderPath && tar --exclude code.tar.gz --exclude node_modules -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
|
||||
if (filesize($tarPath) > 1024 * 1024 * 5) {
|
||||
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
|
||||
|
||||
Reference in New Issue
Block a user