Merge pull request #7227 from appwrite/frontend-review-changes

misc changes
This commit is contained in:
Jake Barnby 2023-12-05 12:45:12 +01:00 committed by GitHub
commit 7e8122749b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 195 additions and 17 deletions

View file

@ -1755,6 +1755,28 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
[
'$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('topicId'),
'type' => Database::VAR_STRING,
@ -1777,6 +1799,17 @@ $commonCollections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('providerType'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 128,
'signed' => true,
'required' => true,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
@ -1793,6 +1826,20 @@ $commonCollections = [
'lengths' => [],
'orders' => [],
],
[
'$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_topicId'),
'type' => Database::INDEX_KEY,

View file

@ -847,5 +847,20 @@ return [
'description' => 'Message with the requested ID has already been scheduled for delivery.',
'code' => 400,
],
Exception::MESSAGE_TARGET_NOT_EMAIL => [
'name' => Exception::MESSAGE_TARGET_NOT_EMAIL,
'description' => 'Message with the target ID is not an email target:',
'code' => 400,
],
Exception::MESSAGE_TARGET_NOT_SMS => [
'name' => Exception::MESSAGE_TARGET_NOT_SMS,
'description' => 'Message with the target ID is not an SMS target:',
'code' => 400,
],
Exception::MESSAGE_TARGET_NOT_PUSH => [
'name' => Exception::MESSAGE_TARGET_NOT_PUSH,
'description' => 'Message with the target ID is not a push target:',
'code' => 400,
],
];

View file

@ -483,7 +483,7 @@ App::post('/v1/messaging/providers/twilio')
'type' => MESSAGE_TYPE_SMS,
'enabled' => $enabled,
'credentials' => $credentials,
'options' => $from,
'options' => $options,
]);
try {
@ -1289,8 +1289,8 @@ App::patch('/v1/messaging/providers/twilio/:providerId')
->param('providerId', '', new UID(), 'Provider ID.')
->param('name', '', new Text(128), 'Provider name.', true)
->param('enabled', null, new Boolean(), 'Set as enabled.', true)
->param('accountSid', null, new Text(0), 'Twilio account secret ID.', true)
->param('authToken', null, new Text(0), 'Twilio authentication token.', true)
->param('accountSid', '', new Text(0), 'Twilio account secret ID.', true)
->param('authToken', '', new Text(0), 'Twilio authentication token.', true)
->param('from', '', new Text(256), 'Sender number.', true)
->inject('queueForEvents')
->inject('dbForProject')
@ -1952,6 +1952,9 @@ App::post('/v1/messaging/topics/:topicId/subscribers')
'topicInternalId' => $topic->getInternalId(),
'targetId' => $targetId,
'targetInternalId' => $target->getInternalId(),
'userId' => $user->getId(),
'userInternalId' => $user->getInternalId(),
'providerType' => $target->getAttribute('providerType'),
]);
try {
@ -1987,11 +1990,16 @@ App::get('/v1/messaging/topics/:topicId/subscribers')
->label('sdk.response.model', Response::MODEL_SUBSCRIBER_LIST)
->param('topicId', '', new UID(), 'Topic ID. The topic ID subscribed to.')
->param('queries', [], new Subscribers(), '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(', ', Providers::ALLOWED_ATTRIBUTES), true)
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
->inject('dbForProject')
->inject('response')
->action(function (string $topicId, array $queries, Database $dbForProject, Response $response) {
->action(function (string $topicId, array $queries, string $search, Database $dbForProject, Response $response) {
$queries = Query::parseQueries($queries);
if (!empty($search)) {
$queries[] = Query::search('search', $search);
}
$topic = Authorization::skip(fn () => $dbForProject->getDocument('topics', $topicId));
if ($topic->isEmpty()) {
@ -2223,7 +2231,7 @@ App::post('/v1/messaging/messages/email')
->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true)
->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true)
->param('description', '', new Text(256), 'Description for message.', true)
->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('html', false, new Boolean(), 'Is content of type HTML', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
@ -2238,6 +2246,18 @@ App::post('/v1/messaging/messages/email')
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId());
}
}
$message = $dbForProject->createDocument('messages', new Document([
'$id' => $messageId,
'providerType' => MESSAGE_TYPE_EMAIL,
@ -2288,7 +2308,7 @@ App::post('/v1/messaging/messages/sms')
->param('users', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of User IDs.', true)
->param('targets', [], new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true)
->param('description', '', new Text(256), 'Description for Message.', true)
->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
->inject('dbForProject')
@ -2302,6 +2322,18 @@ App::post('/v1/messaging/messages/sms')
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId());
}
}
$message = $dbForProject->createDocument('messages', new Document([
'$id' => $messageId,
'providerType' => MESSAGE_TYPE_SMS,
@ -2358,7 +2390,7 @@ App::post('/v1/messaging/messages/push')
->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true)
->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true)
->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true)
->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('status', 'processing', new WhiteList(['draft', 'canceled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
->inject('dbForProject')
@ -2372,6 +2404,18 @@ App::post('/v1/messaging/messages/push')
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId());
}
}
$pushData = [];
$keys = ['title', 'body', 'data', 'action', 'icon', 'sound', 'color', 'tag', 'badge'];
@ -2581,7 +2625,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
->param('subject', '', new Text(998), 'Email Subject.', true)
->param('description', '', new Text(256), 'Description for Message.', true)
->param('content', '', new Text(64230), 'Email Content.', true)
->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('html', false, new Boolean(), 'Is content of type HTML', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
@ -2613,6 +2657,18 @@ App::patch('/v1/messaging/messages/email/:messageId')
}
if (!\is_null($targets)) {
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_EMAIL) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_EMAIL . ' ' . $targetDocument->getId());
}
}
$message->setAttribute('targets', $targets);
}
@ -2680,7 +2736,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->param('targets', null, new ArrayList(new Text(Database::LENGTH_KEY), 1), 'List of Targets IDs.', true)
->param('description', '', new Text(256), 'Description for Message.', true)
->param('content', '', new Text(64230), 'Email Content.', true)
->param('status', '', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
->inject('dbForProject')
@ -2711,6 +2767,18 @@ App::patch('/v1/messaging/messages/sms/:messageId')
}
if (!\is_null($targets)) {
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_SMS) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_SMS . ' ' . $targetDocument->getId());
}
}
$message->setAttribute('targets', $targets);
}
@ -2777,7 +2845,8 @@ App::patch('/v1/messaging/messages/push/:messageId')
->param('sound', '', new Text(256), 'Sound for push notification. Available only for Android and IOS Platform.', true)
->param('color', '', new Text(256), 'Color for push notification. Available only for Android Platform.', true)
->param('tag', '', new Text(256), 'Tag for push notification. Available only for Android Platform.', true)
->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true) ->param('status', 'processing', new WhiteList(['draft', 'processing']), 'Message Status. Value must be either draft or processing.', true)
->param('badge', '', new Text(256), 'Badge for push notification. Available only for IOS Platform.', true)
->param('status', '', new WhiteList(['draft', 'cancelled', 'processing']), 'Message Status. Value must be either draft or cancelled or processing.', true)
->param('scheduledAt', null, new DatetimeValidator(requireDateInFuture: true), 'Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.', true)
->inject('queueForEvents')
->inject('dbForProject')
@ -2808,6 +2877,18 @@ App::patch('/v1/messaging/messages/push/:messageId')
}
if (!\is_null($targets)) {
foreach ($targets as $target) {
$targetDocument = $dbForProject->getDocument('targets', $target);
if ($targetDocument->isEmpty()) {
throw new Exception(Exception::USER_TARGET_NOT_FOUND);
}
if ($targetDocument->getAttribute('providerType') !== MESSAGE_TYPE_PUSH) {
throw new Exception(Exception::MESSAGE_TARGET_NOT_PUSH . ' ' . $targetDocument->getId());
}
}
$message->setAttribute('targets', $targets);
}

View file

@ -1397,6 +1397,10 @@ App::patch('/v1/users/:userId/targets/:targetId')
throw new Exception(Exception::PROVIDER_NOT_FOUND);
}
if ($provider->getAttribute('type') !== $target->getAttribute('providerType')) {
throw new Exception(Exception::PROVIDER_INCORRECT_TYPE);
}
$target->setAttribute('providerId', $provider->getId());
$target->setAttribute('providerInternalId', $provider->getInternalId());
}

View file

@ -521,14 +521,20 @@ services:
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_SMS_PROVIDER
- _APP_SMS_FROM
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_LOGGING_PROVIDER
- _APP_LOGGING_CONFIG
- _APP_SMS_FROM
- _APP_SMS_PROVIDER
appwrite-worker-migrations:
image: <?php echo $organization; ?>/<?php echo $image; ?>:<?php echo $version."\n"; ?>

View file

@ -256,6 +256,10 @@ class Exception extends \Exception
public const MESSAGE_MISSING_TARGET = 'message_missing_target';
public const MESSAGE_ALREADY_SENT = 'message_already_sent';
public const MESSAGE_ALREADY_SCHEDULED = 'message_already_scheduled';
public const MESSAGE_TARGET_NOT_EMAIL = 'message_target_not_email';
public const MESSAGE_TARGET_NOT_SMS = 'message_target_not_sms';
public const MESSAGE_TARGET_NOT_PUSH = 'message_target_not_push';
protected string $type = '';
protected array $errors = [];

View file

@ -556,6 +556,11 @@ class Deletes extends Action
$this->deleteByGroup('identities', [
Query::equal('userInternalId', [$userInternalId])
], $dbForProject);
// Delete targets
$this->deleteByGroup('targets', [
Query::equal('userInternalId', [$userInternalId])
], $dbForProject);
}
/**

View file

@ -91,14 +91,16 @@ class Messaging extends Action
if (\count($topicsId) > 0) {
$topics = $dbForProject->find('topics', [Query::equal('$id', $topicsId)]);
foreach ($topics as $topic) {
$recipients = \array_merge($recipients, $topic->getAttribute('targets'));
$targets = \array_filter($topic->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType'));
$recipients = \array_merge($recipients, $targets);
}
}
if (\count($usersId) > 0) {
$users = $dbForProject->find('users', [Query::equal('$id', $usersId)]);
foreach ($users as $user) {
$recipients = \array_merge($recipients, $user->getAttribute('targets'));
$targets = \array_filter($user->getAttribute('targets'), fn (Document $target) => $target->getAttribute('providerType') === $message->getAttribute('providerType'));
$recipients = \array_merge($recipients, $targets);
}
}

View file

@ -6,7 +6,9 @@ class Subscribers extends Base
{
public const ALLOWED_ATTRIBUTES = [
'targetId',
'topicId'
'topicId',
'userId',
'providerType'
];
/**

View file

@ -98,7 +98,7 @@ class Message extends Model
'type' => self::TYPE_STRING,
'description' => 'Status of delivery.',
'default' => 'processing',
'example' => 'Message status can be one of the following: processing, sent, failed.',
'example' => 'Message status can be one of the following: processing, sent, cancelled, failed.',
])
->addRule('description', [
'type' => self::TYPE_STRING,

View file

@ -49,6 +49,12 @@ class Subscriber extends Model
'userId' => '5e5ea5c16897e',
],
])
->addRule('userId', [
'type' => self::TYPE_STRING,
'description' => 'Topic ID.',
'default' => '',
'example' => '5e5ea5c16897e',
])
->addRule('userName', [
'type' => self::TYPE_STRING,
'description' => 'User Name.',
@ -60,6 +66,12 @@ class Subscriber extends Model
'description' => 'Topic ID.',
'default' => '',
'example' => '259125845563242502',
])
->addRule('providerType', [
'type' => self::TYPE_STRING,
'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.',
'default' => '',
'example' => MESSAGE_TYPE_EMAIL,
]);
}

View file

@ -51,7 +51,7 @@ class Target extends Model
'type' => self::TYPE_STRING,
'description' => 'The target provider type. Can be one of the following: `email`, `sms` or `push`.',
'default' => '',
'example' => 'email',
'example' => MESSAGE_TYPE_EMAIL,
])
->addRule('identifier', [
'type' => self::TYPE_STRING,