diff --git a/app/controllers/api/messaging.php b/app/controllers/api/messaging.php index 36508a0817..0f892ad98b 100644 --- a/app/controllers/api/messaging.php +++ b/app/controllers/api/messaging.php @@ -1,5 +1,6 @@ desc('List provider logs') + ->groups(['api', 'messaging']) + ->label('scope', 'providers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listProviderLogs') + ->label('sdk.description', '/docs/references/messaging/providers/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('providerId', '', new UID(), 'Provider ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $providerId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $provider = $dbForProject->getDocument('providers', $providerId); + + if ($provider->isEmpty()) { + throw new Exception(Exception::PROVIDER_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'provider/' . $providerId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/providers/:providerId') ->desc('Get provider') ->groups(['api', 'messaging']) @@ -1437,7 +1527,7 @@ App::delete('/v1/messaging/providers/:providerId') ->desc('Delete provider') ->groups(['api', 'messaging']) ->label('audits.event', 'provider.delete') - ->label('audits.resource', 'provider/{request.id}') + ->label('audits.resource', 'provider/{request.$providerId}') ->label('event', 'providers.[providerId].delete') ->label('scope', 'providers.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1560,6 +1650,90 @@ App::get('/v1/messaging/topics') ]), Response::MODEL_TOPIC_LIST); }); +App::get('/v1/messaging/topics/:topicId/logs') + ->desc('List topic logs') + ->groups(['api', 'messaging']) + ->label('scope', 'topics.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listTopicLogs') + ->label('sdk.description', '/docs/references/messaging/topics/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('topicId', '', new UID(), 'Topic ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $topicId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $topic = $dbForProject->getDocument('topics', $topicId); + + if ($topic->isEmpty()) { + throw new Exception(Exception::TOPIC_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'topic/' . $topicId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/topics/:topicId') ->desc('Get a topic.') ->groups(['api', 'messaging']) @@ -1645,7 +1819,7 @@ App::delete('/v1/messaging/topics/:topicId') ->desc('Delete a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'topic.delete') - ->label('audits.resource', 'topic/{request.topicId}') + ->label('audits.resource', 'topic/{request.$topicId}') ->label('event', 'topics.[topicId].delete') ->label('scope', 'topics.write') ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -1792,6 +1966,90 @@ App::get('/v1/messaging/topics/:topicId/subscribers') ]), Response::MODEL_SUBSCRIBER_LIST); }); +App::get('/v1/messaging/subscribers/:subscriberId/logs') + ->desc('List subscriber logs') + ->groups(['api', 'messaging']) + ->label('scope', 'subscribers.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listSubscriberLogs') + ->label('sdk.description', '/docs/references/messaging/subscribers/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('subscriberId', '', new UID(), 'Subscriber ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $subscriberId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $subscriber = $dbForProject->getDocument('subscribers', $subscriberId); + + if ($subscriber->isEmpty()) { + throw new Exception(Exception::SUBSCRIBER_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'subscriber/' . $subscriberId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Get a topic\'s subscriber.') ->groups(['api', 'messaging']) @@ -1828,7 +2086,7 @@ App::delete('/v1/messaging/topics/:topicId/subscriber/:subscriberId') ->desc('Delete a subscriber from a topic.') ->groups(['api', 'messaging']) ->label('audits.event', 'subscriber.delete') - ->label('audits.resource', 'subscriber/{request.subscriberId}') + ->label('audits.resource', 'subscriber/{request.$subscriberId}') ->label('event', 'topics.[topicId].subscribers.[subscriberId].delete') ->label('scope', 'subscribers.write') ->label('sdk.auth', [APP_AUTH_TYPE_JWT, APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) @@ -2141,6 +2399,90 @@ App::get('/v1/messaging/messages') ]), Response::MODEL_MESSAGE_LIST); }); +App::get('/v1/messaging/messages/:messageId/logs') + ->desc('List message logs') + ->groups(['api', 'messaging']) + ->label('scope', 'messages.read') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN, APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'messaging') + ->label('sdk.method', 'listMessageLogs') + ->label('sdk.description', '/docs/references/messaging/messages/get-logs.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_LOG_LIST) + ->param('messageId', '', new UID(), 'Message ID.') + ->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true) + ->inject('response') + ->inject('dbForProject') + ->inject('locale') + ->inject('geodb') + ->action(function (string $messageId, array $queries, Response $response, Database $dbForProject, Locale $locale, Reader $geodb) { + $message = $dbForProject->getDocument('messages', $messageId); + + if ($message->isEmpty()) { + throw new Exception(Exception::MESSAGE_NOT_FOUND); + } + + $queries = Query::parseQueries($queries); + $grouped = Query::groupByType($queries); + $limit = $grouped['limit'] ?? APP_LIMIT_COUNT; + $offset = $grouped['offset'] ?? 0; + + $audit = new Audit($dbForProject); + $resource = 'message/' . $messageId; + $logs = $audit->getLogsByResource($resource, $limit, $offset); + + $output = []; + + foreach ($logs as $i => &$log) { + $log['userAgent'] = (!empty($log['userAgent'])) ? $log['userAgent'] : 'UNKNOWN'; + + $detector = new Detector($log['userAgent']); + $detector->skipBotDetection(); // OPTIONAL: If called, bot detection will completely be skipped (bots will be detected as regular devices then) + + $os = $detector->getOS(); + $client = $detector->getClient(); + $device = $detector->getDevice(); + + $output[$i] = new Document([ + 'event' => $log['event'], + 'userId' => ID::custom($log['data']['userId']), + 'userEmail' => $log['data']['userEmail'] ?? null, + 'userName' => $log['data']['userName'] ?? null, + 'mode' => $log['data']['mode'] ?? null, + 'ip' => $log['ip'], + 'time' => $log['time'], + 'osCode' => $os['osCode'], + 'osName' => $os['osName'], + 'osVersion' => $os['osVersion'], + 'clientType' => $client['clientType'], + 'clientCode' => $client['clientCode'], + 'clientName' => $client['clientName'], + 'clientVersion' => $client['clientVersion'], + 'clientEngine' => $client['clientEngine'], + 'clientEngineVersion' => $client['clientEngineVersion'], + 'deviceName' => $device['deviceName'], + 'deviceBrand' => $device['deviceBrand'], + 'deviceModel' => $device['deviceModel'] + ]); + + $record = $geodb->get($log['ip']); + + if ($record) { + $output[$i]['countryCode'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), false) ? \strtolower($record['country']['iso_code']) : '--'; + $output[$i]['countryName'] = $locale->getText('countries.' . strtolower($record['country']['iso_code']), $locale->getText('locale.country.unknown')); + } else { + $output[$i]['countryCode'] = '--'; + $output[$i]['countryName'] = $locale->getText('locale.country.unknown'); + } + } + + $response->dynamic(new Document([ + 'total' => $audit->countLogsByResource($resource), + 'logs' => $output, + ]), Response::MODEL_LOG_LIST); + }); + App::get('/v1/messaging/messages/:messageId') ->desc('Get a message') ->groups(['api', 'messaging']) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 023cef3641..51c4b3330f 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -9,6 +9,7 @@ use Appwrite\Event\Event; use Appwrite\Network\Validator\Email; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Database\Validator\Queries\Identities; +use Appwrite\Utopia\Database\Validator\Queries\Targets; use Utopia\Database\Validator\Queries; use Appwrite\Utopia\Database\Validator\Queries\Users; use Utopia\Database\Validator\Query\Limit; @@ -753,20 +754,38 @@ App::get('/v1/users/:userId/targets') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_TARGET_LIST) ->param('userId', '', new UID(), 'User ID.') + ->param('queries', [], new Targets(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Users::ALLOWED_ATTRIBUTES), true) ->inject('response') ->inject('dbForProject') - ->action(function (string $userId, Response $response, Database $dbForProject) { - + ->action(function (string $userId, array $queries, Response $response, Database $dbForProject) { $user = $dbForProject->getDocument('users', $userId); if ($user->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } - $targets = $user->getAttribute('targets', []); + $queries = Query::parseQueries($queries); + + $queries[] = Query::equal('userId', [$userId]); + + // Get cursor document if there was a cursor query + $cursor = Query::getByType($queries, [Query::TYPE_CURSORAFTER, Query::TYPE_CURSORBEFORE]); + $cursor = reset($cursor); + + if ($cursor) { + $targetId = $cursor->getValue(); + $cursorDocument = Authorization::skip(fn () => $dbForProject->getDocument('targets', $targetId)); + + if ($cursorDocument->isEmpty()) { + throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Target '{$targetId}' for the 'cursor' value not found."); + } + + $cursor->setValue($cursorDocument); + } + $response->dynamic(new Document([ - 'targets' => $targets, - 'total' => \count($targets), + 'targets' => $dbForProject->find('targets', $queries), + 'total' => $dbForProject->count('targets', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_TARGET_LIST); }); diff --git a/composer.lock b/composer.lock index 66e5e5a11b..f320e31e38 100644 --- a/composer.lock +++ b/composer.lock @@ -2318,16 +2318,16 @@ }, { "name": "utopia-php/migration", - "version": "0.3.5", + "version": "0.3.6", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83" + "reference": "f78273b38bade23db5866e5c7cb5f55427ba82af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", - "reference": "b2fd3a8310296f4e44ff0e85b0eb0230ad9a2f83", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/f78273b38bade23db5866e5c7cb5f55427ba82af", + "reference": "f78273b38bade23db5866e5c7cb5f55427ba82af", "shasum": "" }, "require": { @@ -2360,9 +2360,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.3.5" + "source": "https://github.com/utopia-php/migration/tree/0.3.6" }, - "time": "2023-09-25T16:51:47+00:00" + "time": "2023-11-02T15:13:03+00:00" }, { "name": "utopia-php/mongo", diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php b/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php new file mode 100644 index 0000000000..1099604b78 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Targets.php @@ -0,0 +1,21 @@ + $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ]); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(\count($providers), \count($response['body']['providers'])); + + return $providers; } /** @@ -253,7 +256,10 @@ trait MessagingBase return $response['body']['$id']; } - public function testListTopic() + /** + * @depends testUpdateTopic + */ + public function testListTopic(string $topicId) { $response = $this->client->call(Client::METHOD_GET, '/messaging/topics', [ 'content-type' => 'application/json', @@ -262,8 +268,11 @@ trait MessagingBase ], [ 'search' => 'updated-description', ]); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, \count($response['body']['topics'])); + + return $topicId; } /** @@ -364,9 +373,122 @@ trait MessagingBase 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'], ])); + $this->assertEquals(200, $response['headers']['status-code']); $this->assertEquals(1, $response['body']['total']); $this->assertEquals(\count($response['body']['subscribers']), $response['body']['total']); + + return $data; + } + + /** + * @depends testListSubscribers + */ + public function testGetSubscriberLogs(array $data): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/subscribers/' . $data['subscriberId'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ], [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); } /** diff --git a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php index 0d533c139b..0baa465b48 100644 --- a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php +++ b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php @@ -2,13 +2,412 @@ namespace Tests\E2E\Services\Messaging; +use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectCustom; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideConsole; +use Utopia\Database\Helpers\ID; class MessagingConsoleClientTest extends Scope { use MessagingBase; use ProjectCustom; use SideConsole; + + /** + * @depends testListProviders + */ + public function testGetProviderLogs(array $providers): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $providers[0]['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $provider = $this->client->call(Client::METHOD_POST, '/messaging/providers/sendgrid/', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'providerId' => ID::unique(), + 'name' => 'Sengrid1', + 'apiKey' => 'my-apikey', + 'from' => 'sender-email@my-domain.com', + ]); + + $this->assertEquals(201, $provider['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/providers/sendgrid/' . $provider['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'sendgrid' => [ + 'name' => 'Sendgrid2', + ]]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2, $logs['body']['logs']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/providers/' . $provider['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + + /** + * @depends testListTopic + */ + public function testGetTopicLogs(string $topicId): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topicId . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $topic = $this->client->call(Client::METHOD_POST, '/messaging/topics', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'topicId' => ID::unique(), + 'name' => 'my-app', + 'description' => 'web app' + ]); + $this->assertEquals(201, $topic['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/topics/' . $topic['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'description' => 'updated-description' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertCount(2, $logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } + + /** + * @depends testSendEmail + */ + public function testGetMessageLogs(array $email): void + { + /** + * Test for SUCCESS + */ + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $email = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'messageId' => ID::unique(), + 'status' => 'draft', + 'topics' => [ID::unique()], + 'subject' => 'Khali beats Undertaker', + 'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ', + ]); + + $this->assertEquals(201, $email['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $email['body']['$id'], \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'subject' => 'Khali beats John Cena!', + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + $this->assertCount(2, $logs['body']['logs']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + + $logs = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(1)', 'offset(1)'], + ]); + + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertLessThanOrEqual(1, count($logs['body']['logs'])); + $this->assertIsNumeric($logs['body']['total']); + + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['limit(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['offset(-1)'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['equal("$id", "asdf")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['orderAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + + $response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $email['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => ['cursorAsc("$id")'] + ]); + + $this->assertEquals($response['headers']['status-code'], 400); + } }