mirror of
https://github.com/appwrite/appwrite
synced 2026-05-22 16:38:32 +00:00
Merge branch 'feat-git-integration' into feat-git-integration-migrations
This commit is contained in:
commit
0ebd6d43d5
21 changed files with 260 additions and 115 deletions
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -46,7 +46,7 @@ jobs:
|
|||
- name: Start Appwrite
|
||||
run: |
|
||||
docker compose up -d
|
||||
sleep 60
|
||||
sleep 30
|
||||
|
||||
- name: Doctor
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -363,6 +363,11 @@ return [
|
|||
'description' => 'The requested range is not satisfiable. Please check the value of the Range header.',
|
||||
'code' => 416,
|
||||
],
|
||||
Exception::STORAGE_INVALID_APPWRITE_ID => [
|
||||
'name' => Exception::STORAGE_INVALID_APPWRITE_ID,
|
||||
'description' => 'The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is valid id and not unique().',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** VCS */
|
||||
Exception::INSTALLATION_NOT_FOUND => [
|
||||
|
|
@ -385,6 +390,11 @@ return [
|
|||
'description' => 'External contribution is already authorized.',
|
||||
'code' => 409,
|
||||
],
|
||||
Exception::GENERAL_PROVIDER_FAILURE => [
|
||||
'name' => Exception::GENERAL_PROVIDER_FAILURE,
|
||||
'description' => 'VCS (Version Control System) provider failed to proccess the request.',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** Functions */
|
||||
Exception::FUNCTION_NOT_FOUND => [
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
"emails.magicSession.signature": "Equipa {{project}}",
|
||||
"emails.recovery.subject": "Redefinição de senha",
|
||||
"emails.recovery.hello": "Olá {{name}}",
|
||||
"emails.recovery.body": "tilize este link para redefinir a palavra-passe do seu projecto {{project}}",
|
||||
"emails.recovery.body": "Utilize este link para redefinir a palavra-passe do seu projecto {{project}}",
|
||||
"emails.recovery.footer": "Se não pediu para redefinir a sua palavra-passe, pode ignorar esta mensagem.",
|
||||
"emails.recovery.thanks": "Obrigado",
|
||||
"emails.recovery.signature": "Equipa {{project}}",
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit a1ec99e86331e5eeb56614c69f50e83f334deafb
|
||||
Subproject commit 451e591a1d6c0843fdaef131f1064fd6cdbb2a3b
|
||||
|
|
@ -1086,11 +1086,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
|||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Text(0, 0), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true)
|
||||
->param('array', false, new Boolean(), 'Is attribute an array?', true)
|
||||
->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('database')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
|
||||
// Ensure attribute default is within required size
|
||||
$validator = new Text($size, 0);
|
||||
|
|
@ -1098,6 +1099,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
|||
throw new Exception(Exception::ATTRIBUTE_VALUE_INVALID, $validator->getDescription());
|
||||
}
|
||||
|
||||
$filters = [];
|
||||
|
||||
if ($encrypt) {
|
||||
$filters[] = 'encrypt';
|
||||
}
|
||||
|
||||
$attribute = createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
|
|
@ -1105,6 +1112,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string
|
|||
'required' => $required,
|
||||
'default' => $default,
|
||||
'array' => $array,
|
||||
'filters' => $filters,
|
||||
]), $response, $dbForProject, $database, $events);
|
||||
|
||||
$response
|
||||
|
|
@ -1509,6 +1517,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
|
|||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, bool $array, Response $response, Database $dbForProject, EventDatabase $database, Event $events) {
|
||||
|
||||
$filters[] = 'datetime';
|
||||
|
||||
$attribute = createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_DATETIME,
|
||||
|
|
@ -1516,7 +1526,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/dateti
|
|||
'required' => $required,
|
||||
'default' => $default,
|
||||
'array' => $array,
|
||||
'filters' => ['datetime']
|
||||
'filters' => $filters,
|
||||
]), $response, $dbForProject, $database, $events);
|
||||
|
||||
$response
|
||||
|
|
@ -1739,6 +1749,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/attributes/strin
|
|||
->inject('dbForProject')
|
||||
->inject('events')
|
||||
->action(function (string $databaseId, string $collectionId, string $key, ?bool $required, ?string $default, Response $response, Database $dbForProject, Event $events) {
|
||||
|
||||
$attribute = updateAttribute(
|
||||
databaseId: $databaseId,
|
||||
collectionId: $collectionId,
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ App::post('/v1/functions')
|
|||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
->param('logging', true, new Boolean(), 'Do executions get logged?', true)
|
||||
->param('entrypoint', '', new Text(1028), 'Entrypoint File.')
|
||||
->param('commands', '', new Text(1028, 0), 'Build Commands.', true)
|
||||
->param('commands', '', new Text(8192, 0), 'Build Commands.', true)
|
||||
->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for vcs deployment.', true)
|
||||
->param('providerRepositoryId', '', new Text(128, 0), 'Repository ID of the repo linked to the function', true)
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true)
|
||||
|
|
@ -165,7 +165,12 @@ App::post('/v1/functions')
|
|||
|
||||
// build from template
|
||||
$template = new Document([]);
|
||||
if (!empty($templateRepository) && !empty($templateOwner) && !empty($templateRootDirectory) && !empty($templateBranch)) {
|
||||
if (
|
||||
!empty($templateRepository)
|
||||
&& !empty($templateOwner)
|
||||
&& !empty($templateRootDirectory)
|
||||
&& !empty($templateBranch)
|
||||
) {
|
||||
$template->setAttribute('repositoryName', $templateRepository)
|
||||
->setAttribute('ownerName', $templateOwner)
|
||||
->setAttribute('rootDirectory', $templateRootDirectory)
|
||||
|
|
@ -609,7 +614,7 @@ App::put('/v1/functions/:functionId')
|
|||
->param('enabled', true, new Boolean(), 'Is function enabled?', true)
|
||||
->param('logging', true, new Boolean(), 'Do executions get logged?', true)
|
||||
->param('entrypoint', '', new Text(1028), 'Entrypoint File.')
|
||||
->param('commands', '', new Text(1028, 0), 'Build Commands.', true)
|
||||
->param('commands', '', new Text(8192, 0), 'Build Commands.', true)
|
||||
->param('installationId', '', new Text(128, 0), 'Appwrite Installation ID for vcs deployment.', true)
|
||||
->param('providerRepositoryId', '', new Text(128, 0), 'Repository ID of the repo linked to the function', true)
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true)
|
||||
|
|
@ -1273,7 +1278,8 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
|||
->inject('dbForConsole')
|
||||
->inject('project')
|
||||
->inject('gitHub')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, GitHub $github) use ($redeployVcs) {
|
||||
->inject('events')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Database $dbForConsole, Document $project, GitHub $github, Event $events) use ($redeployVcs) {
|
||||
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
|
@ -1298,6 +1304,10 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/builds/:buildId')
|
|||
|
||||
$redeployVcs($request, $function, $project, $installation, $dbForProject, new Document([]), $github);
|
||||
|
||||
$events
|
||||
->setParam('functionId', $function->getId())
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
|
|
@ -1318,7 +1328,7 @@ App::post('/v1/functions/:functionId/executions')
|
|||
->param('async', false, new Boolean(), 'Execute code in the background. Default value is false.', true)
|
||||
->param('path', '/', new Text(2048), 'HTTP path of execution. Path can include query params. Default value is /', true)
|
||||
->param('method', 'POST', new Whitelist(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], true), 'HTTP method of execution. Default value is GET.', true)
|
||||
->param('headers', [], new Assoc(), 'HTP headers of execution. Defaults to empty.', true)
|
||||
->param('headers', [], new Assoc(), 'HTTP headers of execution. Defaults to empty.', true)
|
||||
->inject('response')
|
||||
->inject('project')
|
||||
->inject('dbForProject')
|
||||
|
|
@ -1476,11 +1486,9 @@ App::post('/v1/functions/:functionId/executions')
|
|||
$vars = [];
|
||||
|
||||
// Shared vars
|
||||
$varsShared = $project->getAttribute('variables', []);
|
||||
$vars = \array_merge($vars, \array_reduce($varsShared, function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
return $carry;
|
||||
}, []));
|
||||
foreach ($project->getAttribute('variables', []) as $var) {
|
||||
$vars[$var->getAttribute('key')] = $var->getAttribute('value', '');
|
||||
}
|
||||
|
||||
// Function vars
|
||||
$vars = \array_merge($vars, array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) {
|
||||
|
|
@ -1825,7 +1833,12 @@ App::get('/v1/functions/:functionId/variables/:variableId')
|
|||
}
|
||||
|
||||
$variable = $dbForProject->getDocument('variables', $variableId);
|
||||
if ($variable === false || $variable->isEmpty() || $variable->getAttribute('resourceInternalId') !== $function->getInternalId() || $variable->getAttribute('resourceType') !== 'function') {
|
||||
if (
|
||||
$variable === false ||
|
||||
$variable->isEmpty() ||
|
||||
$variable->getAttribute('resourceInternalId') !== $function->getInternalId() ||
|
||||
$variable->getAttribute('resourceType') !== 'function'
|
||||
) {
|
||||
throw new Exception(Exception::VARIABLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ App::post('/v1/proxy/rules')
|
|||
|
||||
$message .= '.';
|
||||
} else {
|
||||
$message = "Domain already assigned to different project.";
|
||||
$message = 'Domain already assigned to different project.';
|
||||
}
|
||||
|
||||
throw new Exception(Exception::RULE_ALREADY_EXISTS, $message);
|
||||
|
|
|
|||
|
|
@ -443,6 +443,11 @@ App::post('/v1/storage/buckets/:bucketId/files')
|
|||
throw new Exception(Exception::STORAGE_INVALID_CONTENT_RANGE);
|
||||
}
|
||||
|
||||
$idValidator = new UID();
|
||||
if (!$idValidator->isValid($request->getHeader('x-appwrite-id'))) {
|
||||
throw new Exception(Exception::STORAGE_INVALID_APPWRITE_ID);
|
||||
}
|
||||
|
||||
// TODO remove the condition that checks `$end === $fileSize` in next breaking version
|
||||
if ($end === $fileSize - 1 || $end === $fileSize) {
|
||||
//if it's a last chunks the chunk size might differ, so we set the $chunks and $chunk to -1 notify it's last chunk
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ use Utopia\Detector\Adapter\Swift;
|
|||
use Utopia\Detector\Detector;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
||||
use function PHPUnit\Framework\throwException;
|
||||
use function Swoole\Coroutine\batch;
|
||||
|
||||
$createGitDeployments = function (GitHub $github, string $providerInstallationId, array $repositories, string $providerBranch, string $providerBranchUrl, string $providerRepositoryName, string $providerRepositoryUrl, string $providerRepositoryOwner, string $providerCommitHash, string $providerCommitAuthor, string $providerCommitAuthorUrl, string $providerCommitMessage, string $providerCommitUrl, string $providerPullRequestId, bool $external, Database $dbForConsole, callable $getProjectDB, Request $request) {
|
||||
|
|
@ -702,7 +703,11 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
|
|||
$dbForConsole->updateDocument('identities', $identity->getId(), $identity);
|
||||
}
|
||||
|
||||
$repository = $oauth2->createRepository($accessToken, $name, $private);
|
||||
try {
|
||||
$repository = $oauth2->createRepository($accessToken, $name, $private);
|
||||
} catch (Exception $exception) {
|
||||
throw new Exception(Exception::GENERAL_PROVIDER_FAILURE, "GitHub failed to process the request: " . $exception->getMessage());
|
||||
}
|
||||
} else {
|
||||
$providerInstallationId = $installation->getAttribute('providerInstallationId');
|
||||
$privateKey = App::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
||||
|
|
@ -710,7 +715,11 @@ App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
|
|||
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
|
||||
$owner = $github->getOwnerName($providerInstallationId);
|
||||
|
||||
$repository = $github->createRepository($owner, $name, $private);
|
||||
try {
|
||||
$repository = $github->createRepository($owner, $name, $private);
|
||||
} catch (Exception $exception) {
|
||||
throw new Exception(Exception::GENERAL_PROVIDER_FAILURE, "GitHub failed to process the request: " . $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($repository['message'])) {
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ App::init()
|
|||
Request::setRoute($route);
|
||||
|
||||
if ($route === null) {
|
||||
return $response->setStatusCode(404)->send("Not Found");
|
||||
return $response->setStatusCode(404)->send('Not Found');
|
||||
}
|
||||
|
||||
$requestFormat = $request->getHeader('x-appwrite-response-format', App::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
|
|
|
|||
|
|
@ -330,14 +330,15 @@ class BuildsV1 extends Worker
|
|||
|
||||
$vars = [];
|
||||
|
||||
// global vars
|
||||
$vars = \array_merge($vars, \array_reduce($dbForProject->find('variables', [
|
||||
// Global vars
|
||||
$varsFromProject = $dbForProject->find('variables', [
|
||||
Query::equal('resourceType', ['project']),
|
||||
Query::limit(APP_LIMIT_SUBQUERY)
|
||||
]), function (array $carry, Document $var) {
|
||||
$carry[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
return $carry;
|
||||
}, []));
|
||||
]);
|
||||
|
||||
foreach ($varsFromProject as $var) {
|
||||
$vars[$var->getAttribute('key')] = $var->getAttribute('value') ?? '';
|
||||
}
|
||||
|
||||
// Function vars
|
||||
$vars = \array_merge($vars, array_reduce($function->getAttribute('vars', []), function (array $carry, Document $var) {
|
||||
|
|
@ -454,12 +455,15 @@ class BuildsV1 extends Worker
|
|||
/** Update function schedule */
|
||||
$dbForConsole = $this->getConsoleDB();
|
||||
// Inform scheduler if function is still active
|
||||
$schedule = $dbForConsole->getDocument('schedules', $function->getAttribute('scheduleId'));
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
$scheduleId = $function->getAttribute('scheduleId', '');
|
||||
if (!empty($scheduleId)) {
|
||||
$schedule = $dbForConsole->getDocument('schedules', $scheduleId);
|
||||
$schedule
|
||||
->setAttribute('resourceUpdatedAt', DateTime::now())
|
||||
->setAttribute('schedule', $function->getAttribute('schedule'))
|
||||
->setAttribute('active', !empty($function->getAttribute('schedule')) && !empty($function->getAttribute('deployment')));
|
||||
Authorization::skip(fn () => $dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule));
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
$endTime = DateTime::now();
|
||||
$durationEnd = \microtime(true);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"appwrite/sdk-generator": "dev-master as 0.33.99",
|
||||
"appwrite/sdk-generator": "0.34.*",
|
||||
"ext-fileinfo": "*",
|
||||
"phpunit/phpunit": "9.5.20",
|
||||
"squizlabs/php_codesniffer": "^3.7",
|
||||
|
|
|
|||
70
composer.lock
generated
70
composer.lock
generated
|
|
@ -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": "b87e28f6f096af1fd3b1ddee62fe2f13",
|
||||
"content-hash": "e4934eff80bec5e9fe402528df07d72d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -727,16 +727,16 @@
|
|||
},
|
||||
{
|
||||
"name": "matomo/device-detector",
|
||||
"version": "6.1.4",
|
||||
"version": "6.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matomo-org/device-detector.git",
|
||||
"reference": "74f6c4f6732b3ad6cdf25560746841d522969112"
|
||||
"reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/74f6c4f6732b3ad6cdf25560746841d522969112",
|
||||
"reference": "74f6c4f6732b3ad6cdf25560746841d522969112",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/40ca2990dba2c1719e5c62168e822e0b86c167d4",
|
||||
"reference": "40ca2990dba2c1719e5c62168e822e0b86c167d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -792,7 +792,7 @@
|
|||
"source": "https://github.com/matomo-org/matomo",
|
||||
"wiki": "https://dev.matomo.org/"
|
||||
},
|
||||
"time": "2023-08-02T08:48:53+00:00"
|
||||
"time": "2023-08-17T16:17:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mongodb/mongodb",
|
||||
|
|
@ -1963,16 +1963,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "8a1d4de19002e4c8eabf368edff6b653b6722880"
|
||||
"reference": "af4233f4ff6a37982dad294033199ce29cafc00c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/8a1d4de19002e4c8eabf368edff6b653b6722880",
|
||||
"reference": "8a1d4de19002e4c8eabf368edff6b653b6722880",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/af4233f4ff6a37982dad294033199ce29cafc00c",
|
||||
"reference": "af4233f4ff6a37982dad294033199ce29cafc00c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2015,9 +2015,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/0.3.0"
|
||||
"source": "https://github.com/utopia-php/migration/tree/0.3.1"
|
||||
},
|
||||
"time": "2023-08-16T11:57:13+00:00"
|
||||
"time": "2023-08-17T14:18:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
|
|
@ -2564,6 +2564,12 @@
|
|||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "fc9c38a3f84a4391470cc7184199dec6f953b144"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/fc9c38a3f84a4391470cc7184199dec6f953b144",
|
||||
"reference": "fc9c38a3f84a4391470cc7184199dec6f953b144",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"adhocore/jwt": "^1.1",
|
||||
"php": ">=8.0",
|
||||
|
|
@ -2582,25 +2588,7 @@
|
|||
"Utopia\\Detector\\": "src/Detector"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/VCS"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"lint": [
|
||||
"./vendor/bin/pint --test --config pint.json"
|
||||
],
|
||||
"format": [
|
||||
"./vendor/bin/pint --config pint.json"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 8 -c phpstan.neon src tests"
|
||||
],
|
||||
"test": [
|
||||
"./vendor/bin/phpunit --configuration phpunit.xml --debug"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
|
|
@ -2611,6 +2599,10 @@
|
|||
"utopia",
|
||||
"vcs"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.1.0"
|
||||
},
|
||||
"time": "2023-08-09T20:48:51+00:00"
|
||||
},
|
||||
{
|
||||
|
|
@ -2798,7 +2790,7 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "dev-master",
|
||||
"version": "0.34.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
|
|
@ -2823,7 +2815,6 @@
|
|||
"phpunit/phpunit": "^9.5.21",
|
||||
"squizlabs/php_codesniffer": "^3.6"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
@ -5409,18 +5400,9 @@
|
|||
"time": "2023-07-26T07:16:09+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "appwrite/sdk-generator",
|
||||
"version": "9999999-dev",
|
||||
"alias": "0.33.99",
|
||||
"alias_normalized": "0.33.99.0"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"appwrite/sdk-generator": 20
|
||||
},
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
|
|
|||
|
|
@ -115,12 +115,14 @@ class Exception extends \Exception
|
|||
public const STORAGE_BUCKET_NOT_FOUND = 'storage_bucket_not_found';
|
||||
public const STORAGE_INVALID_CONTENT_RANGE = 'storage_invalid_content_range';
|
||||
public const STORAGE_INVALID_RANGE = 'storage_invalid_range';
|
||||
public const STORAGE_INVALID_APPWRITE_ID = 'storage_invalid_appwrite_id';
|
||||
|
||||
/** VCS */
|
||||
public const INSTALLATION_NOT_FOUND = 'installation_not_found';
|
||||
public const PROVIDER_REPOSITORY_NOT_FOUND = 'provider_repository_not_found';
|
||||
public const REPOSITORY_NOT_FOUND = 'repository_not_found';
|
||||
public const PROVIDER_CONTRIBUTION_CONFLICT = 'provider_contribution_conflict';
|
||||
public const GENERAL_PROVIDER_FAILURE = 'general_provider_failure';
|
||||
|
||||
/** Functions */
|
||||
public const FUNCTION_NOT_FOUND = 'function_not_found';
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ class V19 extends Migration
|
|||
$this->projectDB->setNamespace("_{$this->project->getInternalId()}");
|
||||
|
||||
$this->alterPermissionIndex('_metadata');
|
||||
$this->alterUidType('_metadata');
|
||||
|
||||
Console::info('Migrating Databases');
|
||||
$this->migrateDatabases();
|
||||
|
|
@ -57,11 +58,13 @@ class V19 extends Migration
|
|||
$databaseTable = "database_{$database->getInternalId()}";
|
||||
|
||||
$this->alterPermissionIndex($databaseTable);
|
||||
$this->alterUidType($databaseTable);
|
||||
|
||||
foreach ($this->documentsIterator($databaseTable) as $collection) {
|
||||
$collectionTable = "{$databaseTable}_collection_{$collection->getInternalId()}";
|
||||
Console::log("Migrating Collections of {$collectionTable} {$collection->getId()} ({$collection->getAttribute('name')})");
|
||||
$this->alterPermissionIndex($collectionTable);
|
||||
$this->alterUidType($collectionTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -98,6 +101,7 @@ class V19 extends Migration
|
|||
}
|
||||
if (!in_array($id, ['files', 'collections'])) {
|
||||
$this->alterPermissionIndex($id);
|
||||
$this->alterUidType($id);
|
||||
}
|
||||
|
||||
usleep(50000);
|
||||
|
|
@ -131,7 +135,7 @@ class V19 extends Migration
|
|||
protected function alterPermissionIndex($collectionName): void
|
||||
{
|
||||
try {
|
||||
$table = "`{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collectionName}_perms";
|
||||
$table = "`{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collectionName}_perms`";
|
||||
$this->pdo->prepare("
|
||||
ALTER TABLE {$table}
|
||||
DROP INDEX `_permission`,
|
||||
|
|
@ -142,6 +146,19 @@ class V19 extends Migration
|
|||
}
|
||||
}
|
||||
|
||||
protected function alterUidType($collectionName): void
|
||||
{
|
||||
try {
|
||||
$table = "`{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}_{$collectionName}`";
|
||||
$this->pdo->prepare("
|
||||
ALTER TABLE {$table}
|
||||
CHANGE COLUMN `_uid` `_uid` VARCHAR(255) NOT NULL ;
|
||||
")->execute();
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrating all Bucket tables.
|
||||
*
|
||||
|
|
@ -155,6 +172,7 @@ class V19 extends Migration
|
|||
$id = "bucket_{$bucket->getInternalId()}";
|
||||
Console::log("Migrating Bucket {$id} {$bucket->getId()} ({$bucket->getAttribute('name')})");
|
||||
$this->alterPermissionIndex($id);
|
||||
$this->alterUidType($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ class V12 extends Filter
|
|||
case Response::MODEL_WEBHOOK_LIST:
|
||||
case Response::MODEL_KEY_LIST:
|
||||
case Response::MODEL_PLATFORM_LIST:
|
||||
// case Response::MODEL_DOMAIN_LIST:
|
||||
case Response::MODEL_COUNTRY_LIST:
|
||||
case Response::MODEL_CONTINENT_LIST:
|
||||
case Response::MODEL_LANGUAGE_LIST:
|
||||
|
|
|
|||
|
|
@ -100,8 +100,6 @@ class Executor
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Listen to realtime logs stream of a runtime
|
||||
*
|
||||
* @param string $deploymentId
|
||||
|
|
|
|||
|
|
@ -593,6 +593,110 @@ class DatabasesCustomServerTest extends Scope
|
|||
$this->assertFalse($collection['body']['enabled']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testListCollections
|
||||
*/
|
||||
public function testCreateEncryptedAttribute(array $data): void
|
||||
{
|
||||
|
||||
$databaseId = $data['databaseId'];
|
||||
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
|
||||
// Create collection
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Encrypted Actors Data',
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
'documentSecurity' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $actors['headers']['status-code']);
|
||||
$this->assertEquals($actors['body']['name'], 'Encrypted Actors Data');
|
||||
|
||||
/**
|
||||
* Test for creating encrypted attributes
|
||||
*/
|
||||
|
||||
$attributesPath = '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/attributes';
|
||||
|
||||
$firstName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'firstName',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'lastName',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
'encrypt' => true,
|
||||
]);
|
||||
|
||||
|
||||
/**
|
||||
* Check status of every attribute
|
||||
*/
|
||||
$this->assertEquals(202, $firstName['headers']['status-code']);
|
||||
$this->assertEquals('firstName', $firstName['body']['key']);
|
||||
$this->assertEquals('string', $firstName['body']['type']);
|
||||
|
||||
$this->assertEquals(202, $lastName['headers']['status-code']);
|
||||
$this->assertEquals('lastName', $lastName['body']['key']);
|
||||
$this->assertEquals('string', $lastName['body']['type']);
|
||||
|
||||
// Wait for database worker to finish creating attributes
|
||||
sleep(2);
|
||||
|
||||
// Creating document to ensure cache is purged on schema change
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'firstName' => 'Jonah',
|
||||
'lastName' => 'Jameson',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
// Check document to ensure cache is purged on schema change
|
||||
$document = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'] . '/documents/' . $document['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->assertEquals(200, $document['headers']['status-code']);
|
||||
$this->assertEquals('Jonah', $document['body']['firstName']);
|
||||
$this->assertEquals('Jameson', $document['body']['lastName']);
|
||||
}
|
||||
|
||||
public function testDeleteAttribute(): array
|
||||
{
|
||||
$database = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
|
|
|
|||
|
|
@ -241,6 +241,29 @@ trait StorageBase
|
|||
|
||||
$this->assertEquals(400, $failedBucket['headers']['status-code']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE set x-appwrite-id to unique()
|
||||
*/
|
||||
$source = realpath(__DIR__ . '/../../../resources/logo.png');
|
||||
$totalSize = \filesize($source);
|
||||
$res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'content-range' => 'bytes 0-' . $size . '/' . $size,
|
||||
'x-appwrite-id' => 'unique()',
|
||||
], $this->getHeaders()), [
|
||||
'fileId' => ID::unique(),
|
||||
'file' => new CURLFile($source, 'image/png', 'logo.png'),
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $res['headers']['status-code']);
|
||||
$this->assertEquals('The value for x-appwrite-id header is invalid. Please check the value of the x-appwrite-id header is valid id and not unique().', $res['body']['message']);
|
||||
|
||||
return ['bucketId' => $bucketId, 'fileId' => $file['body']['$id'], 'largeFileId' => $largeFile['body']['$id'], 'largeBucketId' => $bucket2['body']['$id']];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace Tests\E2E\Services\Teams;
|
|||
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
||||
trait TeamsBaseServer
|
||||
{
|
||||
|
|
|
|||
|
|
@ -562,40 +562,6 @@ class V15Test extends TestCase
|
|||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @dataProvider createdAtUpdatedAtProvider
|
||||
// */
|
||||
// public function testDomain(array $content, array $expected): void
|
||||
// {
|
||||
// $model = Response::MODEL_DOMAIN;
|
||||
|
||||
// $result = $this->filter->parse($content, $model);
|
||||
|
||||
// $this->assertEquals($expected, $result);
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * @dataProvider createdAtUpdatedAtProvider
|
||||
// */
|
||||
// public function testDomainList(array $content, array $expected): void
|
||||
// {
|
||||
// $model = Response::MODEL_DOMAIN_LIST;
|
||||
|
||||
// $content = [
|
||||
// 'domains' => [$content],
|
||||
// 'total' => 1,
|
||||
// ];
|
||||
|
||||
// $expected = [
|
||||
// 'domains' => [$expected],
|
||||
// 'total' => 1,
|
||||
// ];
|
||||
|
||||
// $result = $this->filter->parse($content, $model);
|
||||
|
||||
// $this->assertEquals($expected, $result);
|
||||
// }
|
||||
|
||||
public function executionProvider(): array
|
||||
{
|
||||
return [
|
||||
|
|
|
|||
Loading…
Reference in a new issue