From 5dd987711b55425fe33f8d1d85dcf2cc67f14ec9 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 6 May 2026 14:46:22 +1200 Subject: [PATCH] feat(notifications): implement GET /v1/account/alerts list endpoint body Replace the placeholder body of the listAlerts action with real implementation: scope alerts to the current user via userId equality, parse incoming queries, support cursor pagination over the alerts collection, run filters through count for total, and return MODEL_ALERT_LIST. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Modules/Account/Http/Alerts/XList.php | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Account/Http/Alerts/XList.php b/src/Appwrite/Platform/Modules/Account/Http/Alerts/XList.php index 18b3243071..c91ec1232d 100644 --- a/src/Appwrite/Platform/Modules/Account/Http/Alerts/XList.php +++ b/src/Appwrite/Platform/Modules/Account/Http/Alerts/XList.php @@ -2,6 +2,7 @@ namespace Appwrite\Platform\Modules\Account\Http\Alerts; +use Appwrite\Extend\Exception; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; @@ -9,6 +10,10 @@ use Appwrite\Utopia\Database\Validator\Queries\Alerts; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Exception\Order as OrderException; +use Utopia\Database\Exception\Query as QueryException; +use Utopia\Database\Query; +use Utopia\Database\Validator\Query\Cursor; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -58,9 +63,51 @@ class XList extends Action Database $dbForPlatform, Document $user ): void { + try { + $queries = Query::parseQueries($queries); + } catch (QueryException $e) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage()); + } + + $queries[] = Query::equal('userId', [$user->getId()]); + + /** + * Get cursor document if there was a cursor query, we use array_filter and reset for reference $cursor to $queries + */ + $cursor = \array_filter($queries, function ($query) { + return \in_array($query->getMethod(), [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE]); + }); + $cursor = reset($cursor); + if ($cursor) { + /** @var Query $cursor */ + + $validator = new Cursor(); + if (!$validator->isValid($cursor)) { + throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription()); + } + + $alertId = $cursor->getValue(); + $cursorDocument = $dbForPlatform->getDocument('alerts', $alertId); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Alert '{$alertId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + + $filterQueries = Query::groupByType($queries)['filters']; + + try { + $results = $dbForPlatform->find('alerts', $queries); + $total = $dbForPlatform->count('alerts', $filterQueries, APP_LIMIT_COUNT); + } catch (OrderException $e) { + throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null."); + } + $response->dynamic(new Document([ - 'alerts' => [], - 'total' => 0, + 'alerts' => $results, + 'total' => $total, ]), Response::MODEL_ALERT_LIST); } }