1
0
Fork 0
mirror of synced 2024-10-03 02:37:40 +13:00

Merge remote-tracking branch 'origin/1.5.x' into feat-maintenance-delete-expired-targets

This commit is contained in:
Jake Barnby 2024-01-19 19:18:04 +13:00
commit 332fddac12
No known key found for this signature in database
GPG key ID: C437A8CC85B96E9C
5 changed files with 170 additions and 13 deletions

View file

@ -1718,7 +1718,7 @@ App::post('/v1/account/jwt')
App::post('/v1/account/targets/push')
->desc('Create Account\'s push target')
->groups(['api', 'account'])
->label('error', __DIR__ . '/../../views/general/error.phtml')
->label('scope', 'account')
->label('audits.event', 'target.create')
->label('audits.resource', 'target/response.$id')
->label('event', 'users.[userId].targets.[targetId].create')
@ -1728,10 +1728,9 @@ App::post('/v1/account/targets/push')
->label('sdk.response.code', Response::STATUS_CODE_CREATED)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TARGET)
->label('docs', false)
->param('targetId', '', new CustomId(), 'Target ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.')
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.')
->param('identifier', '', new Text(Database::LENGTH_KEY), 'The target identifier (token, email, phone etc.)')
->param('providerId', '', new UID(), 'Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.', true)
->inject('queueForEvents')
->inject('user')
->inject('request')
@ -1742,10 +1741,6 @@ App::post('/v1/account/targets/push')
$provider = Authorization::skip(fn () => $dbForProject->getDocument('providers', $providerId));
if ($provider->isEmpty()) {
throw new Exception(Exception::PROVIDER_NOT_FOUND);
}
if ($user->isEmpty()) {
throw new Exception(Exception::USER_NOT_FOUND);
}
@ -1768,8 +1763,8 @@ App::post('/v1/account/targets/push')
Permission::read(Role::user($user->getId())),
Permission::update(Role::user($user->getId())),
],
'providerId' => $providerId ?? null,
'providerInternalId' => $provider->getInternalId() ?? null,
'providerId' => !empty($providerId) ? $providerId : null,
'providerInternalId' => !empty($providerId) ? $provider->getInternalId() : null,
'providerType' => MESSAGE_TYPE_PUSH,
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
@ -3204,7 +3199,7 @@ App::put('/v1/account/verification/phone')
App::put('/v1/account/targets/:targetId/push')
->desc('Update Account\'s push target')
->groups(['api', 'account'])
->label('error', __DIR__ . '/../../views/general/error.phtml')
->label('scope', 'account')
->label('audits.event', 'target.update')
->label('audits.resource', 'target/response.$id')
->label('event', 'users.[userId].targets.[targetId].update')

View file

@ -14,6 +14,7 @@ use Appwrite\Utopia\Database\Validator\CustomId;
use Appwrite\Utopia\Database\Validator\Queries\Messages;
use Appwrite\Utopia\Database\Validator\Queries\Providers;
use Appwrite\Utopia\Database\Validator\Queries\Subscribers;
use Appwrite\Utopia\Database\Validator\Queries\Targets;
use Appwrite\Utopia\Database\Validator\Queries\Topics;
use Appwrite\Utopia\Response;
use Utopia\App;
@ -2742,6 +2743,65 @@ App::get('/v1/messaging/messages/:messageId/logs')
]), Response::MODEL_LOG_LIST);
});
App::get('/v1/messaging/messages/:messageId/targets')
->desc('List message targets')
->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', 'listTargets')
->label('sdk.description', '/docs/references/messaging/list-message-targets.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_TARGET_LIST)
->param('messageId', '', new UID(), 'Message 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(', ', Targets::ALLOWED_ATTRIBUTES), 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);
}
$targetIDs = $message->getAttribute('targets');
if (empty($targetIDs)) {
$response->dynamic(new Document([
'targets' => [],
'total' => 0,
]), Response::MODEL_TARGET_LIST);
return;
}
$queries = Query::parseQueries($queries);
$queries[] = Query::equal('$id', $targetIDs);
// 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 = $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' => $dbForProject->find('targets', $queries),
'total' => $dbForProject->count('targets', $queries, APP_LIMIT_COUNT),
]), Response::MODEL_TARGET_LIST);
});
App::get('/v1/messaging/messages/:messageId')
->desc('Get a message')
->groups(['api', 'messaging'])

View file

@ -0,0 +1 @@
List the targets associated with a message as set via the targets attribute.

View file

@ -433,14 +433,20 @@ class Messaging extends Action
$bcc = [];
if (\count($ccTargets) > 0) {
$ccTargets = $dbForProject->find('targets', [Query::equal('identifier', $ccTargets)]);
$ccTargets = $dbForProject->find('targets', [
Query::equal('$id', $ccTargets),
Query::limit(\count($ccTargets)),
]);
foreach ($ccTargets as $ccTarget) {
$cc[] = ['email' => $ccTarget['identifier']];
}
}
if (\count($bccTargets) > 0) {
$bccTargets = $dbForProject->find('targets', [Query::equal('identifier', $bccTargets)]);
$bccTargets = $dbForProject->find('targets', [
Query::equal('$id', $bccTargets),
Query::limit(\count($bccTargets)),
]);
foreach ($bccTargets as $bccTarget) {
$bcc[] = ['email' => $bccTarget['identifier']];
}

View file

@ -2,10 +2,10 @@
namespace Tests\E2E\Services\Messaging;
use Appwrite\Enum\MessageStatus;
use Tests\E2E\Client;
use Utopia\App;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Query;
use Utopia\DSN\DSN;
trait MessagingBase
@ -617,6 +617,47 @@ trait MessagingBase
$this->assertEquals(204, $response['headers']['status-code']);
}
public function testCreateDraftEmail()
{
// Create User
$response = $this->client->call(Client::METHOD_POST, '/users', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'userId' => ID::unique(),
'email' => uniqid() . "@example.com",
'password' => 'password',
'name' => 'Messaging User',
]);
$this->assertEquals(201, $response['headers']['status-code'], "Error creating user: " . var_export($response['body'], true));
$user = $response['body'];
$this->assertEquals(1, \count($user['targets']));
$targetId = $user['targets'][0]['$id'];
// Create Email
$response = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'targets' => [$targetId],
'subject' => 'New blog post',
'content' => 'Check out the new blog post at http://localhost',
]);
$this->assertEquals(201, $response['headers']['status-code']);
$message = $response['body'];
$this->assertEquals(MessageStatus::DRAFT, $message['status']);
return $message;
}
public function testSendEmail()
{
if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) {
@ -1101,4 +1142,58 @@ trait MessagingBase
$this->assertEquals(1, $message['body']['deliveredTotal']);
$this->assertEquals(0, \count($message['body']['deliveryErrors']));
}
/**
* @depends testCreateDraftEmail
*/
public function testListTargets(array $message)
{
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/does_not_exist/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(404, $response['headers']['status-code']);
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(1, $targetList['total']);
$this->assertEquals(1, count($targetList['targets']));
$this->assertEquals($message['targets'][0], $targetList['targets'][0]['$id']);
// Test for empty targets
$response = $this->client->call(Client::METHOD_POST, '/messaging/messages/email', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'subject' => 'New blog post',
'content' => 'Check out the new blog post at http://localhost',
]);
$this->assertEquals(201, $response['headers']['status-code']);
$message = $response['body'];
$response = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['$id'] . '/targets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$targetList = $response['body'];
$this->assertEquals(0, $targetList['total']);
$this->assertEquals(0, count($targetList['targets']));
}
}