diff --git a/app/config/errors.php b/app/config/errors.php index 7932dcd3a9..f880ed9a02 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -872,7 +872,7 @@ return [ ], Exception::MESSAGE_MISSING_TARGET => [ 'name' => Exception::MESSAGE_MISSING_TARGET, - 'description' => 'Message with the requested ID is missing a target (Topics or Users or Targets).', + 'description' => 'Message with the requested ID has no recipients (topics or users or targets).', 'code' => 400, ], Exception::MESSAGE_ALREADY_SENT => [ @@ -920,4 +920,11 @@ return [ 'description' => 'Schedule with the requested ID could not be found.', 'code' => 404, ], + + /** Targets */ + Exception::TARGET_PROVIDER_INVALID_TYPE => [ + 'name' => Exception::PROVIDER_INVALID_TYPE, + 'description' => 'Target has an invalid provider type.', + 'code' => 400, + ], ]; diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 0e865a7184..501c724127 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -2260,7 +2260,19 @@ App::post('/v1/messaging/topics/:topicId/subscribers') try { $subscriber = $dbForProject->createDocument('subscribers', $subscriber); - Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute('topics', $topicId, 'total', 1)); + + $totalAttribute = match ($target->getAttribute('providerType')) { + MESSAGE_TYPE_EMAIL => 'emailTotal', + MESSAGE_TYPE_SMS => 'smsTotal', + MESSAGE_TYPE_PUSH => 'pushTotal', + default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), + }; + + Authorization::skip(fn () => $dbForProject->increaseDocumentAttribute( + 'topics', + $topicId, + $totalAttribute, + )); } catch (DuplicateException) { throw new Exception(Exception::SUBSCRIBER_ALREADY_EXISTS); } @@ -2512,8 +2524,23 @@ App::delete('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } + $target = $dbForProject->getDocument('targets', $subscriber->getAttribute('targetId')); + $dbForProject->deleteDocument('subscribers', $subscriberId); - Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', 1)); + + $totalAttribute = match ($target->getAttribute('providerType')) { + MESSAGE_TYPE_EMAIL => 'emailTotal', + MESSAGE_TYPE_SMS => 'smsTotal', + MESSAGE_TYPE_PUSH => 'pushTotal', + default => throw new Exception(Exception::TARGET_PROVIDER_INVALID_TYPE), + }; + + Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute( + 'topics', + $topicId, + $totalAttribute, + min: 0 + )); $queueForEvents ->setParam('topicId', $topic->getId()) diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 98dee95c94..348fdacc0b 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -252,6 +252,7 @@ class Exception extends \Exception public const PROVIDER_NOT_FOUND = 'provider_not_found'; public const PROVIDER_ALREADY_EXISTS = 'provider_already_exists'; public const PROVIDER_INCORRECT_TYPE = 'provider_incorrect_type'; + public const PROVIDER_MISSING_CREDENTIALS = 'provider_missing_credentials'; /** Topic */ @@ -274,6 +275,9 @@ class Exception extends \Exception public const MESSAGE_TARGET_NOT_PUSH = 'message_target_not_push'; public const MESSAGE_MISSING_SCHEDULE = 'message_missing_schedule'; + /** Targets */ + public const TARGET_PROVIDER_INVALID_TYPE = 'target_provider_invalid_type'; + /** Schedules */ public const SCHEDULE_NOT_FOUND = 'schedule_not_found'; diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 7a7070b9e4..ad804d6d05 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -3,6 +3,7 @@ namespace Appwrite\Platform\Workers; use Appwrite\Auth\Auth; +use Appwrite\Extend\Exception; use Executor\Executor; use Throwable; use Utopia\Abuse\Abuse; @@ -263,12 +264,23 @@ class Deletes extends Action Query::equal('targetInternalId', [$target->getInternalId()]) ], $dbForProject, - function (Document $subscriber) use ($dbForProject) { + function (Document $subscriber) use ($dbForProject, $target) { $topicId = $subscriber->getAttribute('topicId'); $topicInternalId = $subscriber->getAttribute('topicInternalId'); $topic = $dbForProject->getDocument('topics', $topicId); if (!$topic->isEmpty() && $topic->getInternalId() === $topicInternalId) { - $dbForProject->decreaseDocumentAttribute('topics', $topicId, 'total', min: 0); + $totalAttribute = match ($target->getAttribute('providerType')) { + MESSAGE_TYPE_EMAIL => 'emailTotal', + MESSAGE_TYPE_SMS => 'smsTotal', + MESSAGE_TYPE_PUSH => 'pushTotal', + default => throw new Exception('Invalid target provider type'), + }; + $dbForProject->decreaseDocumentAttribute( + 'topics', + $topicId, + $totalAttribute, + min: 0 + ); } } ); diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 99730d475f..083eae4e0a 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -249,7 +249,7 @@ class Messaging extends Action } // Deleting push targets when token has expired. - if (($result['error'] ?? '') === 'Expired device token.') { + if (($result['error'] ?? '') === 'Expired device token') { $target = $dbForProject->findOne('targets', [ Query::equal('identifier', [$result['recipient']]) ]);