Skip to content

Commit

Permalink
Merge pull request cypht-org#1270 from Shadow243/imap-capabilities-fo…
Browse files Browse the repository at this point in the history
…r-sharing-folders

[ENH] Implement Expose IMAP capabilities for sharing folders
  • Loading branch information
marclaporte authored Oct 12, 2024
2 parents 52f958f + ac7d952 commit a8dc883
Show file tree
Hide file tree
Showing 12 changed files with 518 additions and 5 deletions.
1 change: 1 addition & 0 deletions modules/core/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ function setup_base_page($name, $source=false, $use_layout=true) {
add_output($name, 'folder_list_end', true, $source);
add_output($name, 'content_section_start', true, $source);
add_output($name, 'content_section_end', true, $source);
add_output($name, 'modals', true, $source);
add_output($name, 'save_reminder', true, $source);
add_output($name, 'content_end', false, $source, 'page_js', 'after');
}
Expand Down
106 changes: 106 additions & 0 deletions modules/core/output_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -1647,6 +1647,112 @@ protected function output() {
}
}

/**
* modals
* @subpackage core/output
*/
class Hm_Output_modals extends Hm_Output_Module {
/**
* Outputs modals
*/
protected function output() {
$share_folder_modal = '<div class="modal fade" id="shareFolderModal" tabindex="-1" aria-labelledby="shareFolderModalLabel" aria-hidden="true">';
$share_folder_modal .= '<div class="modal-dialog modal-lg">';
$share_folder_modal .= '<div class="modal-content">';
$share_folder_modal .= '<div class="modal-header">';
$share_folder_modal .= '<h5 class="modal-title" id="shareFolderModalLabel">'.$this->trans('Edit Permissions').'</h5>';
$share_folder_modal .= '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '<div class="modal-body">';
$share_folder_modal .= '<div class="row">';

$share_folder_modal .= '<div class="col-lg-8 col-md-12">';

$share_folder_modal .= '<div id="loadingSpinner" class="text-center">';
$share_folder_modal .= '<div class="spinner-border text-primary" role="status">';
$share_folder_modal .= '<span class="visually-hidden">Loading...</span>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '<table class="table table-striped" id="permissionTable" style="display:none;">';
$share_folder_modal .= '<thead>';
$share_folder_modal .= '<tr>';
$share_folder_modal .= '<th>'.$this->trans('User').'</th>';
$share_folder_modal .= '<th>'.$this->trans('Permissions').'</th>';
$share_folder_modal .= '<th>'.$this->trans('Actions').'</th>';
$share_folder_modal .= '</tr>';
$share_folder_modal .= '</thead>';
$share_folder_modal .= '<tbody></tbody>';
$share_folder_modal .= '</table>';

$share_folder_modal .= '</div>';

$share_folder_modal .= '<div class="col-lg-4 col-md-12">';
$share_folder_modal .= '<form id="shareForm" action="" method="POST">';
$share_folder_modal .= '<input type="hidden" name="server_id" id="server_id" value="">';
$share_folder_modal .= '<input type="hidden" name="folder_uid" id="folder_uid" value="">';
$share_folder_modal .= '<input type="hidden" name="folder" id="folder" value="">';

$share_folder_modal .= '<div class="mb-3 row">';
$share_folder_modal .= '<div class="col-12">';
$share_folder_modal .= '<label class="form-label">'.$this->trans('Identifier').'</label>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="radio" name="identifier" value="user" id="identifierUser" checked>';
$share_folder_modal .= '<label for="identifierUser">'.$this->trans('User').':</label>';
$share_folder_modal .= '<input type="text" class="form-control d-inline-block" id="email" name="email" required placeholder="Enter email">';
$share_folder_modal .= '</div>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="radio" name="identifier" value="all" id="identifierAll">';
$share_folder_modal .= '<label for="identifierAll">'.$this->trans('All users (anyone)').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="radio" name="identifier" value="guests" id="identifierGuests">';
$share_folder_modal .= '<label for="identifierGuests">'.$this->trans('Guests (anonymous)').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '<div class="mb-3 row">';
$share_folder_modal .= '<div class="col-12">';
$share_folder_modal .= '<label class="form-label">'.$this->trans('Access Rights').'</label>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="checkbox" name="access_read" id="accessRead" checked>';
$share_folder_modal .= '<label for="accessRead">'.$this->trans('Read').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="checkbox" name="access_write" id="accessWrite">';
$share_folder_modal .= '<label for="accessWrite">'.$this->trans('Write').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="checkbox" name="access_delete" id="accessDelete">';
$share_folder_modal .= '<label for="accessDelete">'.$this->trans('Delete').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '<div>';
$share_folder_modal .= '<input type="checkbox" name="access_other" id="accessOther">';
$share_folder_modal .= '<label for="accessOther">'.$this->trans('Other').'</label>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '<div class="modal-footer">';
$share_folder_modal .= '<button type="submit" class="btn btn-primary">'.$this->trans('Save').'</button>';
$share_folder_modal .= '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">'.$this->trans('Cancel').'</button>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</form>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';

$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';
$share_folder_modal .= '</div>';

return $share_folder_modal;
}
}

/**
* Starts the message view page
* @subpackage core/output
Expand Down
12 changes: 12 additions & 0 deletions modules/core/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ $.fn.fadeOutAndRemove = function(timeout = 600) {
return this;
};

$.fn.modal = function(action) {
const modalElement = this[0];
if (modalElement) {
const modal = new bootstrap.Modal(modalElement);
if (action === 'show') {
modal.show();
} else if (action === 'hide') {
modal.hide();
}
}
};

/* swipe event handler */
var swipe_event = function(el, callback, direction) {
var start_x, start_y, dist_x, dist_y, threshold = 150, restraint = 100,
Expand Down
10 changes: 7 additions & 3 deletions modules/imap/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function prepare_imap_message_list($msgs, $mod, $type) {
* @return string
*/
if (!hm_exists('format_imap_folder_section')) {
function format_imap_folder_section($folders, $id, $output_mod, $with_input = false) {
function format_imap_folder_section($folders, $id, $output_mod, $with_input = false, $can_share_folders = false) {
$results = '<ul class="inner_list">';
$manage = $output_mod->get('imap_folder_manage_link');

Expand All @@ -131,7 +131,7 @@ function format_imap_folder_section($folders, $id, $output_mod, $with_input = fa
$attrs .= ' class="folder-disabled"';
}
} else {
$attrs = 'data-id="imap_'.$id.'_'.$output_mod->html_safe($folder_name).
$attrs = 'id="main-link" data-id="imap_'.$id.'_'.$output_mod->html_safe($folder_name).
'" href="?page=message_list&amp;list_path='.
urlencode('imap_'.$id.'_'.$output_mod->html_safe($folder_name)).'"';
}
Expand All @@ -150,7 +150,11 @@ function format_imap_folder_section($folders, $id, $output_mod, $with_input = fa
if ($with_input) {
$results .= '<input type="checkbox" value="1" class="folder_subscription" id="'.$output_mod->html_safe($folder_name).'" name="'.$folder_name.'" '.($folder['subscribed']? 'checked="checked"': '').($folder['special']? ' disabled="disabled"': '').' />';
}
$results .= '<span class="unread_count unread_imap_'.$id.'_'.$output_mod->html_safe($folder_name).'"></span></li>';
$results .= '<span class="unread_count unread_imap_'.$id.'_'.$output_mod->html_safe($folder_name).'"></span>';
if($can_share_folders) {
$results .= '<div class="dropdown"><a href="#" class="action-link" data-bs-toggle="dropdown" aria-expanded="false"><i class="icon bi bi-three-dots-vertical"></i></a><ul class="dropdown-menu dropdown-menu"><li data-id="'.$id.'" data-folder-uid="'.$output_mod->html_safe($folder_name).'" data-folder="'.$output_mod->html_safe($folder['basename']).'"><a href="#" class="dropdown-item share"><i class="icon bi bi-share"></i> Share</a></ul></div>';
}
$results .= '</li>';
}
if ($manage) {
$results .= '<li class="manage_folders_li"><i class="bi bi-gear-wide me-1"></i><a class="manage_folder_link" href="'.$manage.'">'.$output_mod->trans('Manage Folders').'</a></li>';
Expand Down
54 changes: 54 additions & 0 deletions modules/imap/handler_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ public function process() {
$with_subscription = isset($this->request->post['subscription_state']) && $this->request->post['subscription_state'];
$cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);
$imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache);
$this->out('can_share_folders', stripos($imap->get_capability(), 'ACL') !== false);
if (imap_authed($imap)) {
$quota_root = $imap->get_quota_root($folder ? $folder : 'INBOX');
if ($quota_root && isset($quota_root[0]['name'])) {
Expand Down Expand Up @@ -1630,6 +1631,59 @@ public function process() {
}
}
}
/**
* Load IMAP servers permissions for shared folders
* @subpackage imap/handler
*/
class Hm_Handler_load_imap_folders_permissions extends Hm_Handler_Module {
/**
* Output IMAP server permissions array for shared folders
*/
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id','imap_folder_uid','imap_folder'));

if ($success && !empty($form['imap_server_id']) && !empty($form['imap_folder']) && !empty($form['imap_folder_uid'])) {
Hm_IMAP_List::init($this->user_config, $this->session);
$server = Hm_IMAP_List::dump($form['imap_server_id'], true);
$cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);

$imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $server['user'], $server['pass']);
$permissions = $imap->get_acl($form['imap_folder']);
$this->out('imap_folders_permissions', $permissions);
}
}
}

/**
* Load IMAP servers permissions for shared folders
* @subpackage imap/handler
*/
class Hm_Handler_set_acl_to_imap_folders extends Hm_Handler_Module {
/**
* Output IMAP server permissions array for shared folders
*/
public function process() {
list($success, $form) = $this->process_form(array('imap_server_id','imap_folder','identifier','permissions','action'));

if ($success && !empty($form['imap_server_id']) && !empty($form['identifier']) && !empty($form['permissions']) && !empty($form['action'])) {

Hm_IMAP_List::init($this->user_config, $this->session);
$server = Hm_IMAP_List::dump($form['imap_server_id'], true);
$cache = Hm_IMAP_List::get_cache($this->cache, $form['imap_server_id']);

$imap = Hm_IMAP_List::connect($form['imap_server_id'], $cache, $server['user'], $server['pass']);
if($form['action'] === 'add') {
$response = $imap->set_acl($form['imap_folder'], $form['identifier'], $form['permissions']);
} else {
$response = $imap->delete_acl($form['imap_folder'], $form['identifier']);
}
if($response) {
$permissions = $imap->get_acl($form['imap_folder']);
$this->out('imap_folders_permissions', $permissions);
}
}
}
}

/**
* Load IMAP servers for the user config object
Expand Down
Loading

0 comments on commit a8dc883

Please sign in to comment.