mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge remote-tracking branch 'origin/1.8.x' into feat-txn
# Conflicts: # composer.lock
This commit is contained in:
@@ -5745,7 +5745,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 448,
|
||||
"weight": 460,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -5820,7 +5820,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 446,
|
||||
"weight": 458,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -5936,7 +5936,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 447,
|
||||
"weight": 459,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7491,7 +7491,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 420,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -7579,7 +7579,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 412,
|
||||
"weight": 424,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -7724,7 +7724,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 413,
|
||||
"weight": 425,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -7822,7 +7822,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 416,
|
||||
"weight": 428,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -7961,7 +7961,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 414,
|
||||
"weight": 426,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -8063,7 +8063,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 418,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -8150,7 +8150,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 423,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -8268,7 +8268,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 422,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5745,7 +5745,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 448,
|
||||
"weight": 460,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -5820,7 +5820,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 446,
|
||||
"weight": 458,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -5936,7 +5936,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 447,
|
||||
"weight": 459,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7491,7 +7491,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 420,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -7579,7 +7579,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 412,
|
||||
"weight": 424,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -7724,7 +7724,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 413,
|
||||
"weight": 425,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -7822,7 +7822,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 416,
|
||||
"weight": 428,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -7961,7 +7961,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 414,
|
||||
"weight": 426,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -8063,7 +8063,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 418,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -8150,7 +8150,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 423,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -8268,7 +8268,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 422,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5845,7 +5845,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 448,
|
||||
"weight": 460,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -5918,7 +5918,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 446,
|
||||
"weight": 458,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -6035,7 +6035,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 447,
|
||||
"weight": 459,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7573,7 +7573,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 420,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -7657,7 +7657,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 412,
|
||||
"weight": 424,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -7799,7 +7799,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 413,
|
||||
"weight": 425,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -7891,7 +7891,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 416,
|
||||
"weight": 428,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -8025,7 +8025,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 414,
|
||||
"weight": 426,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -8124,7 +8124,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 418,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -8206,7 +8206,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 423,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -8317,7 +8317,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 422,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5845,7 +5845,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listExecutions",
|
||||
"group": "executions",
|
||||
"weight": 448,
|
||||
"weight": 460,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/list-executions.md",
|
||||
@@ -5918,7 +5918,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createExecution",
|
||||
"group": "executions",
|
||||
"weight": 446,
|
||||
"weight": 458,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/create-execution.md",
|
||||
@@ -6035,7 +6035,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getExecution",
|
||||
"group": "executions",
|
||||
"weight": 447,
|
||||
"weight": 459,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "functions\/get-execution.md",
|
||||
@@ -7573,7 +7573,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "listRows",
|
||||
"group": "rows",
|
||||
"weight": 420,
|
||||
"weight": 432,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/list-rows.md",
|
||||
@@ -7657,7 +7657,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "createRow",
|
||||
"group": "rows",
|
||||
"weight": 412,
|
||||
"weight": 424,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/create-row.md",
|
||||
@@ -7799,7 +7799,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "getRow",
|
||||
"group": "rows",
|
||||
"weight": 413,
|
||||
"weight": 425,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/get-row.md",
|
||||
@@ -7891,7 +7891,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "upsertRow",
|
||||
"group": "rows",
|
||||
"weight": 416,
|
||||
"weight": 428,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/upsert-row.md",
|
||||
@@ -8025,7 +8025,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "updateRow",
|
||||
"group": "rows",
|
||||
"weight": 414,
|
||||
"weight": 426,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/update-row.md",
|
||||
@@ -8124,7 +8124,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "deleteRow",
|
||||
"group": "rows",
|
||||
"weight": 418,
|
||||
"weight": 430,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/delete-row.md",
|
||||
@@ -8206,7 +8206,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "decrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 423,
|
||||
"weight": 435,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/decrement-row-column.md",
|
||||
@@ -8317,7 +8317,7 @@
|
||||
"x-appwrite": {
|
||||
"method": "incrementRowColumn",
|
||||
"group": "rows",
|
||||
"weight": 422,
|
||||
"weight": 434,
|
||||
"cookies": false,
|
||||
"type": "",
|
||||
"demo": "tablesdb\/increment-row-column.md",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@ use Utopia\Database\Exception\Authorization as AuthorizationException;
|
||||
use Utopia\Database\Exception\Duplicate;
|
||||
use Utopia\Database\Exception\Order as OrderException;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
@@ -282,7 +283,13 @@ App::get('/v1/teams/:teamId/prefs')
|
||||
|
||||
$prefs = $team->getAttribute('prefs', []);
|
||||
|
||||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
try {
|
||||
$prefs = new Document($prefs);
|
||||
} catch (StructureException $e) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage());
|
||||
}
|
||||
|
||||
$response->dynamic($prefs, Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
App::put('/v1/teams/:teamId')
|
||||
@@ -357,6 +364,11 @@ App::put('/v1/teams/:teamId/prefs')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->action(function (string $teamId, array $prefs, Response $response, Database $dbForProject, Event $queueForEvents) {
|
||||
try {
|
||||
$prefs = new Document($prefs);
|
||||
} catch (StructureException $e) {
|
||||
throw new Exception(Exception::DOCUMENT_INVALID_STRUCTURE, $e->getMessage());
|
||||
}
|
||||
|
||||
$team = $dbForProject->getDocument('teams', $teamId);
|
||||
|
||||
@@ -364,11 +376,13 @@ App::put('/v1/teams/:teamId/prefs')
|
||||
throw new Exception(Exception::TEAM_NOT_FOUND);
|
||||
}
|
||||
|
||||
$team = $dbForProject->updateDocument('teams', $team->getId(), $team->setAttribute('prefs', $prefs));
|
||||
$team = $dbForProject->updateDocument('teams', $team->getId(), new Document([
|
||||
'prefs' => $prefs->getArrayCopy()
|
||||
]));
|
||||
|
||||
$queueForEvents->setParam('teamId', $team->getId());
|
||||
|
||||
$response->dynamic(new Document($prefs), Response::MODEL_PREFERENCES);
|
||||
$response->dynamic($prefs, Response::MODEL_PREFERENCES);
|
||||
});
|
||||
|
||||
App::delete('/v1/teams/:teamId')
|
||||
|
||||
+109
-8
@@ -15,6 +15,7 @@ use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Vcs\Comment;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
@@ -135,11 +136,39 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
if (!$latestComment->isEmpty()) {
|
||||
$latestCommentId = $latestComment->getAttribute('providerCommentId', '');
|
||||
|
||||
$comment = new Comment();
|
||||
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
|
||||
$retries = 0;
|
||||
$lockAcquired = false;
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
while ($retries < 9) {
|
||||
$retries++;
|
||||
|
||||
try {
|
||||
$dbForPlatform->createDocument('vcsCommentLocks', new Document([
|
||||
'$id' => $latestCommentId
|
||||
]));
|
||||
$lockAcquired = true;
|
||||
break;
|
||||
} catch (\Throwable $err) {
|
||||
if ($retries >= 9) {
|
||||
Console::warning("Error creating vcs comment lock for " . $latestCommentId . ": " . $err->getMessage());
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($lockAcquired) {
|
||||
// Wrap in try/finally to ensure lock file gets deleted
|
||||
try {
|
||||
$comment = new Comment();
|
||||
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$comment = new Comment();
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
|
||||
@@ -177,11 +206,40 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
|
||||
foreach ($latestComments as $comment) {
|
||||
$latestCommentId = $comment->getAttribute('providerCommentId', '');
|
||||
$comment = new Comment();
|
||||
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
$retries = 0;
|
||||
$lockAcquired = false;
|
||||
|
||||
while ($retries < 9) {
|
||||
$retries++;
|
||||
|
||||
try {
|
||||
$dbForPlatform->createDocument('vcsCommentLocks', new Document([
|
||||
'$id' => $latestCommentId
|
||||
]));
|
||||
$lockAcquired = true;
|
||||
break;
|
||||
} catch (\Throwable $err) {
|
||||
if ($retries >= 9) {
|
||||
Console::warning("Error creating vcs comment lock for " . $latestCommentId . ": " . $err->getMessage());
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($lockAcquired) {
|
||||
// Wrap in try/finally to ensure lock file gets deleted
|
||||
try {
|
||||
$comment = new Comment();
|
||||
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, '');
|
||||
|
||||
$latestCommentId = \strval($github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment()));
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,6 +329,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
$ruleId = md5($domain);
|
||||
$previewRuleId = $ruleId;
|
||||
Authorization::skip(
|
||||
fn () => $dbForPlatform->createDocument('rules', new Document([
|
||||
'$id' => $ruleId,
|
||||
@@ -362,6 +421,48 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
||||
}
|
||||
}
|
||||
|
||||
if ($resource->getCollection() === 'sites' && !empty($latestCommentId) && !empty($previewRuleId)) {
|
||||
$retries = 0;
|
||||
$lockAcquired = false;
|
||||
|
||||
while ($retries < 9) {
|
||||
$retries++;
|
||||
|
||||
try {
|
||||
$dbForPlatform->createDocument('vcsCommentLocks', new Document([
|
||||
'$id' => $latestCommentId
|
||||
]));
|
||||
$lockAcquired = true;
|
||||
break;
|
||||
} catch (\Throwable $err) {
|
||||
if ($retries >= 9) {
|
||||
Console::warning("Error creating vcs comment lock for " . $latestCommentId . ": " . $err->getMessage());
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($lockAcquired) {
|
||||
// Wrap in try/finally to ensure lock file gets deleted
|
||||
try {
|
||||
$rule = Authorization::skip(fn () => $dbForPlatform->getDocument('rules', $previewRuleId));
|
||||
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS') === 'disabled' ? 'http' : 'https';
|
||||
$previewUrl = !empty($rule) ? ("{$protocol}://" . $rule->getAttribute('domain', '')) : '';
|
||||
|
||||
if (!empty($previewUrl)) {
|
||||
$comment = new Comment();
|
||||
$comment->parseComment($github->getComment($owner, $repositoryName, $latestCommentId));
|
||||
$comment->addBuild($project, $resource, $resourceType, $commentStatus, $deploymentId, $action, $previewUrl);
|
||||
$github->updateComment($owner, $repositoryName, $latestCommentId, $comment->generateComment());
|
||||
}
|
||||
} finally {
|
||||
$dbForPlatform->deleteDocument('vcsCommentLocks', $latestCommentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($providerCommitHash) && $resource->getAttribute('providerSilentMode', false) === false) {
|
||||
$resourceName = $resource->getAttribute('name');
|
||||
$projectName = $project->getAttribute('name');
|
||||
|
||||
+40
-27
@@ -562,15 +562,18 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
cpus: $spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT,
|
||||
memory: $spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT,
|
||||
logging: $resource->getAttribute('logging', true),
|
||||
requestTimeout: 30
|
||||
requestTimeout: 30,
|
||||
responseFormat: Executor::RESPONSE_FORMAT_ARRAY_HEADERS
|
||||
);
|
||||
|
||||
$headerOverrides = [];
|
||||
|
||||
// Branded 404 override
|
||||
$isResponseBranded = false;
|
||||
if ($executionResponse['statusCode'] === 404 && $deployment->getAttribute('adapter', '') === 'static') {
|
||||
$layout = new View(__DIR__ . '/../views/general/404.phtml');
|
||||
$executionResponse['body'] = $layout->render();
|
||||
$executionResponse['headers']['content-length'] = \strlen($executionResponse['body']);
|
||||
$headerOverrides['content-length'] = \strlen($executionResponse['body']);
|
||||
$isResponseBranded = true;
|
||||
}
|
||||
|
||||
@@ -580,15 +583,16 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
$transformation = new Transformation();
|
||||
$transformation->addAdapter(new Preview());
|
||||
$transformation->setInput($executionResponse['body']);
|
||||
$transformation->setTraits($executionResponse['headers']);
|
||||
|
||||
$simpleHeaders = [];
|
||||
foreach ($executionResponse['headers'] as $key => $value) {
|
||||
$simpleHeaders[$key] = \is_array($value) ? \implode(', ', $value) : $value;
|
||||
}
|
||||
|
||||
$transformation->setTraits($simpleHeaders);
|
||||
if ($isPreview && $transformation->transform()) {
|
||||
$executionResponse['body'] = $transformation->getOutput();
|
||||
|
||||
foreach ($executionResponse['headers'] as $key => $value) {
|
||||
if (\strtolower($key) === 'content-length') {
|
||||
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
|
||||
}
|
||||
}
|
||||
$headerOverrides['content-length'] = \strlen($executionResponse['body']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,25 +606,33 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
->setParam('code', $executionResponse['statusCode']);
|
||||
|
||||
$executionResponse['body'] = $layout->render();
|
||||
foreach ($executionResponse['headers'] as $key => $value) {
|
||||
if (\strtolower($key) === 'content-length') {
|
||||
$executionResponse['headers'][$key] = \strlen($executionResponse['body']);
|
||||
} elseif (\strtolower($key) === 'content-type') {
|
||||
$executionResponse['headers'][$key] = 'text/html';
|
||||
}
|
||||
}
|
||||
|
||||
$headerOverrides['content-length'] = \strlen($executionResponse['body']);
|
||||
$headerOverrides['content-type'] = 'text/html';
|
||||
}
|
||||
|
||||
if ($deployment->getAttribute('resourceType') === 'functions') {
|
||||
$executionResponse['headers']['x-appwrite-execution-id'] = $execution->getId();
|
||||
$headerOverrides['x-appwrite-execution-id'] = $execution->getId();
|
||||
} elseif ($deployment->getAttribute('resourceType') === 'sites') {
|
||||
$executionResponse['headers']['x-appwrite-log-id'] = $execution->getId();
|
||||
$headerOverrides['x-appwrite-log-id'] = $execution->getId();
|
||||
}
|
||||
|
||||
foreach ($headerOverrides as $key => $value) {
|
||||
if (\array_key_exists($key, $executionResponse['headers'])) {
|
||||
if (\is_array($executionResponse['headers'][$key])) {
|
||||
$executionResponse['headers'][$key][] = $value;
|
||||
} else {
|
||||
$executionResponse['headers'][$key] = [$executionResponse['headers'][$key], $value];
|
||||
}
|
||||
} else {
|
||||
$executionResponse['headers'][$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$headersFiltered = [];
|
||||
foreach ($executionResponse['headers'] as $key => $value) {
|
||||
if (\in_array(\strtolower($key), FUNCTION_ALLOWLIST_HEADERS_RESPONSE)) {
|
||||
$headersFiltered[] = ['name' => $key, 'value' => $value];
|
||||
$headersFiltered[] = ['name' => $key, 'value' => \is_array($value) ? \implode(', ', $value) : $value];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,7 +699,7 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
|
||||
$headers = [];
|
||||
foreach (($executionResponse['headers'] ?? []) as $key => $value) {
|
||||
$headers[] = ['name' => $key, 'value' => $value];
|
||||
$headers[] = ['name' => $key, 'value' => \is_array($value) ? \implode(', ', $value) : $value];
|
||||
}
|
||||
|
||||
$execution->setAttribute('responseBody', $executionResponse['body'] ?? '');
|
||||
@@ -696,16 +708,17 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
|
||||
$body = $execution['responseBody'] ?? '';
|
||||
|
||||
$contentType = 'text/plain';
|
||||
foreach ($execution['responseHeaders'] as $header) {
|
||||
if (\strtolower($header['name']) === 'content-type') {
|
||||
$contentType = $header['value'];
|
||||
}
|
||||
|
||||
if (\strtolower($header['name']) === 'transfer-encoding') {
|
||||
foreach ($executionResponse['headers'] as $name => $values) {
|
||||
if (\strtolower($name) === 'content-type') {
|
||||
$contentType = \is_array($values) ? $values[0] : $values;
|
||||
continue;
|
||||
}
|
||||
|
||||
$response->addHeader(\strtolower($header['name']), $header['value']);
|
||||
if (\strtolower($name) === 'transfer-encoding') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response->setHeader($name, $values);
|
||||
}
|
||||
|
||||
$response
|
||||
|
||||
+1
-1
@@ -966,7 +966,7 @@ services:
|
||||
hostname: exc1
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.8.1
|
||||
image: openruntimes/executor:0.11.0
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -57,8 +57,7 @@ class Mapper
|
||||
'datetime' => Type::string(),
|
||||
'json' => Types::json(),
|
||||
'none' => Types::json(),
|
||||
'any' => Types::json(),
|
||||
'spatial' => Types::json(),
|
||||
'any' => Types::json()
|
||||
];
|
||||
|
||||
foreach ($defaults as $type => $default) {
|
||||
|
||||
@@ -416,6 +416,8 @@ class Response extends SwooleResponse
|
||||
*/
|
||||
protected static bool $showSensitive = false;
|
||||
|
||||
protected SwooleHTTPResponse $swoole;
|
||||
|
||||
/**
|
||||
* Response constructor.
|
||||
*
|
||||
@@ -423,6 +425,8 @@ class Response extends SwooleResponse
|
||||
*/
|
||||
public function __construct(SwooleHTTPResponse $response)
|
||||
{
|
||||
$this->swoole = $response;
|
||||
|
||||
$this
|
||||
// General
|
||||
->setModel(new None())
|
||||
@@ -962,12 +966,18 @@ class Response extends SwooleResponse
|
||||
* Set Header
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param string|array<string> $value
|
||||
* @return void
|
||||
*/
|
||||
public function setHeader(string $key, string $value): void
|
||||
public function setHeader(string $key, mixed $value): void
|
||||
{
|
||||
$this->sendHeader($key, $value);
|
||||
if (is_array($value)) {
|
||||
// Temporary solution to support proxying Set-cookie (2 cookies, 1 name)
|
||||
// Ideally this would live in http library, supporting array of values in all adapters
|
||||
$this->swoole->header($key, $value);
|
||||
} else {
|
||||
$this->sendHeader($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,7 +15,6 @@ abstract class Model
|
||||
public const TYPE_DATETIME_EXAMPLE = '2020-10-15T06:38:00.000+00:00';
|
||||
public const TYPE_RELATIONSHIP = 'relationship';
|
||||
public const TYPE_PAYLOAD = 'payload';
|
||||
public const TYPE_SPATIAL = 'spatial';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
|
||||
@@ -12,7 +12,7 @@ class AttributeLine extends Attribute
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -12,7 +12,7 @@ class AttributePoint extends Attribute
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -12,7 +12,7 @@ class AttributePolygon extends Attribute
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -12,7 +12,7 @@ class ColumnLine extends Column
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for column when not provided. Cannot be set when column is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -12,7 +12,7 @@ class ColumnPoint extends Column
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for column when not provided. Cannot be set when column is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -12,7 +12,7 @@ class ColumnPolygon extends Column
|
||||
|
||||
$this
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_SPATIAL,
|
||||
'type' => self::TYPE_JSON,
|
||||
'description' => 'Default value for column when not provided. Cannot be set when column is required.',
|
||||
'default' => null,
|
||||
'required' => false,
|
||||
|
||||
@@ -9,6 +9,12 @@ use Utopia\System\System;
|
||||
|
||||
class Executor
|
||||
{
|
||||
// 0.8.6 is last version with object-based headers
|
||||
public const RESPONSE_FORMAT_OBJECT_HEADERS = '0.10.0';
|
||||
|
||||
// 0.9.0 is first version with array-based headers
|
||||
public const RESPONSE_FORMAT_ARRAY_HEADERS = '0.11.0';
|
||||
|
||||
public const METHOD_GET = 'GET';
|
||||
public const METHOD_POST = 'POST';
|
||||
public const METHOD_PUT = 'PUT';
|
||||
@@ -170,6 +176,7 @@ class Executor
|
||||
* @param string $entrypoint
|
||||
* @param string $runtimeEntrypoint
|
||||
* @param bool $logging
|
||||
* @param string $responseFormat
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
@@ -190,7 +197,8 @@ class Executor
|
||||
int $memory,
|
||||
bool $logging,
|
||||
string $runtimeEntrypoint = '',
|
||||
?int $requestTimeout = null
|
||||
?int $requestTimeout = null,
|
||||
string $responseFormat = self::RESPONSE_FORMAT_OBJECT_HEADERS
|
||||
) {
|
||||
if (empty($headers['host'])) {
|
||||
$headers['host'] = System::getEnv('_APP_DOMAIN', '');
|
||||
@@ -232,7 +240,7 @@ class Executor
|
||||
$requestTimeout = $timeout + 15;
|
||||
}
|
||||
|
||||
$response = $this->call($this->endpoint, self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId, 'content-type' => 'multipart/form-data', 'accept' => 'multipart/form-data' ], $params, true, $requestTimeout);
|
||||
$response = $this->call($this->endpoint, self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId, 'content-type' => 'multipart/form-data', 'accept' => 'multipart/form-data', 'x-executor-response-format' => $responseFormat ], $params, true, $requestTimeout);
|
||||
|
||||
$status = $response['headers']['status-code'];
|
||||
if ($status >= 400) {
|
||||
|
||||
@@ -6343,6 +6343,192 @@ trait DatabasesBase
|
||||
$this->assertEquals('Latest Event', $rows['body']['rows'][0]['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Utopia\Database\Exception
|
||||
* @throws \Utopia\Database\Exception\Query
|
||||
*/
|
||||
public function testCreatedBetween(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'CreatedBetween test'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('CreatedBetween test', $database['body']['name']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Create Collection
|
||||
$articles = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Articles',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $articles['headers']['status-code']);
|
||||
$this->assertEquals($articles['body']['name'], 'Articles');
|
||||
|
||||
// Create Attributes
|
||||
$title = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $title['headers']['status-code']);
|
||||
|
||||
$content = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'content',
|
||||
'size' => 5000,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $content['headers']['status-code']);
|
||||
|
||||
// Wait for attributes to be available
|
||||
sleep(2);
|
||||
|
||||
// Create first article
|
||||
$row1 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'First Article',
|
||||
'content' => 'This is the first article content',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row1['headers']['status-code']);
|
||||
$firstArticleCreatedAt = $row1['body']['$createdAt'];
|
||||
|
||||
// Sleep to ensure different timestamps
|
||||
sleep(1);
|
||||
|
||||
// Create second article
|
||||
$row2 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Second Article',
|
||||
'content' => 'This is the second article content',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row2['headers']['status-code']);
|
||||
$secondArticleCreatedAt = $row2['body']['$createdAt'];
|
||||
|
||||
// Sleep again
|
||||
sleep(1);
|
||||
|
||||
// Create third article
|
||||
$row3 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Third Article',
|
||||
'content' => 'This is the third article content',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row3['headers']['status-code']);
|
||||
$thirdArticleCreatedAt = $row3['body']['$createdAt'];
|
||||
|
||||
// Sleep again
|
||||
sleep(1);
|
||||
|
||||
// Create fourth article
|
||||
$row4 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Fourth Article',
|
||||
'content' => 'This is the fourth article content',
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row4['headers']['status-code']);
|
||||
|
||||
// Test createdBetween query - should return articles created between first and third (inclusive)
|
||||
$rows = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::createdBetween($firstArticleCreatedAt, $thirdArticleCreatedAt)->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertCount(3, $rows['body']['rows']);
|
||||
|
||||
// Verify the returned articles are the correct ones
|
||||
$titles = array_column($rows['body']['rows'], 'title');
|
||||
$this->assertContains('First Article', $titles);
|
||||
$this->assertContains('Second Article', $titles);
|
||||
$this->assertContains('Third Article', $titles);
|
||||
$this->assertNotContains('Fourth Article', $titles);
|
||||
|
||||
// Test createdBetween query - should return only the second article when using its timestamp for both bounds
|
||||
$rows = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $articles['body']['$id'] . '/rows',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::createdBetween($secondArticleCreatedAt, $secondArticleCreatedAt)->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertCount(1, $rows['body']['rows']);
|
||||
$this->assertEquals('Second Article', $rows['body']['rows'][0]['title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Utopia\Database\Exception
|
||||
* @throws \Utopia\Database\Exception\Query
|
||||
@@ -6689,6 +6875,249 @@ trait DatabasesBase
|
||||
$this->assertEquals('delivered', $rows['body']['rows'][0]['status']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Utopia\Database\Exception
|
||||
* @throws \Utopia\Database\Exception\Query
|
||||
*/
|
||||
public function testUpdatedBetween(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'UpdatedBetween test'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($database['body']['$id']);
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$this->assertEquals('UpdatedBetween test', $database['body']['name']);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Create Collection
|
||||
$products = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'Products',
|
||||
'rowSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $products['headers']['status-code']);
|
||||
$this->assertEquals($products['body']['name'], 'Products');
|
||||
|
||||
// Create Attributes
|
||||
$name = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/columns/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'name',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $name['headers']['status-code']);
|
||||
|
||||
$price = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/columns/float', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'price',
|
||||
'required' => true,
|
||||
]);
|
||||
$this->assertEquals(202, $price['headers']['status-code']);
|
||||
|
||||
// Wait for attributes to be available
|
||||
sleep(2);
|
||||
|
||||
// Create first product
|
||||
$row1 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Product A',
|
||||
'price' => 99.99,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row1['headers']['status-code']);
|
||||
|
||||
// Sleep to ensure different timestamps
|
||||
sleep(1);
|
||||
|
||||
// Create second product
|
||||
$row2 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Product B',
|
||||
'price' => 149.99,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row2['headers']['status-code']);
|
||||
|
||||
// Sleep again
|
||||
sleep(1);
|
||||
|
||||
// Create third product
|
||||
$row3 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Product C',
|
||||
'price' => 199.99,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row3['headers']['status-code']);
|
||||
|
||||
// Sleep again
|
||||
sleep(1);
|
||||
|
||||
// Create fourth product
|
||||
$row4 = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'name' => 'Product D',
|
||||
'price' => 249.99,
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(201, $row4['headers']['status-code']);
|
||||
|
||||
// Now update products in sequence to get different updatedAt timestamps
|
||||
sleep(1);
|
||||
|
||||
// Update first product
|
||||
$update1 = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows/' . $row1['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'price' => 89.99,
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $update1['headers']['status-code']);
|
||||
$firstProductUpdatedAt = $update1['body']['$updatedAt'];
|
||||
|
||||
sleep(1);
|
||||
|
||||
// Update second product
|
||||
$update2 = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows/' . $row2['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'price' => 139.99,
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $update2['headers']['status-code']);
|
||||
$secondProductUpdatedAt = $update2['body']['$updatedAt'];
|
||||
|
||||
sleep(1);
|
||||
|
||||
// Update third product
|
||||
$update3 = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows/' . $row3['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'price' => 189.99,
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $update3['headers']['status-code']);
|
||||
$thirdProductUpdatedAt = $update3['body']['$updatedAt'];
|
||||
|
||||
sleep(1);
|
||||
|
||||
// Update fourth product
|
||||
$update4 = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows/' . $row4['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'price' => 239.99,
|
||||
]
|
||||
]);
|
||||
$this->assertEquals(200, $update4['headers']['status-code']);
|
||||
|
||||
// Test updatedBetween query - should return products updated between first and third (inclusive)
|
||||
$rows = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::updatedBetween($firstProductUpdatedAt, $thirdProductUpdatedAt)->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertCount(3, $rows['body']['rows']);
|
||||
|
||||
// Verify the returned products are the correct ones
|
||||
$names = array_column($rows['body']['rows'], 'name');
|
||||
$this->assertContains('Product A', $names);
|
||||
$this->assertContains('Product B', $names);
|
||||
$this->assertContains('Product C', $names);
|
||||
$this->assertNotContains('Product D', $names);
|
||||
|
||||
// Test updatedBetween query - should return only the second product when using its timestamp for both bounds
|
||||
$rows = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/tablesdb/' . $databaseId . '/tables/' . $products['body']['$id'] . '/rows',
|
||||
array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()),
|
||||
[
|
||||
'queries' => [
|
||||
Query::updatedBetween($secondProductUpdatedAt, $secondProductUpdatedAt)->toString(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $rows['headers']['status-code']);
|
||||
$this->assertCount(1, $rows['body']['rows']);
|
||||
$this->assertEquals('Product B', $rows['body']['rows'][0]['name']);
|
||||
$this->assertEquals(139.99, $rows['body']['rows'][0]['price']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateDatabase
|
||||
* @param array $data
|
||||
|
||||
@@ -2775,11 +2775,13 @@ class SitesCustomServerTest extends Scope
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/cookies', [
|
||||
'cookie' => 'custom-session-id=abcd123'
|
||||
'cookie' => 'custom-session-id=abcd123; custom-user-id=efgh456'
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals("abcd123", $response['body']);
|
||||
$this->assertEquals("abcd123;efgh456", $response['body']);
|
||||
$this->assertEquals("value-one", $response['cookies']['my-cookie-one']);
|
||||
$this->assertEquals("value-two", $response['cookies']['my-cookie-two']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
export async function GET(context) {
|
||||
const sessionId = context.cookies.get("custom-session-id")?.value ?? 'Custom session ID missing';
|
||||
return new Response(sessionId);
|
||||
const userId = context.cookies.get("custom-user-id")?.value ?? 'Custom user ID missing';
|
||||
|
||||
context.cookies.set('my-cookie-one', 'value-one');
|
||||
context.cookies.set('my-cookie-two', 'value-two');
|
||||
|
||||
return new Response(sessionId + ";" + userId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user