Skip to content

Commit

Permalink
Review and fix the implementation of the tags feature (cypht-org#1378)
Browse files Browse the repository at this point in the history
* WIP: Review and fix the tags feature

* More fixes: the tags ids do not change on each reload, the folder is registered when adding a tag, & msgs are listed

* Alter the tags storage structure to also save the msg uids as part of the tag rather than altering the message entry in the imap server

* Move output modules to their appropriate file

* Fix the tag handler called multiple times

* Revert changes made to merge_imap_search_results(). It is not needed anymore

* Does this hinder the selenium tests?
  • Loading branch information
mercihabam authored Nov 23, 2024
1 parent b4cd0f0 commit 3163ddf
Show file tree
Hide file tree
Showing 12 changed files with 524 additions and 490 deletions.
5 changes: 4 additions & 1 deletion lib/repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ protected static function initRepo($name, $user_config, $session, &$entities, ca
if ($init) {
$init($initial);
} else {
foreach ($initial as $entity) {
foreach ($initial as $key => $entity) {
if (! array_key_exists('id', $entity)) {
$entity['id'] = $key;
}
self::add($entity, false);
}
}
Expand Down
2 changes: 2 additions & 0 deletions modules/core/navigation/utils.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
function showRoutingToast() {
if (window.routingToast) hideRoutingToast();
window.routingToast = showLoaderToast('Redirecting...');
}

function hideRoutingToast() {
window.routingToast.hide();
window.routingToast = null;
}

function getListPathParam() {
Expand Down
38 changes: 0 additions & 38 deletions modules/imap/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1350,44 +1350,6 @@ function snooze_message($imap, $msg_id, $folder, $snooze_tag) {
}
return $res;
}}
if (!hm_exists('add_tag_to_message')) {
function add_tag_to_message($imap, $msg_id, $folder, $tag) {
if (!$imap->select_mailbox($folder)) {
return false;
}
$msg = $imap->get_message_content($msg_id, 0);
preg_match("/^X-Cypht-Tags:(.+)\r?\n/i", $msg, $matches);

if (count($matches)) {
$msg = str_replace($matches[0], '', $msg);
$tags = explode(',', $matches[1]);
if(in_array($tag, $tags)) {
unset($tags[array_search(trim($tag), $tags)]);
}else{
$tags[] = trim($tag);
}
}else {
$tags = array($tag);
}

$msg = "X-Cypht-Tags:".implode(',',$tags)."\n".$msg;
$msg = str_replace("\r\n", "\n", $msg);
$msg = str_replace("\n", "\r\n", $msg);
$msg = rtrim($msg)."\r\n";

$res = false;
if ($imap->append_start($folder, strlen($msg))) {
$imap->append_feed($msg."\r\n");
if ($imap->append_end()) {
if ($imap->message_action('DELETE', array($msg_id))) {
$imap->message_action('EXPUNGE', array($msg_id));
$res = true;
}
}
}

return $res;
}}

/**
* @subpackage imap/functions
Expand Down
38 changes: 0 additions & 38 deletions modules/imap/handler_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -1081,44 +1081,6 @@ public function process() {
}
}

/**
* Add tag/label to message
* @subpackage imap/handler
*/
class Hm_Handler_imap_add_tag_message extends Hm_Handler_Module {
/**
* Use IMAP to tag the selected message uid
*/
public function process() {
list($success, $form) = $this->process_form(array('tag_id', 'imap_server_ids'));
if (!$success) {
return;
}
$taged_messages = 0;
$ids = explode(',', $form['imap_server_ids']);
foreach ($ids as $msg_part) {
list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
$cache = Hm_IMAP_List::get_cache($this->cache, $imap_server_id);
$imap = Hm_IMAP_List::connect($imap_server_id, $cache);
if (imap_authed($imap)) {
$folder = hex2bin($folder);
if (add_tag_to_message($imap, $msg_id, $folder, $form['tag_id'])) {
$taged_messages++;
}
}
}
$this->out('taged_messages', $taged_messages);
if ($taged_messages == count($ids)) {
$msg = 'Tag added';
} elseif ($taged_messages > 0) {
$msg = 'Some messages have been taged';
} else {
$msg = 'ERRFailed to tag selected messages';
}
Hm_Msgs::add($msg);
}
}

/**
* Unsnooze messages
* @subpackage imap/handler
Expand Down
3 changes: 1 addition & 2 deletions modules/imap/js_modules/route_handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ function applyImapMessageListPageHandlers(routeParams) {
}

function applyImapMessageContentPageHandlers(routeParams) {
imap_setup_message_view_page(routeParams.uid, null, routeParams.list_path);
imap_setup_message_view_page(routeParams.uid, null, routeParams.list_path, imap_setup_tags);
imap_setup_snooze();
imap_setup_tags();

const messages = new Hm_MessagesStore(routeParams.list_path, routeParams.list_page);
messages.load(false);
Expand Down
8 changes: 0 additions & 8 deletions modules/imap/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,6 @@
add_handler('ajax_imap_snooze', 'save_imap_cache', true);
add_handler('ajax_imap_snooze', 'imap_snooze_message', true, 'core');

/* add label email */
setup_base_ajax_page('ajax_imap_tag', 'core');
add_handler('ajax_imap_tag', 'load_imap_servers_from_config', true);
add_handler('ajax_imap_tag', 'close_session_early', true, 'core');
add_handler('ajax_imap_tag', 'save_imap_cache', true);
add_handler('ajax_imap_tag', 'imap_add_tag_message', true, 'core');

/* unsnooze emails in snoozed folders */
setup_base_ajax_page('ajax_imap_unsnooze', 'core');
add_handler('ajax_imap_unsnooze', 'load_imap_servers_from_config', true);
Expand Down Expand Up @@ -348,7 +341,6 @@
'ajax_imap_move_copy_action',
'ajax_imap_folder_status',
'ajax_imap_snooze',
'ajax_imap_tag',
'ajax_imap_unsnooze',
'ajax_imap_junk',
'message_source',
Expand Down
14 changes: 3 additions & 11 deletions modules/imap/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -1042,8 +1042,8 @@ var imap_folder_status = function() {
}
};

var imap_setup_tags = function() {
$(document).on('click', '.label-checkbox', function() {
function imap_setup_tags() {
$('.label-checkbox').on('click', function() {
var folder_id = $(this).data('id');
var ids = [];
if (getPageNameParam() == 'message') {
Expand All @@ -1064,15 +1064,7 @@ var imap_setup_tags = function() {
Hm_Ajax.request(
[{'name': 'hm_ajax_hook', 'value': 'ajax_imap_tag'},
{'name': 'tag_id', 'value': folder_id},
{'name': 'imap_server_ids', 'value': ids}],
function(res) {
if (!res.router_user_msgs[0].startsWith('ERR')) {
Hm_Utils.search_from_local_storage("/^\d+_imap_.+/")?.forEach((source) => Hm_Utils.save_to_local_storage(source, 1));
Hm_Folders.reload_folders(true);
var path = hm_list_parent()? hm_list_parent(): getListPathParam();
window.location.replace('?page=message_list&list_path='+path);
}
}
{'name': 'list_path', 'value': ids}]
);
});
}
Expand Down
192 changes: 192 additions & 0 deletions modules/tags/handler_modules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php

/**
* @subpackage tags/handler
*/
class Hm_Handler_mod_env extends Hm_Handler_Module {
public function process() {
$this->out('mod_support', array_filter(array(
$this->module_is_supported('imap') ? 'imap' : false,
$this->module_is_supported('feeds') ? 'feeds' : false,
$this->module_is_supported('github') ? 'github' : false,
$this->module_is_supported('wordpress') ? 'wordpress' : false
)));
}
}

/**
* Add tag/label to message
* @subpackage imap/handler
*/
class Hm_Handler_add_tag_to_message extends Hm_Handler_Module {
/**
* Use IMAP to tag the selected message uid
*/
public function process() {
list($success, $form) = $this->process_form(array('tag_id', 'list_path'));
if (!$success) {
return;
}

$taged_messages = 0;
$ids = explode(',', $form['list_path']);
foreach ($ids as $msg_part) {
list($imap_server_id, $msg_id, $folder) = explode('_', $msg_part);
$folder = hex2bin($folder);
$tagged = Hm_Tags::addMessage($form['tag_id'], $imap_server_id, $folder, $msg_id);
if ($tagged) {
$taged_messages++;
}
}
$this->out('taged_messages', $taged_messages);
if ($taged_messages == count($ids)) {
$msg = 'Tag added';
} elseif ($taged_messages > 0) {
$msg = 'Some messages have been taged';
} else {
$msg = 'ERRFailed to tag selected messages';
}
Hm_Msgs::add($msg);
}
}

/**
* @subpackage tags/handler
*/
class Hm_Handler_tag_edit_data extends Hm_Handler_Module {
public function process() {
$id = false;
if (array_key_exists('tag_id', $this->request->get)) {
$id = $this->request->get['tag_id'];
}
$folders = $this->get('tags');
$folder = null;
foreach ($folders as $f) {
if ($f['id'] === $id) {
$folder = $f;
}
}
if ($id !== false) {
$this->out('edit_tag', $folder);
$this->out('edit_tag_id', $id);
}
else {
$this->out('new_tag_id', count($folders));
}
}
}
/**
* @subpackage tags/handler
*/
class Hm_Handler_process_tag_update extends Hm_Handler_Module {
public function process() {
if (array_key_exists('tag_delete', $this->request->post)) {
return;
}
list($success, $form) = $this->process_form(array('tag_name','parent_tag','tag_id'));// 'tag_id', parent_tag
if (!$success) {
return;
}
$tag = array(
'name' => html_entity_decode($form['tag_name'], ENT_QUOTES),
'parent' => $form['parent_tag'] ?? null
);
if (!is_null($form['tag_id']) AND Hm_Tags::get($form['tag_id'])) {
$tag['id'] = $form['tag_id'];
Hm_Tags::edit($form['tag_id'], $tag);
Hm_Msgs::add('Tag Edited');
} else {
Hm_Tags::add($tag);
Hm_Msgs::add('Tag Created');
}
}
}

/**
* @subpackage profile/handler
*/
class Hm_Handler_process_tag_delete extends Hm_Handler_Module {
public function process() {
list($success, $form) = $this->process_form(array('tag_delete', 'tag_id'));
if (!$success) {
return;
}
if (($tag = Hm_Tags::get($form['tag_id']))) {
Hm_Tags::del($tag['id']);
Hm_Msgs::add('Tag Deleted');
} else {
Hm_Msgs::add('ERRTag ID not found');
return;
}
}
}

/**
* @subpackage tags/handler
*/
class Hm_Handler_imap_tag_content extends Hm_Handler_Module {
public function process() {
$data_sources = imap_data_sources('');
$ids = array_map(function($ds) { return $ds['id']; }, $data_sources);
$tag_id = $this->request->post['folder'];
if ($ids && $tag_id) {
try {
$msg_list = [];
foreach ($ids as $serverId) {
$folders = Hm_Tags::getFolders($tag_id, $serverId);
if (!empty($folders)) {
$cache = Hm_IMAP_List::get_cache($this->cache, $serverId);
$imap = Hm_IMAP_List::connect($serverId, $cache);
$server_details = Hm_IMAP_List::dump($serverId);
if (imap_authed($imap)) {
foreach ($folders as $folder => $messageIds) {
$imap->select_mailbox($folder);
$messages = array_map(function($msg) use ($serverId, $folder, $server_details) {
$msg['server_id'] = $serverId;
$msg['folder'] = bin2hex($folder);
$msg['server_name'] = $server_details['name'];
return $msg;
}, $imap->get_message_list($messageIds));
$msg_list = array_merge($msg_list, $messages);
}
}
}
}
$limit = $this->user_config->get('tag_per_source_setting', DEFAULT_TAGS_PER_SOURCE);
$date = process_since_argument($this->user_config->get('tag_since_setting', DEFAULT_TAGS_SINCE));

$msg_list = array_filter($msg_list, function($msg) use ($date) {
return strtotime($msg['internal_date']) >= strtotime($date);
});
$msg_list = array_slice($msg_list, 0, $limit);
usort($msg_list, function($a, $b) {
return strtotime($b['internal_date']) - strtotime($a['internal_date']);
});

$this->out('imap_tag_data', $msg_list);
} catch (\Throwable $th) {
Hm_Msgs::add('ERRFailed to load tag messages: '.$th->getMessage());
}
}
}
}

/**
* Process "tag_per_source" setting for the tag page in the settings page
* @subpackage core/handler
*/
class Hm_Handler_process_tag_source_max_setting extends Hm_Handler_Module {
/**
* Allowed values are greater than zero and less than MAX_PER_SOURCE
*/
public function process() {
process_site_setting('tag_per_source', $this, 'max_source_setting_callback', DEFAULT_TAGS_PER_SOURCE);
}
}

class Hm_Handler_tag_data extends Hm_Handler_Module {
public function process() {
Hm_Tags::init($this);
$this->out('tags', Hm_Tags::getAll());
}
}
Loading

0 comments on commit 3163ddf

Please sign in to comment.