From a0400d2e93e64f68c7ec205aab97ba1007d83cbc Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 6 May 2026 13:44:58 +1200 Subject: [PATCH] feat(notifications): scaffold GET /v1/account/alerts/:alertId/track endpoint Adds a public-scope tracking-pixel endpoint skeleton that always returns a 1x1 transparent PNG. The body is intentionally minimal so the email-tracking read-flag flip can be wired up cleanly in Wave 3 (ST14) once the JWT decode and DB write paths are designed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Modules/Account/Http/Alerts/Track/Get.php | 68 +++++++++++++++++++ .../Modules/Account/Services/Http.php | 4 +- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/Appwrite/Platform/Modules/Account/Http/Alerts/Track/Get.php diff --git a/src/Appwrite/Platform/Modules/Account/Http/Alerts/Track/Get.php b/src/Appwrite/Platform/Modules/Account/Http/Alerts/Track/Get.php new file mode 100644 index 0000000000..7e9a9d9e44 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Account/Http/Alerts/Track/Get.php @@ -0,0 +1,68 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_GET) + ->setHttpPath('/v1/account/alerts/:alertId/track') + ->desc('Track alert') + ->groups(['api', 'account']) + ->label('scope', 'public') + ->label('sdk', new Method( + namespace: 'account', + name: 'getAlertTrack', + description: '/docs/references/account/get-alert-track.md', + auth: [AuthType::SESSION, AuthType::JWT], + responses: [ + new SDKResponse( + code: Response::STATUS_CODE_OK, + model: Response::MODEL_NONE, + ), + ], + contentType: ContentType::IMAGE_PNG, + )) + ->param('alertId', '', new UID(), 'Alert ID.') + ->param('jwt', '', new Text(2048, 0), 'Tracking token.', true) + ->inject('response') + ->inject('dbForPlatform') + ->callback($this->action(...)); + } + + public function action( + string $alertId, + string $jwt, + Response $response, + Database $dbForPlatform, + ): void { + // 1x1 transparent PNG. Wave 3 (ST14) will replace this body with + // JWT decode + read-flag flip; the skeleton always returns the pixel. + $pixel = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=='); + + $response + ->setContentType('image/png') + ->addHeader('Cache-Control', 'no-store') + ->send($pixel); + } +} diff --git a/src/Appwrite/Platform/Modules/Account/Services/Http.php b/src/Appwrite/Platform/Modules/Account/Services/Http.php index ae2e841636..baaed61f4e 100644 --- a/src/Appwrite/Platform/Modules/Account/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Account/Services/Http.php @@ -12,6 +12,7 @@ use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Create as C use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Get as GetRecoveryCodes; use Appwrite\Platform\Modules\Account\Http\Account\MFA\RecoveryCodes\Update as UpdateRecoveryCodes; use Appwrite\Platform\Modules\Account\Http\Account\MFA\Update as UpdateMfa; +use Appwrite\Platform\Modules\Account\Http\Alerts\Track\Get as TrackAlert; use Utopia\Platform\Service; class Http extends Service @@ -29,6 +30,7 @@ class Http extends Service ->addAction(UpdateRecoveryCodes::getName(), new UpdateRecoveryCodes()) ->addAction(GetRecoveryCodes::getName(), new GetRecoveryCodes()) ->addAction(CreateChallenge::getName(), new CreateChallenge()) - ->addAction(UpdateChallenge::getName(), new UpdateChallenge()); + ->addAction(UpdateChallenge::getName(), new UpdateChallenge()) + ->addAction(TrackAlert::getName(), new TrackAlert()); } }