diff --git a/app/config/collections.php b/app/config/collections.php index 7e715baa2c..f310c91211 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -1722,6 +1722,28 @@ $commonCollections = [ '$id' => ID::custom('subscribers'), 'name' => 'Subscribers', 'attributes' => [ + [ + '$id' => ID::custom('userId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('userInternalId'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('targetId'), 'type' => Database::VAR_STRING, @@ -1768,6 +1790,20 @@ $commonCollections = [ ], ], 'indexes' => [ + [ + '$id' => ID::custom('_key_userId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userId'], + 'lengths' => [], + 'orders' => [], + ], + [ + '$id' => ID::custom('_key_userInternalId'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['userInternalId'], + 'lengths' => [], + 'orders' => [], + ], [ '$id' => ID::custom('_key_targetId'), 'type' => Database::INDEX_KEY, diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index e1e531c1a1..35ba97c1af 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -36,6 +36,8 @@ use Utopia\Validator\Text; use MaxMind\Db\Reader; use Utopia\Validator\WhiteList; +use function Swoole\Coroutine\batch; + App::post('/v1/messaging/providers/mailgun') ->desc('Create Mailgun provider') ->groups(['api', 'messaging']) @@ -1644,12 +1646,16 @@ App::post('/v1/messaging/topics/:topicId/subscribers') throw new Exception(Exception::USER_TARGET_NOT_FOUND); } + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $target->getAttribute('userId'))); + $subscriber = new Document([ '$id' => $subscriberId, '$permissions' => [ - Permission::read(Role::user($target->getAttribute('userId'))), + Permission::read(Role::user($user->getId())), Permission::delete(Role::user($target->getAttribute('userId'))), ], + 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'topicId' => $topicId, 'topicInternalId' => $topic->getInternalId(), 'targetId' => $targetId, @@ -1667,6 +1673,8 @@ App::post('/v1/messaging/topics/:topicId/subscribers') ->setParam('topicId', $topic->getId()) ->setParam('subscriberId', $subscriber->getId()); + $subscriber->setAttribute('userName', $user->getAttribute('name')); + $response ->setStatusCode(Response::STATUS_CODE_CREATED) ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); @@ -1713,9 +1721,20 @@ App::get('/v1/messaging/topics/:topicId/subscribers') $cursor->setValue($cursorDocument); } + $subscribers = $dbForProject->find('subscribers', $queries); + + $subscribers = batch(\array_map(function (Document $subscriber) use ($dbForProject) { + return function () use ($subscriber, $dbForProject) { + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + + return $subscriber + ->setAttribute('userName', $user->getAttribute('name')); + }; + }, $subscribers)); + $response ->dynamic(new Document([ - 'subscribers' => $dbForProject->find('subscribers', $queries), + 'subscribers' => $subscribers, 'total' => $dbForProject->count('subscribers', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_SUBSCRIBER_LIST); }); @@ -1832,6 +1851,10 @@ App::get('/v1/messaging/topics/:topicId/subscribers/:subscriberId') throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); } + $user = Authorization::skip(fn () => $dbForProject->getDocument('users', $subscriber->getAttribute('userId'))); + + $subscriber->setAttribute('userName', $user->getAttribute('name')); + $response ->dynamic($subscriber, Response::MODEL_SUBSCRIBER); }); diff --git a/src/Appwrite/Utopia/Response/Model/Subscriber.php b/src/Appwrite/Utopia/Response/Model/Subscriber.php index 65bbd38f0e..5080b44333 100644 --- a/src/Appwrite/Utopia/Response/Model/Subscriber.php +++ b/src/Appwrite/Utopia/Response/Model/Subscriber.php @@ -34,6 +34,18 @@ class Subscriber extends Model 'default' => '', 'example' => '259125845563242502', ]) + ->addRule('userId', [ + 'type' => self::TYPE_STRING, + 'description' => 'User ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('userName', [ + 'type' => self::TYPE_STRING, + 'description' => 'User Name.', + 'default' => '', + 'example' => 'Aegon Targaryen', + ]) ->addRule('topicId', [ 'type' => self::TYPE_STRING, 'description' => 'Topic ID.', diff --git a/tests/e2e/Services/GraphQL/Base.php b/tests/e2e/Services/GraphQL/Base.php index 707905892c..8655395dc2 100644 --- a/tests/e2e/Services/GraphQL/Base.php +++ b/tests/e2e/Services/GraphQL/Base.php @@ -2044,6 +2044,7 @@ trait Base return 'mutation createSubscriber($subscriberId: String!, $targetId: String!, $topicId: String!) { messagingCreateSubscriber(subscriberId: $subscriberId, targetId: $targetId, topicId: $topicId) { _id + userId targetId topicId } @@ -2054,6 +2055,7 @@ trait Base total subscribers { _id + userId targetId topicId } @@ -2063,6 +2065,7 @@ trait Base return 'query getSubscriber($topicId: String!, $subscriberId: String!) { messagingGetSubscriber(topicId: $topicId, subscriberId: $subscriberId) { _id + userId targetId topicId } diff --git a/tests/e2e/Services/GraphQL/MessagingTest.php b/tests/e2e/Services/GraphQL/MessagingTest.php index 112e9e5633..27b2b52cd3 100644 --- a/tests/e2e/Services/GraphQL/MessagingTest.php +++ b/tests/e2e/Services/GraphQL/MessagingTest.php @@ -428,20 +428,23 @@ class MessagingTest extends Scope ], $this->getHeaders()), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['topicId'], $topicId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['targetId'], $targetId); + $this->assertEquals($response['body']['data']['messagingCreateSubscriber']['userId'], $userId); return $response['body']['data']['messagingCreateSubscriber']; } /** - * @depends testUpdateTopic + * @depends testCreateSubscriber */ - public function testListSubscribers(string $topicId) + public function testListSubscribers(array $subscriber) { $query = $this->getQuery(self::$LIST_SUBSCRIBERS); $graphQLPayload = [ 'query' => $query, 'variables' => [ - 'topicId' => $topicId, + 'topicId' => $subscriber['topicId'], ], ]; $response = $this->client->call(Client::METHOD_POST, '/graphql', \array_merge([ @@ -451,6 +454,9 @@ class MessagingTest extends Scope ]), $graphQLPayload); $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['topicId'], $subscriber['topicId']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['targetId'], $subscriber['targetId']); + $this->assertEquals($response['body']['data']['messagingListSubscribers']['subscribers'][0]['userId'], $subscriber['userId']); $this->assertEquals(1, \count($response['body']['data']['messagingListSubscribers']['subscribers'])); } @@ -479,6 +485,9 @@ class MessagingTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($subscriberId, $response['body']['data']['messagingGetSubscriber']['_id']); + $this->assertEquals($topicId, $response['body']['data']['messagingGetSubscriber']['topicId']); + $this->assertEquals($subscriber['targetId'], $response['body']['data']['messagingGetSubscriber']['targetId']); + $this->assertEquals($subscriber['userId'], $response['body']['data']['messagingGetSubscriber']['userId']); } /** diff --git a/tests/e2e/Services/Messaging/MessagingBase.php b/tests/e2e/Services/Messaging/MessagingBase.php index daafd52e8f..1f09d95522 100644 --- a/tests/e2e/Services/Messaging/MessagingBase.php +++ b/tests/e2e/Services/Messaging/MessagingBase.php @@ -321,6 +321,7 @@ trait MessagingBase 'providerId' => $provider['body']['$id'], 'identifier' => 'my-token', ]); + $this->assertEquals(201, $target['headers']['status-code']); $response = $this->client->call(Client::METHOD_POST, '/messaging/topics/' . $topic['$id'] . '/subscribers', \array_merge([ @@ -330,13 +331,16 @@ trait MessagingBase 'subscriberId' => ID::unique(), 'targetId' => $target['body']['$id'], ]); + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertEquals($target['body']['userId'], $response['body']['userId']); $topic = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['$id'], [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]); + $this->assertEquals(200, $topic['headers']['status-code']); $this->assertEquals('android-app', $topic['body']['name']); $this->assertEquals('updated-description', $topic['body']['description']); @@ -345,6 +349,7 @@ trait MessagingBase return [ 'topicId' => $topic['body']['$id'], 'targetId' => $target['body']['$id'], + 'userId' => $target['body']['userId'], 'subscriberId' => $response['body']['$id'] ]; } @@ -359,9 +364,11 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ])); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals($data['topicId'], $response['body']['topicId']); $this->assertEquals($data['targetId'], $response['body']['targetId']); + $this->assertEquals($data['userId'], $response['body']['userId']); } /** @@ -377,6 +384,7 @@ trait MessagingBase $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); + $this->assertEquals($data['userId'], $response['body']['subscribers'][0]['userId']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); return $data;