diff --git a/components/ILIAS/Mail/classes/Folder/MailFolderData.php b/components/ILIAS/Mail/classes/Folder/MailFolderData.php
index 5d6526f04ea5..b74aa2da0858 100644
--- a/components/ILIAS/Mail/classes/Folder/MailFolderData.php
+++ b/components/ILIAS/Mail/classes/Folder/MailFolderData.php
@@ -60,6 +60,11 @@ public function isDrafts(): bool
return $this->type === MailFolderType::DRAFTS;
}
+ public function isOutbox(): bool
+ {
+ return $this->type === MailFolderType::OUTBOX;
+ }
+
public function isSent(): bool
{
return $this->type === MailFolderType::SENT;
diff --git a/components/ILIAS/Mail/classes/Folder/MailFolderTableUI.php b/components/ILIAS/Mail/classes/Folder/MailFolderTableUI.php
index 885a7c75bae6..88c1bfe9088d 100644
--- a/components/ILIAS/Mail/classes/Folder/MailFolderTableUI.php
+++ b/components/ILIAS/Mail/classes/Folder/MailFolderTableUI.php
@@ -241,7 +241,7 @@ private function getActions(): array
}
}
- if ($this->current_folder->isDrafts()) {
+ if ($this->current_folder->isDrafts() || $this->current_folder->isOutbox()) {
unset($actions[self::ACTION_SHOW], $actions[self::ACTION_REPLY], $actions[self::ACTION_FORWARD]);
} else {
unset($actions[self::ACTION_EDIT]);
@@ -421,7 +421,7 @@ private function getSubject(MailRecordData $record): Link
(string) $this->url_builder
->withParameter(
$this->action_token,
- $this->current_folder->isDrafts() ? self::ACTION_EDIT : self::ACTION_SHOW
+ $this->current_folder->isDrafts() || $this->current_folder->isOutbox() ? self::ACTION_EDIT : self::ACTION_SHOW
)
->withParameter($this->row_id_token, (string) $record->getMailId())
->buildURI()
diff --git a/components/ILIAS/Mail/classes/Folder/MailFolderType.php b/components/ILIAS/Mail/classes/Folder/MailFolderType.php
index dfbbcae20ca4..f6d2650f586e 100644
--- a/components/ILIAS/Mail/classes/Folder/MailFolderType.php
+++ b/components/ILIAS/Mail/classes/Folder/MailFolderType.php
@@ -29,4 +29,5 @@ enum MailFolderType: string
case SENT = 'sent';
case LOCAL = 'local';
case USER = 'user_folder';
+ case OUTBOX = 'outbox';
}
diff --git a/components/ILIAS/Mail/classes/class.ilMail.php b/components/ILIAS/Mail/classes/class.ilMail.php
index d3b8e550ffac..3e50f33b7625 100755
--- a/components/ILIAS/Mail/classes/class.ilMail.php
+++ b/components/ILIAS/Mail/classes/class.ilMail.php
@@ -461,16 +461,18 @@ public function updateDraft(
string $a_m_subject,
string $a_m_message,
int $a_draft_id = 0,
+ ?ilDateTime $a_send_time = null,
bool $a_use_placeholders = false,
?string $a_tpl_context_id = null,
array $a_tpl_context_params = []
): int {
+ $a_send_time?->switchTimeZone('UTC');
$this->db->update(
$this->table_mail,
[
'folder_id' => ['integer', $a_folder_id],
'attachments' => ['clob', serialize($a_attachments)],
- 'send_time' => ['timestamp', date('Y-m-d H:i:s')],
+ 'send_time' => ['timestamp', $a_send_time ? $a_send_time->get(IL_CAL_DATETIME) : date('Y-m-d H:i:s')],
'rcp_to' => ['clob', $a_rcp_to],
'rcp_cc' => ['clob', $a_rcp_cc],
'rcp_bcc' => ['clob', $a_rcp_bcc],
@@ -489,6 +491,55 @@ public function updateDraft(
return $a_draft_id;
}
+ public function sendTerminatedMail(
+ int $outbox_id,
+ int $folder_id,
+ int $sender_usr_id,
+ array $attachments,
+ string $to,
+ string $cc,
+ string $bcc,
+ string $subject,
+ string $message,
+ ?ilDateTime $a_send_time = null,
+ bool $use_placeholders = false,
+ ?string $template_context_id = null,
+ array $template_context_parameters = []
+ ): int {
+ if ($use_placeholders) {
+ $message = $this->replacePlaceholders($message, $sender_usr_id);
+ }
+ $a_send_time?->switchTimeZone('UTC');
+ $message = str_ireplace(['
', '
', '
'], "\n", $message);
+ $mail_values = [
+ 'user_id' => ['integer', $sender_usr_id],
+ 'folder_id' => ['integer', $folder_id],
+ 'sender_id' => ['integer', $sender_usr_id],
+ 'attachments' => ['clob', serialize($attachments)],
+ 'send_time' => ['timestamp', $a_send_time ? $a_send_time->get(IL_CAL_DATETIME) : date('Y-m-d H:i:s')],
+ 'rcp_to' => ['clob', $to],
+ 'rcp_cc' => ['clob', $cc],
+ 'rcp_bcc' => ['clob', $bcc],
+ 'm_status' => ['text', 'read'],
+ 'm_subject' => ['text', $subject],
+ 'm_message' => ['clob', $message],
+ 'tpl_ctx_id' => ['text', $template_context_id],
+ 'tpl_ctx_params' => ['blob', json_encode($template_context_parameters, JSON_THROW_ON_ERROR)],
+ ];
+
+ if (!$outbox_id) {
+ $outbox_id = $this->db->nextId($this->table_mail);
+ $mail_values['mail_id'] = ['integer', $outbox_id];
+ $this->db->insert($this->table_mail, $mail_values);
+ } else {
+ $this->db->update($this->table_mail, $mail_values, [
+ 'mail_id' => ['integer', $outbox_id],
+ ]);
+ }
+
+ return $outbox_id;
+ }
+
private function sendInternalMail(
int $folder_id,
int $sender_usr_id,
diff --git a/components/ILIAS/Mail/classes/class.ilMailCronTerminatedMails.php b/components/ILIAS/Mail/classes/class.ilMailCronTerminatedMails.php
new file mode 100644
index 000000000000..be02101260fe
--- /dev/null
+++ b/components/ILIAS/Mail/classes/class.ilMailCronTerminatedMails.php
@@ -0,0 +1,177 @@
+init_done) {
+ $this->settings = $DIC->settings();
+ $this->lng = $DIC->language();
+ $this->db = $DIC->database();
+ $this->user = $DIC->user();
+ $this->http = $DIC->http();
+ $this->cron_manager = $DIC->cron()->manager();
+ $this->mail = new ilMail($this->user->getId());
+ $this->umail = new ilFormatMail($this->user->getId());
+
+ $this->lng->loadLanguageModule('mail');
+ $this->init_done = true;
+ }
+ }
+
+ public function getId(): string
+ {
+ return 'mail_terminated_mails';
+ }
+
+ public function getTitle(): string
+ {
+ $this->init();
+
+ return $this->lng->txt('mail_cron_terminated_mails');
+ }
+
+ public function getDescription(): string
+ {
+ $this->init();
+
+ return $this->lng->txt('mail_cron_terminated_mails_desc');
+ }
+
+ public function hasAutoActivation(): bool
+ {
+ return true;
+ }
+
+ public function hasFlexibleSchedule(): bool
+ {
+ return true;
+ }
+
+ public function getDefaultScheduleType(): JobScheduleType
+ {
+ return JobScheduleType::DAILY;
+ }
+
+ public function getDefaultScheduleValue(): ?int
+ {
+ return 1;
+ }
+
+ public function run(): JobResult
+ {
+ $this->init();
+
+ $job_result = new JobResult();
+ $job_result->setStatus(JobResult::STATUS_OK);
+
+ ilLoggerFactory::getLogger('mail')->info('Start sending terminated mails from all users.');
+
+ $mails = $this->getOutboxMails();
+ $sent_mail_ids = [];
+ foreach ($mails as $mail) {
+ try {
+ $mailer = $this->umail
+ ->withContextId(ilContext::CONTEXT_CRON);
+
+ $mailer->setSaveInSentbox(true);
+
+ $mailer->autoresponder()->enableAutoresponder();
+ $errors = $mailer->enqueue(
+ $mail['rcp_to'],
+ $mail['rcp_cc'],
+ $mail['rcp_bcc'],
+ $mail['m_subject'],
+ $mail['m_message'],
+ unserialize($mail['attachments'], ['allowed_classes' => false]),
+ (bool) ($mail['use_placeholders'] ?? false)
+ );
+
+ if (empty($errors)) {
+ $sent_mail_ids[] = (int) ($mail['mail_id'] ?? 0);
+ }
+ } catch (\Exception $e) {
+ $job_result->setStatus(JobResult::STATUS_FAIL);
+ ilLoggerFactory::getLogger('mail')->error(
+ 'Error sending terminated mail with id ' . ($mail['mail_id'] ?? 'unknown') . ': ' . $e->getMessage()
+ );
+ $job_result->setMessage($e->getMessage());
+ return $job_result;
+ }
+ }
+ $this->mail->deleteMails($sent_mail_ids);
+ ilLoggerFactory::getLogger('mail')->info(
+ 'Sent ' . count($sent_mail_ids) . ' terminated mails and removed them from outbox.'
+ );
+ $job_result->setMessage('Processed ' . count($sent_mail_ids) . ' mails.');
+ return $job_result;
+ }
+
+ public function getOutboxMails(): Generator
+ {
+ $res = $this->db->queryF(
+ <<<'SQL'
+ SELECT * FROM mail
+ JOIN mail_obj_data ON mail.folder_id = mail_obj_data.obj_id
+ WHERE mail_obj_data.m_type = %s
+ AND send_time IS NOT NULL
+ AND send_time <= %s
+ SQL,
+ ['text', 'timestamp'],
+ ['outbox', (new DateTimeImmutable('NOW', new DateTimeZone('UTC')))->format('Y-m-d H:i:s')]
+ );
+
+ while ($row = $this->db->fetchAssoc($res)) {
+ yield $row;
+ }
+ }
+}
diff --git a/components/ILIAS/Mail/classes/class.ilMailFolderGUI.php b/components/ILIAS/Mail/classes/class.ilMailFolderGUI.php
index 88273eca5ad3..f3e2a256e76a 100755
--- a/components/ILIAS/Mail/classes/class.ilMailFolderGUI.php
+++ b/components/ILIAS/Mail/classes/class.ilMailFolderGUI.php
@@ -239,7 +239,15 @@ protected function executeTableAction(): void
(string) $this->folder->getFolderId()
);
$this->ctrl->setParameterByClass(ilMailFormGUI::class, self::PARAM_MAIL_ID, (string) $mail_ids[0]);
- $this->ctrl->setParameterByClass(ilMailFormGUI::class, 'type', ilMailFormGUI::MAIL_FORM_TYPE_DRAFT);
+ if ($this->folder->isOutbox()) {
+ $this->ctrl->setParameterByClass(
+ ilMailFormGUI::class,
+ 'type',
+ ilMailFormGUI::MAIL_FORM_TYPE_OUTBOX
+ );
+ } else {
+ $this->ctrl->setParameterByClass(ilMailFormGUI::class, 'type', ilMailFormGUI::MAIL_FORM_TYPE_DRAFT);
+ }
$this->ctrl->redirectByClass(ilMailFormGUI::class);
// no break
diff --git a/components/ILIAS/Mail/classes/class.ilMailFormAttachmentPropertyGUI.php b/components/ILIAS/Mail/classes/class.ilMailFormAttachmentPropertyGUI.php
index fc3c85f49096..3fa4d46b23ab 100755
--- a/components/ILIAS/Mail/classes/class.ilMailFormAttachmentPropertyGUI.php
+++ b/components/ILIAS/Mail/classes/class.ilMailFormAttachmentPropertyGUI.php
@@ -49,4 +49,13 @@ public function insert(ilTemplate $a_tpl): void
$a_tpl->setVariable('PROP_GENERIC', $tpl->get());
$a_tpl->parseCurrentBlock();
}
+
+ public function checkInput(): bool
+ {
+ return true;
+ }
+
+ public function setValueByArray(): void
+ {
+ }
}
diff --git a/components/ILIAS/Mail/classes/class.ilMailFormGUI.php b/components/ILIAS/Mail/classes/class.ilMailFormGUI.php
index 8840fcfc1229..23babca97142 100755
--- a/components/ILIAS/Mail/classes/class.ilMailFormGUI.php
+++ b/components/ILIAS/Mail/classes/class.ilMailFormGUI.php
@@ -38,6 +38,7 @@ class ilMailFormGUI
final public const string MAIL_FORM_TYPE_ADDRESS = 'address';
final public const string MAIL_FORM_TYPE_FORWARD = 'forward';
final public const string MAIL_FORM_TYPE_DRAFT = 'draft';
+ final public const string MAIL_FORM_TYPE_OUTBOX = 'outbox';
private readonly ilGlobalTemplateInterface $tpl;
private readonly ilCtrlInterface $ctrl;
@@ -175,20 +176,126 @@ protected function decodeAttachmentFiles(array $files): array
return $decoded_files;
}
- public function sendMessage(): void
+ public function saveMessageToOutbox(): void
{
- $message = $this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '');
+ $termination = new DateTimeImmutable(
+ $this->getBodyParam('m_termination', $this->refinery->kindlyTo()->string(), null),
+ new DateTimeZone($this->user->getTimezone())
+ );
+ $termination = new ilDateTime($termination->getTimestamp(), IL_CAL_UNIX, $this->user->getTimezone());
+
+ $files = $this->decodeAttachmentFiles($this->getBodyParam(
+ 'attachments',
+ $this->refinery->kindlyTo()->listOf(
+ $this->refinery->custom()->transformation($this->refinery->kindlyTo()->string())
+ ),
+ []
+ ));
- $mail_body = new ilMailBody($message, $this->purifier);
+ $rcp_to = ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
+ $rcp_cc = ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
+ $rcp_bcc = ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
+
+ $message = ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), ''));
+ $mail_body = new ilMailBody($message, $this->purifier);
$sanitized_message = $mail_body->getContent();
+ $outbox_folder_id = $this->mbox->getOutboxFolder();
+ if (ilSession::get('outbox')) {
+ $outbox_id = (int) ilSession::get('outbox');
+ ilSession::clear('outbox');
+ }
+
+ $this->umail->sendTerminatedMail(
+ $outbox_id ?? 0,
+ $outbox_folder_id,
+ $this->user->getId(),
+ $files,
+ $rcp_to,
+ $rcp_cc,
+ $rcp_bcc,
+ ilUtil::securePlainString(
+ $this->getBodyParam('m_subject', $this->refinery->kindlyTo()->string(), '')
+ ) ?: 'No Subject',
+ $sanitized_message,
+ $termination,
+ $this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
+ ilMailFormCall::getContextId(),
+ ilMailFormCall::getContextParameters()
+ );
+
+ if (ilSession::get('draft')) {
+ $draft_id = (int) ilSession::get('draft');
+ ilSession::clear('draft');
+ $this->umail->deleteMails([$draft_id]);
+ }
+
+ $this->ctrl->setParameterByClass(ilMailFolderGUI::class, 'mobj_id', $outbox_folder_id);
+ $this->tpl->setOnScreenMessage('info', $this->lng->txt('mail_saved'), true);
+
+ if (ilMailFormCall::isRefererStored()) {
+ ilUtil::redirect(ilMailFormCall::getRefererRedirectUrl());
+ } else {
+ $this->ctrl->redirectByClass([ilMailGUI::class, ilMailFolderGUI::class]);
+ }
+
+ $this->showForm();
+ }
+
+ public function sendMessage(): void
+ {
$attachments = $this->getBodyParam(
'attachments',
$this->refinery->kindlyTo()->listOf($this->refinery->kindlyTo()->string()),
[]
);
$files = $this->decodeAttachmentFiles($attachments);
+ $mail_data = $this->http->request()->getParsedBody();
+ $mail_data['attachments'] = $files;
+ $form = $this->getShowForm($mail_data);
+ ;
+ $errors = $this->umail->validateRecipients(
+ ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), '')),
+ ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')),
+ ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''))
+ );
+ $form_valid = $form->checkInput();
+ if ($errors || !$form_valid) {
+ if ($errors) {
+ $this->showSubmissionErrors($errors);
+ }
+ $this->tpl->addJavaScript('assets/js/ilMailComposeFunctions.js');
+ $this->tpl->setContent($form->getHTML());
+ $this->tpl->printToStdout();
+ $this->http->close();
+ }
+
+ $termination = new DateTimeImmutable(
+ $this->getBodyParam('m_termination', $this->refinery->kindlyTo()->string(), null),
+ new DateTimeZone($this->user->getTimezone())
+ );
+ if (
+ $termination->getTimestamp() > time() &&
+ $this->getBodyParam('use_termination', $this->refinery->kindlyTo()->bool(), false)
+ ) {
+ $this->saveMessageToOutbox();
+ }
+
+ $mail_id = 0;
+ if (ilSession::get('outbox')) {
+ $mail_id = (int) ilSession::get('outbox');
+ ilSession::clear('outbox');
+ } elseif (ilSession::get('draft')) {
+ $mail_id = (int) ilSession::get('draft');
+ ilSession::clear('draft');
+ }
+
+ $message = $this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '');
+
+ $mail_body = new ilMailBody($message, $this->purifier);
+
+ $sanitized_message = $mail_body->getContent();
$mailer = $this->umail
->withContextId(ilMailFormCall::getContextId() ?: '')
@@ -211,6 +318,9 @@ public function sendMessage(): void
$this->showSubmissionErrors($errors);
} else {
$mailer->autoresponder()->disableAutoresponder();
+ if ($mail_id) {
+ $mailer->deleteMails([$mail_id]);
+ }
$mailer->persistToStage(
$this->user->getId(),
@@ -238,7 +348,15 @@ public function sendMessage(): void
public function saveDraft(): void
{
- $draft_folder_id = $this->mbox->getDraftsFolder();
+ $rcp_to = ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
+ $rcp_cc = ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
+ $rcp_bcc = ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
+
+ $errors = $this->umail->validateRecipients(
+ $rcp_to,
+ $rcp_cc,
+ $rcp_bcc,
+ );
$files = $this->decodeAttachmentFiles($this->getBodyParam(
'attachments',
@@ -248,19 +366,26 @@ public function saveDraft(): void
[]
));
- $rcp_to = ilUtil::securePlainString($this->getBodyParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
- $rcp_cc = ilUtil::securePlainString($this->getBodyParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
- $rcp_bcc = ilUtil::securePlainString($this->getBodyParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
+ $mail_data = $this->http->request()->getParsedBody();
+ $mail_data['attachments'] = $files;
+ $form = $this->getShowForm($mail_data);
+ $form_valid = $form->checkInput();
+ if ($errors || !$form_valid) {
+ if ($errors) {
+ $this->showSubmissionErrors($errors);
+ }
+ $this->tpl->addJavaScript('assets/js/ilMailComposeFunctions.js');
+ $this->tpl->setContent($form->getHTML());
+ $this->tpl->printToStdout();
+ $this->http->close();
+ }
- if ($errors = $this->umail->validateRecipients(
- $rcp_to,
- $rcp_cc,
- $rcp_bcc,
- )) {
- $this->request_attachments = $files;
- $this->showSubmissionErrors($errors);
- $this->showForm();
- return;
+ $draft_folder_id = $this->mbox->getDraftsFolder();
+
+ if (ilSession::get('outbox')) {
+ $outbox_id = (int) ilSession::get('outbox');
+ ilSession::clear('outbox');
+ $this->umail->deleteMails([$outbox_id]);
}
if (ilSession::get('draft')) {
@@ -270,6 +395,12 @@ public function saveDraft(): void
$draft_id = $this->umail->getNewDraftId($draft_folder_id);
}
+ $termination = new DateTimeImmutable(
+ $this->getBodyParam('m_termination', $this->refinery->kindlyTo()->string(), null),
+ new DateTimeZone($this->user->getTimezone())
+ );
+ $termination = new ilDateTime($termination->getTimestamp(), IL_CAL_UNIX, $this->user->getTimezone());
+
$this->umail->updateDraft(
$draft_folder_id,
$files,
@@ -281,11 +412,13 @@ public function saveDraft(): void
) ?: 'No Subject',
ilUtil::securePlainString($this->getBodyParam('m_message', $this->refinery->kindlyTo()->string(), '')),
$draft_id,
+ $termination,
$this->getBodyParam('use_placeholders', $this->refinery->kindlyTo()->bool(), false),
ilMailFormCall::getContextId(),
ilMailFormCall::getContextParameters()
);
+ $this->ctrl->setParameterByClass(ilMailFolderGUI::class, 'mobj_id', $draft_folder_id);
$this->tpl->setOnScreenMessage('info', $this->lng->txt('mail_saved'), true);
if (ilMailFormCall::isRefererStored()) {
@@ -584,12 +717,21 @@ public function showForm(): void
ilMailFormCall::setContextParameters($mail_data['tpl_ctx_params']);
break;
+ case self::MAIL_FORM_TYPE_OUTBOX:
+ ilSession::set('outbox', $mail_id);
+ $mail_data = $this->umail->getMail($mail_id);
+ ilMailFormCall::setContextId($mail_data['tpl_ctx_id']);
+ ilMailFormCall::setContextParameters($mail_data['tpl_ctx_params']);
+ break;
+
case self::MAIL_FORM_TYPE_FORWARD:
$mail_data = $this->umail->getMail($mail_id);
$mail_data['rcp_to'] = $mail_data['rcp_cc'] = $mail_data['rcp_bcc'] = '';
$mail_data['m_subject'] = $this->umail->formatForwardSubject($mail_data['m_subject'] ?? '');
$mail_data['m_message'] = $this->umail->prependSignature($mail_data['m_message'] ?? '');
- if (is_array($mail_data['attachments']) && count($mail_data['attachments']) && $error = $this->mfile->adoptAttachments(
+ if (is_array($mail_data['attachments']) && count(
+ $mail_data['attachments']
+ ) && $error = $this->mfile->adoptAttachments(
$mail_data['attachments'],
$mail_id
)) {
@@ -599,19 +741,25 @@ public function showForm(): void
case self::MAIL_FORM_TYPE_NEW:
// Note: For security reasons, ILIAS only allows Plain text strings in E-Mails.
- $to = ilUtil::securePlainString($this->getQueryParam('rcp_to', $this->refinery->kindlyTo()->string(), ''));
+ $to = ilUtil::securePlainString(
+ $this->getQueryParam('rcp_to', $this->refinery->kindlyTo()->string(), '')
+ );
if ($to === '' && ilSession::get('rcp_to')) {
$to = ilSession::get('rcp_to');
}
$mail_data['rcp_to'] = $to;
- $cc = ilUtil::securePlainString($this->getQueryParam('rcp_cc', $this->refinery->kindlyTo()->string(), ''));
+ $cc = ilUtil::securePlainString(
+ $this->getQueryParam('rcp_cc', $this->refinery->kindlyTo()->string(), '')
+ );
if ($cc === '' && ilSession::get('rcp_cc')) {
$cc = ilSession::get('rcp_cc');
}
$mail_data['rcp_cc'] = $cc;
- $bcc = ilUtil::securePlainString($this->getQueryParam('rcp_bcc', $this->refinery->kindlyTo()->string(), ''));
+ $bcc = ilUtil::securePlainString(
+ $this->getQueryParam('rcp_bcc', $this->refinery->kindlyTo()->string(), '')
+ );
if ($bcc === '' && ilSession::get('rcp_bcc')) {
$bcc = ilSession::get('rcp_bcc');
}
@@ -661,10 +809,12 @@ public function showForm(): void
$additional_msg_text = '';
if ($this->http->wrapper()->post()->has('additional_message_text')) {
- $additional_msg_text = ilUtil::securePlainString($this->http->wrapper()->post()->retrieve(
- 'additional_message_text',
- $this->refinery->kindlyTo()->string()
- ));
+ $additional_msg_text = ilUtil::securePlainString(
+ $this->http->wrapper()->post()->retrieve(
+ 'additional_message_text',
+ $this->refinery->kindlyTo()->string()
+ )
+ );
}
$mail_data['m_message'] .= $additional_msg_text
@@ -691,151 +841,80 @@ public function showForm(): void
}
}
- if ($this->request_attachments) {
- $mail_data['attachments'] = $this->request_attachments;
- }
break;
}
+ $this->tpl->parseCurrentBlock();
+
+ $this->tpl->setVariable('FORM', $this->getShowForm($mail_data)->getHTML());
+
+ $this->tpl->addJavaScript('assets/js/ilMailComposeFunctions.js');
+ $this->tpl->printToStdout();
+ }
+
+ public function getShowForm(array $mail_data = []): ilPropertyFormGUI
+ {
$form_gui = new ilPropertyFormGUI();
$form_gui->setTitle($this->lng->txt('compose'));
$form_gui->setId('mail_compose_form');
$form_gui->setName('mail_compose_form');
$form_gui->setFormAction($this->ctrl->getFormAction($this, 'sendMessage'));
- $this->tpl->setVariable('FORM_ID', $form_gui->getId());
-
- $mail_form = 'form_' . $form_gui->getName();
-
- $btn = $this->ui_factory->button()
- ->standard($this->lng->txt('search_recipients'), '#')
- ->withOnLoadCode(static fn($id): string => "
- document.getElementById('$id').addEventListener('click', function() {
- const frm = document.getElementById('$mail_form'),
- action = new URL(frm.action),
- action_params = new URLSearchParams(action.search);
-
- action_params.delete('cmd');
- action_params.append('cmd', 'searchUsers');
-
- action.search = action_params.toString();
-
- frm.action = action.href;
- frm.submit();
- return false;
- });
- ");
- $this->toolbar->addStickyItem($btn);
-
- $btn = $this->ui_factory->button()
- ->standard($this->lng->txt('mail_my_courses'), '#')
- ->withOnLoadCode(static fn($id): string => "
- document.getElementById('$id').addEventListener('click', function() {
- const frm = document.getElementById('$mail_form'),
- action = new URL(frm.action),
- action_params = new URLSearchParams(action.search);
-
- action_params.delete('cmd');
- action_params.append('cmd', 'searchCoursesTo');
-
- action.search = action_params.toString();
-
- frm.action = action.href;
- frm.submit();
- return false;
- });
- ");
- $this->toolbar->addComponent($btn);
-
- $btn = $this->ui_factory->button()
- ->standard($this->lng->txt('mail_my_groups'), '#')
- ->withOnLoadCode(static fn($id): string => "
- document.getElementById('$id').addEventListener('click', function() {
- const frm = document.getElementById('$mail_form'),
- action = new URL(frm.action),
- action_params = new URLSearchParams(action.search);
-
- action_params.delete('cmd');
- action_params.append('cmd', 'searchGroupsTo');
-
- action.search = action_params.toString();
-
- frm.action = action.href;
- frm.submit();
- return false;
- });
- ");
- $this->toolbar->addComponent($btn);
-
- if (count(ilBuddyList::getInstanceByGlobalUser()->getLinkedRelations()) > 0) {
- $btn = $this->ui_factory->button()
- ->standard($this->lng->txt('mail_my_mailing_lists'), '#')
- ->withOnLoadCode(static fn($id): string => "
- document.getElementById('$id').addEventListener('click', function() {
- const frm = document.getElementById('$mail_form'),
- action = new URL(frm.action),
- action_params = new URLSearchParams(action.search);
-
- action_params.delete('cmd');
- action_params.append('cmd', 'searchMailingListsTo');
-
- action.search = action_params.toString();
-
- frm.action = action.href;
- frm.submit();
- return false;
- });
- ");
- $this->toolbar->addComponent($btn);
- }
-
$data_source_url = $this->ctrl->getLinkTarget($this, 'lookupRecipientAsync', '', true);
$inp = new ilTextInputGUI($this->lng->txt('mail_to'), 'rcp_to');
$inp->setMaxLength(null);
$inp->setRequired(true);
$inp->setSize(50);
- $inp->setValue((string) ($mail_data['rcp_to'] ?? ''));
+ if (isset($mail_data['rcp_to'])) {
+ $inp->setValue((string) $mail_data['rcp_to']);
+ }
$inp->setDataSource($data_source_url, ',');
$form_gui->addItem($inp);
$inp = new ilTextInputGUI($this->lng->txt('mail_cc'), 'rcp_cc');
$inp->setMaxLength(null);
$inp->setSize(50);
- $inp->setValue((string) ($mail_data['rcp_cc'] ?? ''));
+ if (isset($mail_data['rcp_cc'])) {
+ $inp->setValue((string) $mail_data['rcp_cc']);
+ }
$inp->setDataSource($data_source_url, ',');
$form_gui->addItem($inp);
$inp = new ilTextInputGUI($this->lng->txt('mail_bcc'), 'rcp_bcc');
$inp->setMaxLength(null);
$inp->setSize(50);
- $inp->setValue($mail_data['rcp_bcc'] ?? '');
+ if (isset($mail_data['rcp_to'])) {
+ $inp->setValue((string) $mail_data['rcp_bcc']);
+ }
$inp->setDataSource($data_source_url, ',');
$form_gui->addItem($inp);
$inp = new ilTextInputGUI($this->lng->txt('subject'), 'm_subject');
$inp->setSize(50);
$inp->setRequired(true);
- $inp->setValue((string) ($mail_data['m_subject'] ?? ''));
+ if (isset($mail_data['m_subject'])) {
+ $inp->setValue((string) $mail_data['m_subject']);
+ }
$form_gui->addItem($inp);
$att = new ilMailFormAttachmentPropertyGUI(
$this->lng->txt(
- isset($mail_data['attachments']) && is_array($mail_data['attachments']) ?
- 'edit' :
- 'add'
+ isset($mail_data['attachments']) && is_array($mail_data['attachments']) && $mail_data['attachments'] !== [] ?
+ 'edit' :
+ 'add'
),
'm_attachment'
);
- if (isset($mail_data['attachments']) && is_array($mail_data['attachments'])) {
+ if (isset($mail_data['attachments']) && is_array($mail_data['attachments']) && $mail_data['attachments'] !== []) {
foreach ($mail_data['attachments'] as $data) {
if (is_file($this->mfile->getMailPath() . '/' . $this->user->getId() . '_' . $data)) {
$hidden = new ilHiddenInputGUI('attachments[]');
+ $hidden->setValue(urlencode((string) $data));
$form_gui->addItem($hidden);
$size = filesize($this->mfile->getMailPath() . '/' . $this->user->getId() . '_' . $data);
$label = $data . ' [' . ilUtil::formatSize($size) . ']';
$att->addItem($label);
- $hidden->setValue(urlencode((string) $data));
}
}
}
@@ -866,10 +945,12 @@ public function showForm(): void
if (!isset($mail_data['template_id']) && $template->isDefault()) {
$template_chb->setValue((string) $template->getTplId());
- $form_gui->getItemByPostVar('m_subject')->setValue($template->getSubject());
- $mail_data['m_message'] = $template->getMessage() . $this->umail->appendSignature(
- $mail_data['m_message']
- );
+ if (isset($mail_data['m_message'])) {
+ $form_gui->getItemByPostVar('m_subject')->setValue($template->getSubject());
+ $mail_data['m_message'] = $template->getMessage() . $this->umail->appendSignature(
+ $mail_data['m_message']
+ );
+ }
}
}
if (isset($mail_data['template_id'])) {
@@ -882,21 +963,48 @@ public function showForm(): void
$form_gui->addItem($template_chb);
}
} catch (Exception) {
- ilLoggerFactory::getLogger('mail')->error(sprintf(
- '%s has been called with invalid context id: %s.',
- __METHOD__,
- $context_id
- ));
+ ilLoggerFactory::getLogger('mail')->error(
+ sprintf(
+ '%s has been called with invalid context id: %s.',
+ __METHOD__,
+ $context_id
+ )
+ );
}
}
$inp = new ilTextAreaInputGUI($this->lng->txt('message_content'), 'm_message');
- $inp->setValue((string) ($mail_data['m_message'] ?? ''));
+ if (isset($mail_data['m_message'])) {
+ $inp->setValue((string) ($mail_data['m_message']));
+ }
$inp->setRequired(false);
$inp->setCols(60);
$inp->setRows(10);
$form_gui->addItem($inp);
+ if (isset($mail_data['send_time'])) {
+ $current_time = new ilDateTime(time(), IL_CAL_UNIX, 'UTC');
+ $current_time->switchTimeZone($this->user->getTimezone());
+ $termination_time = (new ilDateTime((string) ($mail_data['send_time']), IL_CAL_DATETIME, 'UTC'));
+ $termination_time->switchTimeZone($this->user->getTimeZone());
+ }
+
+ $termination = new ilCheckboxInputGUI($this->lng->txt('mail_message_termination'), 'use_termination');
+ $termination->setValue('1');
+ $termination->setChecked(isset($current_time, $termination_time) && $termination_time->getUnixTime() >= $current_time->getUnixTime());
+
+ $termination_date = new ilDateTimeInputGUI('', 'm_termination');
+ $termination_date->setInfo($this->lng->txt('mail_message_termination_info'));
+ $termination_date->setShowTime(true);
+ if (isset($termination_time, $current_time)) {
+ $termination_date->setDate(
+ $termination_time->getUnixTime() >= $current_time->getUnixTime() ? $termination_time : $current_time
+ );
+ }
+
+ $termination->addSubItem($termination_date);
+ $form_gui->addItem($termination);
+
$chb = new ilCheckboxInputGUI(
$this->lng->txt('mail_serial_letter_placeholders'),
'use_placeholders'
@@ -927,12 +1035,7 @@ public function showForm(): void
$form_gui->addCommandButton('cancelMail', $this->lng->txt('cancel'));
}
- $this->tpl->parseCurrentBlock();
-
- $this->tpl->setVariable('FORM', $form_gui->getHTML());
-
- $this->tpl->addJavaScript('assets/js/ilMailComposeFunctions.js');
- $this->tpl->printToStdout();
+ return $form_gui;
}
public function lookupRecipientAsync(): void
diff --git a/components/ILIAS/Mail/classes/class.ilMailbox.php b/components/ILIAS/Mail/classes/class.ilMailbox.php
index 5d0c88d60235..aad9ad4cdb50 100755
--- a/components/ILIAS/Mail/classes/class.ilMailbox.php
+++ b/components/ILIAS/Mail/classes/class.ilMailbox.php
@@ -27,13 +27,22 @@ class ilMailbox
private readonly ilDBInterface $db;
private readonly ilTree $mtree;
- /** @var array{b_inbox: string, c_trash: string, d_drafts: string, e_sent: string, z_local : string} */
+ /** @var array{
+ * b_inbox: string,
+ * c_trash: string,
+ * d_drafts: string,
+ * e_sent: string,
+ * z_local : string,
+ * o_outbox: string
+ * }
+ */
private array $default_folders = [
'b_inbox' => 'inbox',
'c_trash' => 'trash',
'd_drafts' => 'drafts',
'e_sent' => 'sent',
'z_local' => 'local',
+ 'o_outbox' => 'outbox',
];
private readonly string $table_mail_obj_data;
private readonly string $table_tree;
@@ -96,6 +105,19 @@ public function getDraftsFolder(): int
return (int) $row['obj_id'];
}
+ public function getOutboxFolder(): int
+ {
+ $res = $this->db->queryF(
+ 'SELECT obj_id FROM ' . $this->table_mail_obj_data . ' WHERE user_id = %s AND m_type = %s',
+ ['integer', 'text'],
+ [$this->usr_id, 'outbox']
+ );
+
+ $row = $this->db->fetchAssoc($res);
+
+ return (int) $row['obj_id'];
+ }
+
public function getTrashFolder(): int
{
$res = $this->db->queryF(
diff --git a/components/ILIAS/Mail/service.xml b/components/ILIAS/Mail/service.xml
index c1919cdeb647..c7b8b4dfb355 100755
--- a/components/ILIAS/Mail/service.xml
+++ b/components/ILIAS/Mail/service.xml
@@ -13,6 +13,7 @@
+
diff --git a/components/ILIAS/Mail/tests/ilMailTest.php b/components/ILIAS/Mail/tests/ilMailTest.php
index d7af35d53e83..a57ed3774043 100755
--- a/components/ILIAS/Mail/tests/ilMailTest.php
+++ b/components/ILIAS/Mail/tests/ilMailTest.php
@@ -434,6 +434,10 @@ public function testGetNewDraftId(): void
public function testUpdateDraft(): void
{
+ $send_time = '2022-01-01 00:00:00';
+ $date_time = $this->getMockBuilder(ilDateTime::class)->disableOriginalConstructor()->getMock();
+ $date_time->expects($this->once())->method('get')->with(IL_CAL_DATETIME)->willReturn($send_time);
+
$folder_id = 7890;
$instance = $this->create();
$to = 'abc';
@@ -449,7 +453,7 @@ public function testUpdateDraft(): void
$this->mock_database->expects($this->once())->method('update')->with('mail', [
'folder_id' => ['integer', $folder_id],
'attachments' => ['clob', serialize([])],
- 'send_time' => ['timestamp', date('Y-m-d H:i:s')],
+ 'send_time' => ['timestamp', $send_time],
'rcp_to' => ['clob', $to],
'rcp_cc' => ['clob', $cc],
'rcp_bcc' => ['clob', $bcc],
@@ -463,7 +467,23 @@ public function testUpdateDraft(): void
'mail_id' => ['integer', $draft_id],
]);
- $this->assertSame($draft_id, $instance->updateDraft($folder_id, [], $to, $cc, $bcc, $subject, $message, $draft_id, $use_placeholders, $context_id, $params));
+ $this->assertSame(
+ $draft_id,
+ $instance->updateDraft(
+ $folder_id,
+ [],
+ $to,
+ $cc,
+ $bcc,
+ $subject,
+ $message,
+ $draft_id,
+ $date_time,
+ $use_placeholders,
+ $context_id,
+ $params
+ )
+ );
}
public function testPersistingToStage(): void
diff --git a/components/ILIAS/UI/resources/images/standard/icon_outbox.svg b/components/ILIAS/UI/resources/images/standard/icon_outbox.svg
new file mode 100644
index 000000000000..17dcc1bfeb85
--- /dev/null
+++ b/components/ILIAS/UI/resources/images/standard/icon_outbox.svg
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/lang/ilias_de.lang b/lang/ilias_de.lang
index 5ed4fb61c35c..8fa10245e8b8 100644
--- a/lang/ilias_de.lang
+++ b/lang/ilias_de.lang
@@ -4555,6 +4555,8 @@ common#:#mail_at_the_ilias_installation#:#Auf der ILIAS-Installation %2$s haben
common#:#mail_attachment#:#Mailanhang
common#:#mail_b_inbox#:#Posteingang
common#:#mail_c_trash#:#Papierkorb
+common#:#mail_cron_terminated_mails#:#Versende terminierte Mails
+common#:#mail_cron_terminated_mails_desc#:#...
common#:#mail_d_drafts#:#Entwürfe
common#:#mail_delete_error#:#Fehler beim Löschen
common#:#mail_e_sent#:#Gesendete
@@ -4565,7 +4567,10 @@ common#:#mail_mails_of#:#Mail
common#:#mail_maxsize_attach#:#Maximale Größe des Mail-Anhangs
common#:#mail_member#:#Mail an Mitglied
common#:#mail_members#:#Mail an Mitglieder
+common#:#mail_message_termination#:#Mail terminieren
+common#:#mail_message_termination_info#:#terminierte Mails werden bis zum gewählten Zeitpunkt im Postausgang verbleiben.
common#:#mail_not_sent#:#Ihre Mail konnte nicht verschickt werden
+common#:#mail_o_outbox#:#Postausgang
common#:#mail_search_no#:#Es wurden keine passenden Ergebnisse gefunden
common#:#mail_select_one#:#Sie müssen mindestens eine Mail auswählen
common#:#mail_send_error#:#Fehler beim Verschicken der Mail
diff --git a/lang/ilias_en.lang b/lang/ilias_en.lang
index 0e35906b5e7b..be4a31d0952a 100755
--- a/lang/ilias_en.lang
+++ b/lang/ilias_en.lang
@@ -4555,6 +4555,8 @@ common#:#mail_at_the_ilias_installation#:#You received %1$s new mail at the ILIA
common#:#mail_attachment#:#Mail attachment
common#:#mail_b_inbox#:#Inbox
common#:#mail_c_trash#:#Trash
+common#:#mail_cron_terminated_mails#:#Send scheduled mails
+common#:#mail_cron_terminated_mails_desc#:#...
common#:#mail_d_drafts#:#Drafts
common#:#mail_delete_error#:#Error while deleting
common#:#mail_e_sent#:#Sent
@@ -4565,7 +4567,10 @@ common#:#mail_mails_of#:#Mail
common#:#mail_maxsize_attach#:#Max. attachment size
common#:#mail_member#:#Mail to Member
common#:#mail_members#:#Mail to Members
+common#:#mail_message_termination#:#Schedule mail
+common#:#mail_message_termination_info#:#Scheduled mails will remain in the outbox until the selected time.
common#:#mail_not_sent#:#Mail not sent!
+common#:#mail_o_outbox#:#Outbox
common#:#mail_search_no#:#No entries found.
common#:#mail_select_one#:#You must select one mail
common#:#mail_send_error#:#Error sending mail