From f2dd03e597f797ab8c29c63127031e8da74c0069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 27 Aug 2025 11:20:14 +0200 Subject: [PATCH] Add request to filters, to allow deployment model to respect select queries --- app/http.php | 2 +- app/realtime.php | 5 +- src/Appwrite/Platform/Workers/Functions.php | 4 +- src/Appwrite/SDK/Method.php | 5 +- src/Appwrite/Utopia/Response.php | 7 +-- src/Appwrite/Utopia/Response/Model.php | 46 ++++++++++++++++++- .../Response/Model/AttributeRelationship.php | 3 +- .../Utopia/Response/Model/ColumnIndex.php | 3 +- .../Response/Model/ColumnRelationship.php | 3 +- .../Utopia/Response/Model/Deployment.php | 8 ++++ .../Utopia/Response/Model/Document.php | 7 +-- .../Utopia/Response/Model/Execution.php | 3 +- .../Utopia/Response/Model/Migration.php | 3 +- .../Utopia/Response/Model/Project.php | 3 +- .../Utopia/Response/Model/ResourceToken.php | 3 +- src/Appwrite/Utopia/Response/Model/Row.php | 7 +-- src/Appwrite/Utopia/Response/Model/Table.php | 3 +- src/Appwrite/Utopia/Response/Model/Team.php | 3 +- src/Appwrite/Utopia/Response/Model/User.php | 3 +- .../Utopia/Response/Model/Variable.php | 3 +- tests/unit/GraphQL/BuilderTest.php | 5 +- tests/unit/Utopia/ResponseTest.php | 5 +- 22 files changed, 106 insertions(+), 28 deletions(-) diff --git a/app/http.php b/app/http.php index 30f4013821..1949afbfff 100644 --- a/app/http.php +++ b/app/http.php @@ -426,7 +426,7 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool App::setResource('swooleResponse', fn () => $swooleResponse); $request = new Request($swooleRequest); - $response = new Response($swooleResponse); + $response = new Response($swooleResponse, $request); if (Files::isFileLoaded($request->getURI())) { $time = (60 * 60 * 24 * 365 * 2); // 45 days cache diff --git a/app/realtime.php b/app/realtime.php index bb0d4da78c..12559dd186 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -504,7 +504,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $register, $stats, &$realtime, $logError) { $app = new App('UTC'); $request = new Request($request); - $response = new Response(new SwooleResponse()); + $response = new Response(new SwooleResponse(), $request); Console::info("Connection open (user: {$connection})"); @@ -625,7 +625,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) { try { - $response = new Response(new SwooleResponse()); + $request = new Request(new SwooleRequest()); + $response = new Response(new SwooleResponse(), $request); $projectId = $realtime->connections[$connection]['projectId']; $database = getConsoleDB(); diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index 864d6451b8..3ef9b8703e 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -8,9 +8,11 @@ use Appwrite\Event\Func; use Appwrite\Event\Realtime; use Appwrite\Event\StatsUsage; use Appwrite\Event\Webhook; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response\Model\Execution; use Exception; use Executor\Executor; +use Swoole\Http\Request as SwooleRequest; use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; @@ -610,7 +612,7 @@ class Functions extends Action $execution = $dbForProject->updateDocument('executions', $executionId, $execution); $executionModel = new Execution(); - $realtimeExecution = $executionModel->filter(new Document($execution->getArrayCopy())); + $realtimeExecution = $executionModel->filter(new Document($execution->getArrayCopy()), new Request(new SwooleRequest())); $realtimeExecution = $realtimeExecution->getArrayCopy(\array_keys($executionModel->getRules())); $queueForEvents diff --git a/src/Appwrite/SDK/Method.php b/src/Appwrite/SDK/Method.php index 77e3e1f1af..42c94e58ff 100644 --- a/src/Appwrite/SDK/Method.php +++ b/src/Appwrite/SDK/Method.php @@ -3,7 +3,9 @@ namespace Appwrite\SDK; use Appwrite\SDK\Response as SDKResponse; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; +use Swoole\Http\Request as HttpRequest; use Swoole\Http\Response as HttpResponse; class Method @@ -101,7 +103,8 @@ class Method protected function validateResponseModel(string|array $responseModel): void { - $response = new Response(new HttpResponse()); + $request = new Request(new HttpRequest()); + $response = new Response(new HttpResponse(), $request); if (!\is_array($responseModel)) { $responseModel = [$responseModel]; diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index cec275869a..92156654cd 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -402,9 +402,10 @@ class Response extends SwooleResponse /** * Response constructor. * - * @param float $time + * @param SwooleHTTPResponse $response Native response to be passed to parent constructor + * @param Request $request Relevant request object, useful for some response filters */ - public function __construct(SwooleHTTPResponse $response) + public function __construct(SwooleHTTPResponse $response, protected Request $request) { $this // General @@ -719,7 +720,7 @@ class Response extends SwooleResponse $model = $this->getModel($model); $output = []; - $data = $model->filter($data); + $data = $model->filter($data, $this->request); if ($model->isAny()) { $this->payload = $data->getArrayCopy(); diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 962da4834c..95f26b3ca2 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -2,7 +2,9 @@ namespace Appwrite\Utopia\Response; +use Appwrite\Utopia\Request; use Utopia\Database\Document; +use Utopia\Database\Query; abstract class Model { @@ -44,10 +46,12 @@ abstract class Model /** * Filter Document Structure + * @param Document $document Document to apply filter on + * @param Request $request Relevant request object, useful for select query filtering * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { return $document; } @@ -186,4 +190,44 @@ abstract class Model { return $this->public; } + + /** + * Apply Select Queries + * + * Helper method to respect request select queries, + * to prevent default rule values from being applied on not-selected attributes + * + * @param Document $document + * @param Request $request + * @return void + */ + public function applySelectQueries(Document $document, Request $request): void + { + $queries = $request->getParam('queries', []); + + $queries = Query::parseQueries($queries); + $selectQueries = Query::groupByType($queries)['selections'] ?? []; + + // No select queries means no filtering out + if (empty($selectQueries)) { + return; + } + + $attributes = []; + foreach ($selectQueries as $query) { + foreach ($query->getValues() as $attribute) { + $attributes[] = $attribute; + } + } + + foreach ($this->getRules() as $ruleName => $rule) { + if (\str_starts_with($ruleName, '$')) { + continue; + } + + if (!\in_array($ruleName, $attributes)) { + $this->removeRule($ruleName); + } + } + } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php index d88fbd1530..b4abb0d554 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Document; @@ -80,7 +81,7 @@ class AttributeRelationship extends Attribute * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $options = $document->getAttribute('options'); if (!\is_null($options)) { diff --git a/src/Appwrite/Utopia/Response/Model/ColumnIndex.php b/src/Appwrite/Utopia/Response/Model/ColumnIndex.php index 547312d677..b345c96c02 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnIndex.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnIndex.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -93,7 +94,7 @@ class ColumnIndex extends Model return Response::MODEL_COLUMN_INDEX; } - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $columns = $document->getAttribute('attributes', []); $document diff --git a/src/Appwrite/Utopia/Response/Model/ColumnRelationship.php b/src/Appwrite/Utopia/Response/Model/ColumnRelationship.php index 877982365b..33e7c1d4db 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnRelationship.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnRelationship.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Document; @@ -80,7 +81,7 @@ class ColumnRelationship extends Column * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $options = $document->getAttribute('options'); if (!\is_null($options)) { diff --git a/src/Appwrite/Utopia/Response/Model/Deployment.php b/src/Appwrite/Utopia/Response/Model/Deployment.php index 55c1589af0..9b26c7ec7e 100644 --- a/src/Appwrite/Utopia/Response/Model/Deployment.php +++ b/src/Appwrite/Utopia/Response/Model/Deployment.php @@ -2,8 +2,10 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use Utopia\Database\Document; class Deployment extends Model { @@ -190,6 +192,12 @@ class Deployment extends Model return 'Deployment'; } + public function filter(Document $document, Request $request): Document + { + $this->applySelectQueries($document, $request); + return $document; + } + /** * Get Type * diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php index 5bad504a63..b2a8239fbd 100644 --- a/src/Appwrite/Utopia/Response/Model/Document.php +++ b/src/Appwrite/Utopia/Response/Model/Document.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Document as DatabaseDocument; @@ -78,7 +79,7 @@ class Document extends Any ]); } - public function filter(DatabaseDocument $document): DatabaseDocument + public function filter(DatabaseDocument $document, Request $request): DatabaseDocument { $document->removeAttribute('$collection'); $document->removeAttribute('$tenant'); @@ -88,11 +89,11 @@ class Document extends Any if (\is_array($attribute)) { foreach ($attribute as $subAttribute) { if ($subAttribute instanceof DatabaseDocument) { - $this->filter($subAttribute); + $this->filter($subAttribute, $request); } } } elseif ($attribute instanceof DatabaseDocument) { - $this->filter($attribute); + $this->filter($attribute, $request); } } diff --git a/src/Appwrite/Utopia/Response/Model/Execution.php b/src/Appwrite/Utopia/Response/Model/Execution.php index 39d2203bf9..58d6f49b76 100644 --- a/src/Appwrite/Utopia/Response/Model/Execution.php +++ b/src/Appwrite/Utopia/Response/Model/Execution.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\DateTime; @@ -156,7 +157,7 @@ class Execution extends Model * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $document->removeAttribute('resourceType'); $document->setAttribute('functionId', $document->getAttribute('resourceId', '')); diff --git a/src/Appwrite/Utopia/Response/Model/Migration.php b/src/Appwrite/Utopia/Response/Model/Migration.php index 76e00b3097..85890e69cd 100644 --- a/src/Appwrite/Utopia/Response/Model/Migration.php +++ b/src/Appwrite/Utopia/Response/Model/Migration.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -109,7 +110,7 @@ class Migration extends Model return Response::MODEL_MIGRATION; } - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $errors = $document->getAttribute('errors', []); if (empty($errors)) { diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index abe67e7e86..1c1c0bce62 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -3,6 +3,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Auth\Auth; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Config\Config; @@ -340,7 +341,7 @@ class Project extends Model * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { // SMTP $smtp = $document->getAttribute('smtp', []); diff --git a/src/Appwrite/Utopia/Response/Model/ResourceToken.php b/src/Appwrite/Utopia/Response/Model/ResourceToken.php index 87ab66ab5d..1f6a30aa15 100644 --- a/src/Appwrite/Utopia/Response/Model/ResourceToken.php +++ b/src/Appwrite/Utopia/Response/Model/ResourceToken.php @@ -3,6 +3,7 @@ namespace Appwrite\Utopia\Response\Model; use Ahc\Jwt\JWT; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -59,7 +60,7 @@ class ResourceToken extends Model ; } - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $expire = $document->getAttribute('expire'); diff --git a/src/Appwrite/Utopia/Response/Model/Row.php b/src/Appwrite/Utopia/Response/Model/Row.php index 77df48ce89..b605143ec7 100644 --- a/src/Appwrite/Utopia/Response/Model/Row.php +++ b/src/Appwrite/Utopia/Response/Model/Row.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Utopia\Database\Document as DatabaseDocument; @@ -75,7 +76,7 @@ class Row extends Any ]); } - public function filter(DatabaseDocument $document): DatabaseDocument + public function filter(DatabaseDocument $document, Request $request): DatabaseDocument { $document->removeAttribute('$collection'); $document->removeAttribute('$tenant'); @@ -84,11 +85,11 @@ class Row extends Any if (\is_array($column)) { foreach ($column as $subAttribute) { if ($subAttribute instanceof DatabaseDocument) { - $this->filter($subAttribute); + $this->filter($subAttribute, $request); } } } elseif ($column instanceof DatabaseDocument) { - $this->filter($column); + $this->filter($column, $request); } } diff --git a/src/Appwrite/Utopia/Response/Model/Table.php b/src/Appwrite/Utopia/Response/Model/Table.php index 722edcd4cf..6fe6e6d42a 100644 --- a/src/Appwrite/Utopia/Response/Model/Table.php +++ b/src/Appwrite/Utopia/Response/Model/Table.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -111,7 +112,7 @@ class Table extends Model /** * Process Document before returning it to the client for backwards compatibility! */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $columns = $document->getAttribute('attributes', []); if (!empty($columns) && \is_array($columns)) { diff --git a/src/Appwrite/Utopia/Response/Model/Team.php b/src/Appwrite/Utopia/Response/Model/Team.php index d080a82bb1..845603b7bd 100644 --- a/src/Appwrite/Utopia/Response/Model/Team.php +++ b/src/Appwrite/Utopia/Response/Model/Team.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -55,7 +56,7 @@ class Team extends Model * * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $prefs = $document->getAttribute('prefs'); if ($prefs instanceof Document) { diff --git a/src/Appwrite/Utopia/Response/Model/User.php b/src/Appwrite/Utopia/Response/Model/User.php index 672b8885a0..e2a971179e 100644 --- a/src/Appwrite/Utopia/Response/Model/User.php +++ b/src/Appwrite/Utopia/Response/Model/User.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -147,7 +148,7 @@ class User extends Model * * @return string */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $prefs = $document->getAttribute('prefs'); if ($prefs instanceof Document) { diff --git a/src/Appwrite/Utopia/Response/Model/Variable.php b/src/Appwrite/Utopia/Response/Model/Variable.php index 22f76e44d4..2a8fbfad72 100644 --- a/src/Appwrite/Utopia/Response/Model/Variable.php +++ b/src/Appwrite/Utopia/Response/Model/Variable.php @@ -2,6 +2,7 @@ namespace Appwrite\Utopia\Response\Model; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use Utopia\Database\Document; @@ -69,7 +70,7 @@ class Variable extends Model * @param Document $document * @return Document */ - public function filter(Document $document): Document + public function filter(Document $document, Request $request): Document { $secret = $document->getAttribute('secret'); if ($secret === true) { diff --git a/tests/unit/GraphQL/BuilderTest.php b/tests/unit/GraphQL/BuilderTest.php index 3dd1bcadc7..54366b093f 100644 --- a/tests/unit/GraphQL/BuilderTest.php +++ b/tests/unit/GraphQL/BuilderTest.php @@ -3,8 +3,10 @@ namespace Tests\Unit\GraphQL; use Appwrite\GraphQL\Types\Mapper; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use PHPUnit\Framework\TestCase; +use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; class BuilderTest extends TestCase @@ -13,7 +15,8 @@ class BuilderTest extends TestCase public function setUp(): void { - $this->response = new Response(new SwooleResponse()); + $request = new Request(new SwooleRequest()); + $this->response = new Response(new SwooleResponse(), $request); Mapper::init($this->response->getModels()); } diff --git a/tests/unit/Utopia/ResponseTest.php b/tests/unit/Utopia/ResponseTest.php index 452119fafb..58cd485da3 100644 --- a/tests/unit/Utopia/ResponseTest.php +++ b/tests/unit/Utopia/ResponseTest.php @@ -2,9 +2,11 @@ namespace Tests\Unit\Utopia; +use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Exception; use PHPUnit\Framework\TestCase; +use Swoole\Http\Request as SwooleRequest; use Swoole\Http\Response as SwooleResponse; use Tests\Unit\Utopia\Response\Filters\First; use Tests\Unit\Utopia\Response\Filters\Second; @@ -16,7 +18,8 @@ class ResponseTest extends TestCase public function setUp(): void { - $this->response = new Response(new SwooleResponse()); + $request = new Request(new SwooleRequest()); + $this->response = new Response(new SwooleResponse(), $request); $this->response->setModel(new Single()); $this->response->setModel(new Lists()); $this->response->setModel(new Nested());