1
0
Fork 0
mirror of synced 2024-06-03 03:14:50 +12:00

Merge pull request #7668 from appwrite/fix-rescheduling

Rescheduling fixes
This commit is contained in:
Jake Barnby 2024-02-27 01:18:03 +13:00 committed by GitHub
commit c34bdfb6cd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 490 additions and 131 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2597,7 +2597,7 @@ App::post('/v1/messaging/messages/email')
->param('cc', [], new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
->param('bcc', [], new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
->param('attachments', [], new ArrayList(new CompoundUID()), 'Array of compound bucket IDs to file IDs to be attached to the email.', true)
->param('status', MessageStatus::DRAFT, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', false, new Boolean(), 'Is message a draft', 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')
@ -2606,11 +2606,19 @@ App::post('/v1/messaging/messages/email')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, array $attachments, string $status, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, string $subject, string $content, array $topics, array $users, array $targets, array $cc, array $bcc, array $attachments, bool $draft, bool $html, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()'
? ID::unique()
: $messageId;
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
if ($status !== MessageStatus::DRAFT && \count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
@ -2737,7 +2745,7 @@ App::post('/v1/messaging/messages/sms')
->param('topics', [], new ArrayList(new UID()), 'List of Topic IDs.', true)
->param('users', [], new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', [], new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('status', MessageStatus::DRAFT, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', false, new Boolean(), 'Is message a draft', 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')
@ -2745,11 +2753,19 @@ App::post('/v1/messaging/messages/sms')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, string $content, array $topics, array $users, array $targets, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, string $content, array $topics, array $users, array $targets, bool $draft, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()'
? ID::unique()
: $messageId;
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
if ($status !== MessageStatus::DRAFT && \count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
@ -2854,7 +2870,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', MessageStatus::DRAFT, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', false, new Boolean(), 'Is message a draft', 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')
@ -2862,11 +2878,19 @@ App::post('/v1/messaging/messages/push')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, string $badge, string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, string $title, string $body, array $topics, array $users, array $targets, ?array $data, string $action, string $image, string $icon, string $sound, string $color, string $tag, string $badge, bool $draft, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$messageId = $messageId == 'unique()'
? ID::unique()
: $messageId;
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
if ($status !== MessageStatus::DRAFT && \count($topics) === 0 && \count($users) === 0 && \count($targets) === 0) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
@ -3233,7 +3257,7 @@ App::patch('/v1/messaging/messages/email/:messageId')
->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('subject', null, new Text(998), 'Email Subject.', true)
->param('content', null, new Text(64230), 'Email Content.', true)
->param('status', null, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', null, new Boolean(), 'Is message a draft', true)
->param('html', null, new Boolean(), 'Is content of type HTML', true)
->param('cc', null, new ArrayList(new UID()), 'Array of target IDs to be added as CC.', true)
->param('bcc', null, new ArrayList(new UID()), 'Array of target IDs to be added as BCC.', true)
@ -3244,13 +3268,36 @@ App::patch('/v1/messaging/messages/email/:messageId')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $subject, ?string $content, ?string $status, ?bool $html, ?array $cc, ?array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $subject, ?string $content, ?bool $draft, ?bool $html, ?array $cc, ?array $bcc, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) {
throw new Exception(Exception::MESSAGE_NOT_FOUND);
}
if (!\is_null($draft) || !\is_null($scheduledAt)) {
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
} else {
$status = null;
}
if (
$status !== MessageStatus::DRAFT
&& \count($topics ?? $message->getAttribute('topics', [])) === 0
&& \count($users ?? $message->getAttribute('users', [])) === 0
&& \count($targets ?? $message->getAttribute('targets', [])) === 0
) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
$currentScheduledAt = $message->getAttribute('scheduledAt');
switch ($message->getAttribute('status')) {
case MessageStatus::PROCESSING:
throw new Exception(Exception::MESSAGE_ALREADY_PROCESSING);
@ -3260,10 +3307,56 @@ App::patch('/v1/messaging/messages/email/:messageId')
throw new Exception(Exception::MESSAGE_ALREADY_FAILED);
}
if (!\is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) {
if (
$status === MessageStatus::SCHEDULED
&& \is_null($scheduledAt)
&& \is_null($currentScheduledAt)
) {
throw new Exception(Exception::MESSAGE_MISSING_SCHEDULE);
}
if (!\is_null($currentScheduledAt) && new \DateTime($currentScheduledAt) < new \DateTime()) {
throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED);
}
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
}
if (!\is_null($currentScheduledAt)) {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
$scheduledStatus = ($status ?? $message->getAttribute('status')) === MessageStatus::SCHEDULED;
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('active', $scheduledStatus);
if (!\is_null($scheduledAt)) {
$schedule->setAttribute('schedule', $scheduledAt);
}
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
if (!\is_null($scheduledAt)) {
$message->setAttribute('scheduledAt', $scheduledAt);
}
if (!\is_null($topics)) {
$message->setAttribute('topics', $topics);
}
@ -3304,38 +3397,6 @@ App::patch('/v1/messaging/messages/email/:messageId')
$message->setAttribute('status', $status);
}
if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
} else {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('schedule', $scheduledAt)
->setAttribute('active', $status === MessageStatus::SCHEDULED);
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
$message->setAttribute('scheduleId', $schedule->getId());
}
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
if ($status === MessageStatus::PROCESSING) {
@ -3370,7 +3431,7 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->param('users', null, new ArrayList(new UID()), 'List of User IDs.', true)
->param('targets', null, new ArrayList(new UID()), 'List of Targets IDs.', true)
->param('content', null, new Text(64230), 'Email Content.', true)
->param('status', null, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', null, new Boolean(), 'Is message a draft', 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')
@ -3378,13 +3439,36 @@ App::patch('/v1/messaging/messages/sms/:messageId')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $content, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $content, ?bool $draft, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) {
throw new Exception(Exception::MESSAGE_NOT_FOUND);
}
if (!\is_null($draft) || !\is_null($scheduledAt)) {
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
} else {
$status = null;
}
if (
$status !== MessageStatus::DRAFT
&& \count($topics ?? $message->getAttribute('topics', [])) === 0
&& \count($users ?? $message->getAttribute('users', [])) === 0
&& \count($targets ?? $message->getAttribute('targets', [])) === 0
) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
$currentScheduledAt = $message->getAttribute('scheduledAt');
switch ($message->getAttribute('status')) {
case MessageStatus::PROCESSING:
throw new Exception(Exception::MESSAGE_ALREADY_PROCESSING);
@ -3394,10 +3478,56 @@ App::patch('/v1/messaging/messages/sms/:messageId')
throw new Exception(Exception::MESSAGE_ALREADY_FAILED);
}
if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) {
if (
$status === MessageStatus::SCHEDULED
&& \is_null($scheduledAt)
&& \is_null($currentScheduledAt)
) {
throw new Exception(Exception::MESSAGE_MISSING_SCHEDULE);
}
if (!\is_null($currentScheduledAt) && new \DateTime($currentScheduledAt) < new \DateTime()) {
throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED);
}
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
}
if (!\is_null($currentScheduledAt)) {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
$scheduledStatus = ($status ?? $message->getAttribute('status')) === MessageStatus::SCHEDULED;
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('active', $scheduledStatus);
if (!\is_null($scheduledAt)) {
$schedule->setAttribute('schedule', $scheduledAt);
}
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
if (!\is_null($scheduledAt)) {
$message->setAttribute('scheduledAt', $scheduledAt);
}
if (!\is_null($topics)) {
$message->setAttribute('topics', $topics);
}
@ -3422,38 +3552,6 @@ App::patch('/v1/messaging/messages/sms/:messageId')
$message->setAttribute('status', $status);
}
if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
} else {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('schedule', $scheduledAt)
->setAttribute('active', $status === MessageStatus::SCHEDULED);
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
$message->setAttribute('scheduleId', $schedule->getId());
}
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
if ($status === MessageStatus::PROCESSING) {
@ -3497,7 +3595,7 @@ App::patch('/v1/messaging/messages/push/:messageId')
->param('color', null, new Text(256), 'Color for push notification. Available only for Android platforms.', true)
->param('tag', null, new Text(256), 'Tag for push notification. Available only for Android platforms.', true)
->param('badge', null, new Integer(), 'Badge for push notification. Available only for iOS platforms.', true)
->param('status', null, new WhiteList([MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]), 'Message Status. Value must be one of: ' . implode(', ', [MessageStatus::DRAFT, MessageStatus::SCHEDULED, MessageStatus::PROCESSING]) . '.', true)
->param('draft', null, new Boolean(), 'Is message a draft', 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')
@ -3505,13 +3603,36 @@ App::patch('/v1/messaging/messages/push/:messageId')
->inject('project')
->inject('queueForMessaging')
->inject('response')
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?string $status, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
->action(function (string $messageId, ?array $topics, ?array $users, ?array $targets, ?string $title, ?string $body, ?array $data, ?string $action, ?string $image, ?string $icon, ?string $sound, ?string $color, ?string $tag, ?int $badge, ?bool $draft, ?string $scheduledAt, Event $queueForEvents, Database $dbForProject, Database $dbForConsole, Document $project, Messaging $queueForMessaging, Response $response) {
$message = $dbForProject->getDocument('messages', $messageId);
if ($message->isEmpty()) {
throw new Exception(Exception::MESSAGE_NOT_FOUND);
}
if (!\is_null($draft) || !\is_null($scheduledAt)) {
if ($draft) {
$status = MessageStatus::DRAFT;
} else {
$status = \is_null($scheduledAt)
? MessageStatus::PROCESSING
: MessageStatus::SCHEDULED;
}
} else {
$status = null;
}
if (
$status !== MessageStatus::DRAFT
&& \count($topics ?? $message->getAttribute('topics', [])) === 0
&& \count($users ?? $message->getAttribute('users', [])) === 0
&& \count($targets ?? $message->getAttribute('targets', [])) === 0
) {
throw new Exception(Exception::MESSAGE_MISSING_TARGET);
}
$currentScheduledAt = $message->getAttribute('scheduledAt');
switch ($message->getAttribute('status')) {
case MessageStatus::PROCESSING:
throw new Exception(Exception::MESSAGE_ALREADY_PROCESSING);
@ -3521,10 +3642,56 @@ App::patch('/v1/messaging/messages/push/:messageId')
throw new Exception(Exception::MESSAGE_ALREADY_FAILED);
}
if (!is_null($message->getAttribute('scheduledAt')) && $message->getAttribute('scheduledAt') < new \DateTime()) {
if (
$status === MessageStatus::SCHEDULED
&& \is_null($scheduledAt)
&& \is_null($currentScheduledAt)
) {
throw new Exception(Exception::MESSAGE_MISSING_SCHEDULE);
}
if (!\is_null($currentScheduledAt) && new \DateTime($currentScheduledAt) < new \DateTime()) {
throw new Exception(Exception::MESSAGE_ALREADY_SCHEDULED);
}
if (\is_null($currentScheduledAt) && !\is_null($scheduledAt)) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
}
if (!\is_null($currentScheduledAt)) {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
$scheduledStatus = ($status ?? $message->getAttribute('status')) === MessageStatus::SCHEDULED;
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('active', $scheduledStatus);
if (!\is_null($scheduledAt)) {
$schedule->setAttribute('schedule', $scheduledAt);
}
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
if (!\is_null($scheduledAt)) {
$message->setAttribute('scheduledAt', $scheduledAt);
}
if (!\is_null($topics)) {
$message->setAttribute('topics', $topics);
}
@ -3613,38 +3780,6 @@ App::patch('/v1/messaging/messages/push/:messageId')
$message->setAttribute('status', $status);
}
if (!\is_null($scheduledAt)) {
if (\is_null($message->getAttribute(('scheduleId')))) {
$schedule = $dbForConsole->createDocument('schedules', new Document([
'region' => App::getEnv('_APP_REGION', 'default'),
'resourceType' => 'message',
'resourceId' => $message->getId(),
'resourceInternalId' => $message->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => $status === MessageStatus::SCHEDULED,
]));
$message->setAttribute('scheduleId', $schedule->getId());
} else {
$schedule = $dbForConsole->getDocument('schedules', $message->getAttribute('scheduleId'));
if ($schedule->isEmpty()) {
throw new Exception(Exception::SCHEDULE_NOT_FOUND);
}
$schedule
->setAttribute('resourceUpdatedAt', DateTime::now())
->setAttribute('schedule', $scheduledAt)
->setAttribute('active', $status === MessageStatus::SCHEDULED);
$dbForConsole->updateDocument('schedules', $schedule->getId(), $schedule);
}
$message->setAttribute('scheduleId', $schedule->getId());
}
$message = $dbForProject->updateDocument('messages', $message->getId(), $message);
if ($status === MessageStatus::PROCESSING) {

View file

@ -17,8 +17,8 @@ use function Swoole\Coroutine\run;
class ScheduleMessages extends ScheduleBase
{
public const UPDATE_TIMER = 10; // seconds
public const ENQUEUE_TIMER = 60; // seconds
public const UPDATE_TIMER = 3; // seconds
public const ENQUEUE_TIMER = 4; // seconds
public static function getName(): string
{
@ -37,14 +37,14 @@ class ScheduleMessages extends ScheduleBase
continue;
}
$now = DateTime::now();
$scheduledAt = DateTime::formatTz($schedule['schedule']);
$now = new \DateTime();
$scheduledAt = new \DateTime($schedule['schedule']);
if ($scheduledAt > $now) {
continue;
}
\go(function () use ($schedule, $pools, $dbForConsole) {
\go(function () use ($now, $schedule, $pools, $dbForConsole) {
$queue = $pools->get('queue')->pop();
$connection = $queue->getResource();
$queueForMessaging = new Messaging($connection);

View file

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

View file

@ -5,6 +5,7 @@ namespace Tests\E2E\Services\Messaging;
use Appwrite\Messaging\Status as MessageStatus;
use Tests\E2E\Client;
use Utopia\App;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Role;
@ -799,6 +800,7 @@ trait MessagingBase
'messageId' => ID::unique(),
'subject' => 'New blog post',
'content' => 'Check out the new blog post at http://localhost',
'draft' => true
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -867,6 +869,7 @@ trait MessagingBase
'targets' => [$targetId1, $targetId2],
'subject' => 'New blog post',
'content' => 'Check out the new blog post at http://localhost',
'draft' => true
]);
$this->assertEquals(201, $response['headers']['status-code']);
@ -876,6 +879,228 @@ trait MessagingBase
return $message;
}
public function testScheduledMessage(): void
{
// 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 1',
]);
$targetId = $response['body']['targets'][0]['$id'];
// Create scheduled message
$message = $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',
'scheduledAt' => DateTime::addSeconds(new \DateTime(), 3),
]);
$this->assertEquals(201, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::SCHEDULED, $message['body']['status']);
\sleep(8);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::FAILED, $message['body']['status']);
}
public function testScheduledToDraftMessage(): void
{
// 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 1',
]);
$targetId = $response['body']['targets'][0]['$id'];
// Create scheduled message
$message = $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',
'scheduledAt' => DateTime::addSeconds(new \DateTime(), 5),
]);
$this->assertEquals(201, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::SCHEDULED, $message['body']['status']);
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'draft' => true,
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::DRAFT, $message['body']['status']);
\sleep(8);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::DRAFT, $message['body']['status']);
}
public function testDraftToScheduledMessage(): void
{
// 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 1',
]);
$targetId = $response['body']['targets'][0]['$id'];
// Create draft message
$message = $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',
'draft' => true,
]);
$this->assertEquals(201, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::DRAFT, $message['body']['status']);
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'draft' => false,
'scheduledAt' => DateTime::addSeconds(new \DateTime(), 3),
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::SCHEDULED, $message['body']['status']);
\sleep(8);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::FAILED, $message['body']['status']);
}
public function testUpdateScheduledAt(): void
{
// 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 1',
]);
$targetId = $response['body']['targets'][0]['$id'];
// Create scheduled message
$message = $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',
'scheduledAt' => DateTime::addSeconds(new \DateTime(), 3),
]);
$this->assertEquals(201, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::SCHEDULED, $message['body']['status']);
$scheduledAt = DateTime::addSeconds(new \DateTime(), 10);
$message = $this->client->call(Client::METHOD_PATCH, '/messaging/messages/email/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'scheduledAt' => $scheduledAt,
]);
$this->assertEquals(200, $message['headers']['status-code']);
\sleep(8);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::SCHEDULED, $message['body']['status']);
\sleep(8);
$message = $this->client->call(Client::METHOD_GET, '/messaging/messages/' . $message['body']['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $message['headers']['status-code']);
$this->assertEquals(MessageStatus::FAILED, $message['body']['status']);
}
public function testSendEmail()
{
if (empty(App::getEnv('_APP_MESSAGE_EMAIL_TEST_DSN'))) {
@ -1004,7 +1229,7 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'status' => 'draft',
'draft' => true,
'topics' => [$email['body']['topics'][0]],
'subject' => 'Khali beats Undertaker',
'content' => 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
@ -1017,7 +1242,7 @@ trait MessagingBase
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'status' => 'processing',
'draft' => false,
]);
$this->assertEquals(200, $email['headers']['status-code']);
@ -1169,7 +1394,7 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'status' => 'draft',
'draft' => true,
'topics' => [$sms['body']['topics'][0]],
'content' => 'Your OTP code is 123456',
]);
@ -1181,7 +1406,7 @@ trait MessagingBase
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'status' => 'processing',
'draft' => false,
]);
$this->assertEquals(200, $sms['headers']['status-code']);
@ -1330,7 +1555,7 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'status' => 'draft',
'draft' => true,
'topics' => [$push['body']['topics'][0]],
'title' => 'Test-Notification',
'body' => 'Test-Notification-Body',
@ -1343,7 +1568,7 @@ trait MessagingBase
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'status' => 'processing',
'draft' => false,
]);
$this->assertEquals(200, $push['headers']['status-code']);
@ -1387,7 +1612,6 @@ trait MessagingBase
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'messageId' => ID::unique(),
'status' => 'processing',
'topics' => [$topic['$id']],
'subject' => 'Test subject',
'content' => 'Test content',