[TikiWiki-commits] [Git][tikiwiki/tiki][master] [ENH] Tiki webmail: Enhanced calendar functionality by integrating tracker...
"Marc Laporte \(@marclaporte\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <69c7cdd98e4da_3b192b98744a8@gitlab-sidekiq-low-urgency-cpu-bound-v2-566f8746dd-4kqt7.mail> |
Marc Laporte pushed to branch master at Tiki Wiki CMS Groupware / Tiki
Commits:
99650f37 by Yannick Nsenga at 2026-03-28T12:40:05+00:00
[ENH] Tiki webmail: Enhanced calendar functionality by integrating tracker email message handling for calendar invitations
---
* a lot of code fixes, resolving all review threads
* [REF] Tiki webmail: Refactor calendar invitation handling to unify IMAP and tracker message processing
* [ENH] Tiki webmail: Implement IMAP dependency checks for calendar and email functionalities
* [FIX] Tiki webmail: Include IMAP modules for email sending and streamline outbound message profile retrieval
* [ENH] Tiki webmail : Enhanced calendar functionality by integrating tracker message handling for calendar invitations
See merge request tikiwiki/tiki!8633
- - - - -
6 changed files:
- lib/cypht/modules/tiki/calendar_modules.php
- lib/cypht/modules/tiki/functions.php
- lib/cypht/modules/tiki/js_modules/DOM_events/message_content.js
- lib/cypht/modules/tiki/setup.php
- lib/cypht/modules/tiki/site.js
- lib/cypht/modules/tiki/tracker_modules.php
Changes:
=====================================
lib/cypht/modules/tiki/calendar_modules.php
=====================================
@@ -16,6 +16,7 @@ if (! defined('DEBUG_MODE')) {
require_once APP_PATH . 'modules/smtp/hm-mime-message.php';
+
/**
* Parse message and check for a calendar invitation
* @subpackage tiki/handler
@@ -24,9 +25,13 @@ class Hm_Handler_check_calendar_invitations_imap extends Hm_Handler_Module
{
public function process()
{
+ $list_path = $this->get('list_path', '') ?: ($this->request->post['list_path'] ?? '');
+ $is_tracker = strpos($list_path, 'tracker_folder_') === 0;
+
if ($this->get('msg_struct')) {
- get_calendar_part_imap($this->get('msg_struct'), $this);
+ get_calendar_part($this->get('msg_struct'), $this, ! $is_tracker);
}
+
if ($this->get('calendar_event_raw')) {
$event = Tiki\SabreDav\Utilities::getDenormalizedData($this->get('calendar_event_raw'));
if ($this->get('formatted_calendar_event_description')) {
@@ -36,7 +41,8 @@ class Hm_Handler_check_calendar_invitations_imap extends Hm_Handler_Module
} else {
$event = null;
}
- // get recipient from TO header
+
+ // Determine recipient (same logic for both types)
$recipient = null;
$headers = $this->get('msg_headers', []);
foreach ($headers as $name => $value) {
@@ -44,6 +50,7 @@ class Hm_Handler_check_calendar_invitations_imap extends Hm_Handler_Module
$recipient = (string)$value;
}
}
+
if (! empty($event['participants'])) {
// try to find the recipient in the participants' list
$found = false;
@@ -155,6 +162,17 @@ class Hm_Handler_event_rsvp_action extends Hm_Handler_Module
// use specific text body for the reply
$event = $this->get('calendar_event');
$comment = $this->request->post['rsvp_comment'] ?? '';
+
+ // Extract sender name from headers
+ $from_name = 'User';
+ $headers = $this->get('msg_headers', []);
+ foreach ($headers as $name => $value) {
+ if (strtolower($name) == 'from') {
+ $from_name = (string)$value;
+ break;
+ }
+ }
+
$body = "$from_name has $action the invitation to the following event: \n\n*{$event['name']}*";
if ($comment) {
$body .= "\n\nNote: $comment";
@@ -510,10 +528,11 @@ class Hm_Output_add_rsvp_actions extends Hm_Output_Module
* @subpackage tiki/functions
* @param array $struct message structure
* @param object $mod Hm_Handler_Module
+ * @param bool $is_imap indicates if the source is an IMAP message or a Tiki tracker message
* @return string
*/
-if (! hm_exists('get_calendar_part_imap')) {
- function get_calendar_part_imap($struct, $mod)
+if (! hm_exists('get_calendar_part')) {
+ function get_calendar_part($struct, $mod, $is_imap = true)
{
$event = $method = $html = null;
$part = false;
@@ -528,31 +547,66 @@ if (! hm_exists('get_calendar_part_imap')) {
$htmlPart = $id;
}
if (isset($vals['subs'])) {
- return get_calendar_part_imap($vals['subs'], $mod);
+ return get_calendar_part($vals['subs'], $mod, $is_imap);
}
} else {
if (is_array($vals) && count($vals) == 1 && isset($vals['subs'])) {
- return get_calendar_part_imap($vals['subs'], $mod);
+ return get_calendar_part($vals['subs'], $mod, $is_imap);
}
}
}
if (! $part) {
return;
}
- list($success, $form) = $mod->process_form(['imap_server_id', 'imap_msg_uid', 'folder']);
- if ($success) {
- $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $mod->cache);
- if ($mailbox->authed()) {
- $event = $mailbox->get_structured_message(hex2bin($form['folder']), $form['imap_msg_uid'], $part, true)[2];
- if ($htmlPart) {
- $html = $mailbox->get_structured_message(hex2bin($form['folder']), $form['imap_msg_uid'], $htmlPart, true)[2];
- $html = sanitize_email_html($html);
- $html = format_msg_html($html);
- }
- }
+
+ if ($is_imap) {
+ process_calendar_imap($html, $event, $mod, $part, $htmlPart);
+ } else {
+ process_calendar_tiki($html, $event, $method, $mod, $part, $htmlPart);
}
+
$mod->out('calendar_method', $method);
$mod->out('calendar_event_raw', $event);
$mod->out('formatted_calendar_event_description', $html);
}
}
+
+function process_calendar_imap(&$html, &$event, $mod, $part, $htmlPart)
+{
+ list($success, $form) = $mod->process_form(['imap_server_id', 'imap_msg_uid', 'folder']);
+ if ($success) {
+ $mailbox = Hm_IMAP_List::get_connected_mailbox($form['imap_server_id'], $mod->cache);
+ if ($mailbox->authed()) {
+ $event = $mailbox->get_structured_message(hex2bin($form['folder']), $form['imap_msg_uid'], $part, true)[2];
+ if ($htmlPart) {
+ $html = $mailbox->get_structured_message(hex2bin($form['folder']), $form['imap_msg_uid'], $htmlPart, true)[2];
+ $html = sanitize_email_html($html);
+ $html = format_msg_html($html);
+ }
+ }
+ }
+}
+
+function process_calendar_tiki(&$html, &$event, &$method, $mod, $part, $htmlPart)
+{
+ list($success, $form) = $mod->process_form(['imap_msg_uid', 'list_path']);
+ if ($success) {
+ $email = tiki_parse_message($form['list_path'], $form['imap_msg_uid']);
+ if ($email && ! empty($email['message_raw'])) {
+ $message = $email['message_raw'];
+ $mimePart = tiki_get_mime_part($message, $part);
+ if ($mimePart) {
+ $event = $mimePart->getContent();
+ $header = $mimePart->getHeader('Content-Type');
+ if (! $method && $header && $header->hasParameter('method')) {
+ $method = $header->getValueFor('method');
+ }
+ }
+ $html = tiki_get_mime_part($message, $htmlPart);
+ if ($html) {
+ $html = sanitize_email_html($html->getContent());
+ $html = format_msg_html($html);
+ }
+ }
+ }
+}
=====================================
lib/cypht/modules/tiki/functions.php
=====================================
@@ -10,6 +10,7 @@ if (! defined('DEBUG_MODE')) {
die();
}
+
/**
* Retrive a Tiki-stored mail message and convert to a parsed mime message
* @subpackage tiki/functions
@@ -290,6 +291,12 @@ if (! hm_exists('tiki_flag_message')) {
if (! hm_exists('tiki_send_email_through_cypht')) {
function tiki_send_email_through_cypht($to, $cc, $subject, $body, $in_reply_to, $file, $profiles, $hmod, $recipient = null)
{
+ // Ensure IMAP dependency is available
+ if (! class_exists('Hm_SMTP_List')) {
+ Hm_Msgs::add('The smtp module is required to send emails. Please enable it through the configuration file.', 'danger');
+ return false;
+ }
+
// retrieve smtp server connected with an existing imap message via profiles
$smtp_id = 0;
$compose_smtp_id = null;
@@ -321,7 +328,6 @@ if (! hm_exists('tiki_send_email_through_cypht')) {
// profile details
list($imap_server, $from_name, $reply_to, $from) = get_outbound_msg_profile_detail(['compose_smtp_id' => $compose_smtp_id], $profiles, $smtp_details, $hmod);
-
// xoauth2 check
smtp_refresh_oauth2_token_on_send($smtp_details, $hmod, $smtp_id);
=====================================
lib/cypht/modules/tiki/js_modules/DOM_events/message_content.js
=====================================
@@ -39,6 +39,8 @@ function RSVPButtonClick() {
if (action == "accept" && $('.event_calendar_select_rsvp').val()) {
tiki_event_calendar($('.event_calendar_select_rsvp').val());
}
+
+ // Use single RSVP endpoint with source detection via list_path
const detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
$.tikiModal("Please wait...");
Hm_Ajax.request(
@@ -47,7 +49,8 @@ function RSVPButtonClick() {
{'name': 'rsvp_comment', 'value': comment},
{'name': 'imap_msg_uid', 'value': getMessageUidParam()},
{'name': 'imap_server_id', 'value': detail.server_id},
- {'name': 'folder', 'value': detail.folder}],
+ {'name': 'folder', 'value': detail.folder},
+ {'name': 'list_path', 'value': getListPathParam()}],
function() {
Hm_Notices.show(tr("Your response has been sent."), "success");
$.closeModal();
=====================================
lib/cypht/modules/tiki/setup.php
=====================================
@@ -72,15 +72,20 @@ add_output('ajax_imap_message_content', 'add_move_to_trackers', true, 'imap', 'f
add_output('ajax_imap_message_content', 'tiki_get_create_item_trackers_output', true, 'imap', 'filter_message_headers', 'after');
add_output('ajax_imap_message_content', 'add_restore_message', true, 'imap', 'filter_message_headers', 'after');
+/* message page calendar invitation hooks (Tracker-stored messages) */
+add_handler('ajax_tiki_message_content', 'check_calendar_invitations_imap', true, 'imap', 'tiki_message_content', 'after');
+add_output('ajax_tiki_message_content', 'add_rsvp_actions', true, 'tiki', 'filter_message_headers', 'after');
+
/* message page rsvp actions to an event */
setup_base_ajax_page('ajax_rsvp_action', 'core');
-add_handler('ajax_rsvp_action', 'check_calendar_invitations_imap', true, 'imap', 'imap_message_content', 'after');
add_handler('ajax_rsvp_action', 'load_imap_servers_from_config', true, 'imap');
add_handler('ajax_rsvp_action', 'load_smtp_servers_from_config', true, 'smtp', 'load_imap_servers_from_config', 'after');
add_handler('ajax_rsvp_action', 'add_smtp_servers_to_page_data', true, 'smtp', 'load_smtp_servers_from_config', 'after');
add_handler('ajax_rsvp_action', 'compose_profile_data', true, 'profiles', 'add_smtp_servers_to_page_data', 'after');
-add_handler('ajax_rsvp_action', 'imap_message_content', true, 'imap', 'compose_profile_data', 'after');
-add_handler('ajax_rsvp_action', 'event_rsvp_action', true, 'tiki', 'imap_message_content', 'after');
+add_handler('ajax_rsvp_action', 'tiki_message_content', true, 'tiki', 'compose_profile_data', 'after');
+add_handler('ajax_rsvp_action', 'imap_message_content', true, 'imap', 'tiki_message_content', 'after');
+add_handler('ajax_rsvp_action', 'check_calendar_invitations_imap', true, 'imap', 'imap_message_content', 'after');
+add_handler('ajax_rsvp_action', 'event_rsvp_action', true, 'tiki', 'check_calendar_invitations_imap', 'after');
/* message page add to calendar function */
setup_base_ajax_page('ajax_add_to_calendar', 'core');
=====================================
lib/cypht/modules/tiki/site.js
=====================================
@@ -65,6 +65,11 @@ var tiki_groupmail_put_back = function(btn, id) {
);
};
+// Helper function to detect if we're viewing a tracker email
+function isTrackerPath() {
+ return (getListPathParam() || '').indexOf('tracker_folder_') === 0;
+}
+
var tiki_event_calendar = function(calendar_id) {
var uid = getMessageUidParam();
var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
@@ -73,7 +78,8 @@ var tiki_event_calendar = function(calendar_id) {
{'name': 'calendar_id', 'value': calendar_id},
{'name': 'imap_msg_uid', 'value': uid},
{'name': 'imap_server_id', 'value': detail.server_id},
- {'name': 'folder', 'value': detail.folder}],
+ {'name': 'folder', 'value': detail.folder},
+ {'name': 'list_path', 'value': getListPathParam()}],
function(res) {
// noop
},
@@ -89,13 +95,14 @@ var tiki_event_rsvp_actions = function() {
});
$(document).on("click", '.event_calendar_update', function(e) {
var uid = getMessageUidParam();
- var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
var $btn = $(this);
+ var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
Hm_Ajax.request(
[{'name': 'hm_ajax_hook', 'value': 'ajax_update_in_calendar'},
{'name': 'imap_msg_uid', 'value': uid},
{'name': 'imap_server_id', 'value': detail.server_id},
- {'name': 'folder', 'value': detail.folder}],
+ {'name': 'folder', 'value': detail.folder},
+ {'name': 'list_path', 'value': getListPathParam()}],
function(res) {
// noop
},
@@ -106,13 +113,14 @@ var tiki_event_rsvp_actions = function() {
$(document).on("click", '.event_update_participant_status', function(e) {
e.preventDefault();
var uid = getMessageUidParam();
- var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
var $btn = $(this);
+ var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
Hm_Ajax.request(
[{'name': 'hm_ajax_hook', 'value': 'ajax_update_participant_status'},
{'name': 'imap_msg_uid', 'value': uid},
{'name': 'imap_server_id', 'value': detail.server_id},
- {'name': 'folder', 'value': detail.folder}],
+ {'name': 'folder', 'value': detail.folder},
+ {'name': 'list_path', 'value': getListPathParam()}],
function(res) {
$('.event_update_participant_status').text("Participant status updated");
$('.event_update_participant_status').toggleClass('event_update_participant_status event_participant_status_updated');
@@ -124,13 +132,14 @@ var tiki_event_rsvp_actions = function() {
$(document).on("click", '.event_remove_from_calendar', function(e) {
e.preventDefault();
var uid = getMessageUidParam();
- var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
var $btn = $(this);
+ var detail = Hm_Utils.parse_folder_path(getListPathParam(), 'imap');
Hm_Ajax.request(
[{'name': 'hm_ajax_hook', 'value': 'ajax_remove_from_calendar'},
{'name': 'imap_msg_uid', 'value': uid},
{'name': 'imap_server_id', 'value': detail.server_id},
- {'name': 'folder', 'value': detail.folder}],
+ {'name': 'folder', 'value': detail.folder},
+ {'name': 'list_path', 'value': getListPathParam()}],
function(res) {
// noop
},
=====================================
lib/cypht/modules/tiki/tracker_modules.php
=====================================
@@ -771,11 +771,17 @@ class Hm_Handler_tiki_message_content extends Hm_Handler_Module
return;
}
+ // Only process tracker-stored messages; skip regular IMAP messages
+ $list_path = $this->request->post['list_path'] ?? '';
+ if (strpos($list_path, 'tracker_folder_') !== 0) {
+ return;
+ }
+
$this->out('header_allow_images', $this->config->get('allow_external_image_sources'));
$this->out('images_whitelist', explode(',', $this->user_config->get('images_whitelist_setting')));
$this->out('msg_text_uid', $form['imap_msg_uid']);
- $this->out('msg_list_path', $this->request->post['list_path']);
+ $this->out('msg_list_path', $list_path);
$part_num = false;
if (isset($this->request->post['imap_msg_part']) && preg_match("/[0-9\.]+/", $this->request->post['imap_msg_part'])) {
$part_num = $this->request->post['imap_msg_part'];
@@ -785,7 +791,7 @@ class Hm_Handler_tiki_message_content extends Hm_Handler_Module
}
$this->out('header_allow_images', $this->config->get('allow_external_image_sources'));
- $email = tiki_parse_message($this->request->post['list_path'], $form['imap_msg_uid']);
+ $email = tiki_parse_message($list_path, $form['imap_msg_uid']);
if (! $email) {
return;
}
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/99650f37d03e4b566fc312e7098e8ed6e3f77a43
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/99650f37d03e4b566fc312e7098e8ed6e3f77a43
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs