diff --git a/.env.example b/.env.example index 899e8bab87..c51d242ae1 100644 --- a/.env.example +++ b/.env.example @@ -173,6 +173,14 @@ OUTLOOK_AUTH_URI=https://login.live.com/oauth20_authorize.srf OUTLOOK_TOKEN_URI=https://login.live.com/oauth20_token.srf OUTLOOK_REFRESH_URI=https://login.live.com/oauth20_token.srf +#office365 +OFFICE365_CLIENT_ID= +OFFICE365_CLIENT_SECRET= +OFFICE365_CLIENT_URI=http://localhost/?page=home +OFFICE365_AUTH_URI=https://login.live.com/oauth20_authorize.srf +OFFICE365_TOKEN_URI=https://login.live.com/oauth20_token.srf +OFFICE365_REFRESH_URI=https://login.live.com/oauth20_token.srf + #ldap.php LDAP_SERVER=localhost LDAP_ENABLE_TLS=true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d40a2770ac..811e3b384e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,18 @@ + + ## 🍰 Pullrequest diff --git a/.github/workflows/test.lint.pr.yml b/.github/workflows/test.lint.pr.yml index c800e54a7c..4f20b40f70 100644 --- a/.github/workflows/test.lint.pr.yml +++ b/.github/workflows/test.lint.pr.yml @@ -29,12 +29,17 @@ jobs: # Configure which scopes are allowed (newline delimited). # Append a scope for each service here scopes: | - docu + docs docker release workflow + frontend + backend + frontend/backend + module/[a-z-]+ + unit + e2e other - cypht # Configure that a scope must always be provided. requireScope: true # Configure which scopes (newline delimited) are disallowed in PR diff --git a/config/oauth2.php b/config/oauth2.php index 35c3912803..21f5a812cc 100644 --- a/config/oauth2.php +++ b/config/oauth2.php @@ -39,4 +39,14 @@ 'token_uri' => env('OUTLOOK_TOKEN_URI', 'https://login.live.com/oauth20_token.srf'), 'refresh_uri' => env('OUTLOOK_REFRESH_URI', 'https://login.live.com/oauth20_token.srf') ], + + //[office365] + 'office365' => [ + 'client_id' => env('OFFICE365_CLIENT_ID', ''), + 'client_secret' => env('OFFICE365_CLIENT_SECRET', ''), + 'client_uri' => env('OFFICE365_CLIENT_URI', 'http://localhost/?page=home'), + 'auth_uri' => env('OFFICE365_AUTH_URI', 'https://login.live.com/oauth20_authorize.srf'), + 'token_uri' => env('OFFICE365_TOKEN_URI', 'https://login.live.com/oauth20_token.srf'), + 'refresh_uri' => env('OFFICE365_REFRESH_URI', 'https://login.live.com/oauth20_token.srf') + ], ]; diff --git a/modules/advanced_search/js_modules/route_handlers.js b/modules/advanced_search/js_modules/route_handlers.js index 4cd54ff165..b5b41beaaf 100644 --- a/modules/advanced_search/js_modules/route_handlers.js +++ b/modules/advanced_search/js_modules/route_handlers.js @@ -21,7 +21,6 @@ function applyAdvancedSearchPageHandlers() { $('.adv_controls').show(); $('.core_msg_control').off('click'); $('.core_msg_control').on("click", function() { return Hm_Message_List.message_action($(this).data('action')); }); - Hm_Message_List.set_checkbox_callback(); if (typeof check_select_for_imap !== 'undefined') { check_select_for_imap(); } diff --git a/modules/advanced_search/modules.php b/modules/advanced_search/modules.php index b73663f6d4..752ffc9ef7 100644 --- a/modules/advanced_search/modules.php +++ b/modules/advanced_search/modules.php @@ -90,11 +90,16 @@ public function process() { } } - if ($this->request->post['all_folders']) { + $searchInAllFolders = $this->request->post['all_folders'] ?? false; + $searchInSpecialFolders = $this->request->post['all_special_folders'] ?? false; + $includeSubfolders = $this->request->post['include_subfolders'] ?? false; + if ($searchInAllFolders) { $msg_list = $this->all_folders_search($mailbox, $flags, $params, $limit); - } elseif ($this->request->post['all_special_folders']) { + } elseif ($searchInSpecialFolders) { $msg_list = $this->special_folders_search($mailbox, $flags, $params, $limit); - } else if (!$mailbox->select_mailbox($this->folder)) { + } else if ($includeSubfolders) { + $msg_list = $this->all_folders_search($mailbox, $flags, $params, $limit, $this->folder); + } else if (! $mailbox->select_mailbox($this->folder)) { return; } else { $msg_list = $this->imap_search($flags, $mailbox, $params, $limit); @@ -104,8 +109,12 @@ public function process() { $this->out('imap_server_ids', array($this->imap_id)); } - private function all_folders_search($mailbox, $flags, $params, $limit) { - $folders = $mailbox->get_folders(); + private function all_folders_search($mailbox, $flags, $params, $limit, $parent = '') { + if ($parent) { + $folders = $mailbox->get_subfolders($parent); + } else { + $folders = $mailbox->get_folders(); + } $msg_list = array(); foreach ($folders as $folder) { $this->folder = $folder['name']; diff --git a/modules/advanced_search/setup.php b/modules/advanced_search/setup.php index c147a48c45..cef80eb541 100644 --- a/modules/advanced_search/setup.php +++ b/modules/advanced_search/setup.php @@ -41,5 +41,6 @@ 'adv_targets' => array('filter' => FILTER_DEFAULT, 'flags' => FILTER_REQUIRE_ARRAY), 'all_folders' => FILTER_VALIDATE_BOOLEAN, 'all_special_folders' => FILTER_VALIDATE_BOOLEAN, + 'include_subfolders' => FILTER_VALIDATE_BOOLEAN, ) ); diff --git a/modules/advanced_search/site.js b/modules/advanced_search/site.js index b8cf2020f3..5b221b34f0 100644 --- a/modules/advanced_search/site.js +++ b/modules/advanced_search/site.js @@ -82,6 +82,7 @@ var expand_adv_folder = function(res) { $('.adv_folder_link', list_container).on("click", function() { return expand_adv_folder_list($(this).data('target')); }); $('a', list_container).not('.adv_folder_link').off('click'); $('a', list_container).not('.adv_folder_link').on("click", function() { adv_folder_select($(this).data('id')); return false; }); + modifyInnerLists(); } }; @@ -131,7 +132,9 @@ var adv_select_imap_folder = function(el) { checkboxesWrapper.append(allSpecialFoldersCheckbox); checkboxesWrapper.append(allFoldersCheckbox); $(this).find('.wrapper').append(checkboxesWrapper); - }) + }); + + modifyInnerLists(); $('.imap_folder_link', folders).addClass('adv_folder_link').removeClass('imap_folder_link'); $('.adv_folder_list').html(folders.html()); @@ -147,6 +150,20 @@ var adv_select_imap_folder = function(el) { }); }; +function modifyInnerLists() { + $('.adv_folder_list').find('.inner_list li').each(function(index) { + const subFoldersCheckbox = ` + + + + + `; + $(this).wrapInner('
'); + $(this).find('.wrapper').append(subFoldersCheckbox); + $(this).find('#main-link').css('flex-grow', 0) + }); +} + var adv_folder_select = function(id) { if ($('.'+id, $('.adv_source_list')).length > 0) { $('.adv_folder_list').html(''); @@ -164,17 +181,19 @@ var adv_folder_select = function(id) { var parent_class = '.'+parts[0]+'_'+parts[1]+'_'; var account = $('a', $(parent_class, container)).first().text(); var label = account+' > '+folder; - add_source_to_list(id, label); + const includeSubfolders = $(`.${id}`).closest('li').find('input[name="include_subfolders"]').is(':checked'); + + add_source_to_list(id, label, includeSubfolders); $('.adv_folder_list').html(''); $('.close_adv_folders').remove(); $('.adv_folder_list').hide(); }; -var add_source_to_list = function(id, label) { +var add_source_to_list = function(id, label, includeSubfolders) { var close = $(globals.close_html); close.addClass('adv_remove_source'); close.attr('data-target', id); - var row = '
'+close.prop('outerHTML')+label; + var row = '
'+close.prop('outerHTML')+label; row += '
'; $('.adv_source_list').append(row); $('.adv_remove_source').off('click'); @@ -247,7 +266,7 @@ var get_adv_sources = function() { const source = this.className; const mailboxSource = source.split('_').slice(0, 2).join('_'); if (!sources.find(s => s.source.indexOf(mailboxSource) > -1)) { - sources.push({'source': source, 'label': $('a', $(this)).text()}); + sources.push({'source': source, 'label': $('a', $(this)).text(), subFolders: $(this).data('subfolders')}); } }); return sources; @@ -426,6 +445,8 @@ var send_requests = function(requests) { params.push({name: 'all_folders', value: true}); } else if (request['all_special_folders']) { params.push({name: 'all_special_folders', value: true}); + } else if (request['sub_folders']) { + params.push({name: 'include_subfolders', value: true}); } for (var i=0, len=request['terms'].length; i < len; i++) { @@ -490,7 +511,9 @@ var build_adv_search_requests = function(terms, sources, targets, times, other) config['all_folders'] = true; } else if (source.specialFolders) { config['all_special_folders'] = true; - } + } else if (source.subFolders) { + config['sub_folders'] = true; + } requests.push(config); } } diff --git a/modules/calendar/setup.php b/modules/calendar/setup.php index 31763196a9..07fde0ac9a 100644 --- a/modules/calendar/setup.php +++ b/modules/calendar/setup.php @@ -15,7 +15,7 @@ /*add_output('ajax_imap_message_content', 'vcalendar_add_output', true, 'calendar', 'filter_message_headers', 'after');*/ add_output('calendar', 'calendar_content', true, 'calendar', 'content_section_start', 'after'); add_output('calendar', 'add_cal_event_form', true, 'calendar', 'content_section_start', 'after'); -add_output('ajax_hm_folders', 'calendar_page_link', true, 'calendar', 'logout_menu_item', 'before'); +add_output('ajax_hm_folders', 'calendar_page_link', true, 'calendar', 'main_menu_content', 'before'); return array( 'allowed_pages' => array( diff --git a/modules/contacts/setup.php b/modules/contacts/setup.php index 1bffe16541..3053ef9534 100644 --- a/modules/contacts/setup.php +++ b/modules/contacts/setup.php @@ -16,7 +16,7 @@ add_output('contacts', 'contacts_content_end', true, 'contacts', 'contacts_list', 'after'); add_output('settings', 'contact_auto_collect_setting', true, 'contacts', 'max_google_contacts_number', 'after'); -add_output('ajax_hm_folders', 'contacts_page_link', true, 'contacts', 'logout_menu_item', 'before'); +add_output('ajax_hm_folders', 'contacts_page_link', true, 'contacts', 'main_menu_content', 'before'); add_handler('compose', 'load_contacts', true, 'contacts', 'load_user_data', 'after'); add_handler('compose', 'process_send_to_contact', true, 'contacts', 'save_user_data', 'before'); diff --git a/modules/core/functions.php b/modules/core/functions.php index bea403918b..1e224fff70 100644 --- a/modules/core/functions.php +++ b/modules/core/functions.php @@ -111,12 +111,7 @@ function format_data_sources($array, $output_mod) { foreach ($sources as $values) { $items = array(); foreach ($values as $name => $value) { - if ($name == 'callback') { - $items[] = $output_mod->html_safe($name).':'.$output_mod->html_safe($value); - } - else { - $items[] = $output_mod->html_safe($name).':"'.$output_mod->html_safe($value).'"'; - } + $items[] = $output_mod->html_safe($name).':"'.$output_mod->html_safe($value).'"'; } $objects[] = '{'.implode(',', $items).'}'; } @@ -255,6 +250,7 @@ function get_oauth2_data($config) { return [ 'gmail' => $config->get('gmail',[]), 'outlook' => $config->get('outlook',[]), + 'office365' => $config->get('office365',[]), ]; }} diff --git a/modules/core/js_modules/Hm_MessagesStore.js b/modules/core/js_modules/Hm_MessagesStore.js index 6851a76324..7e4f7df23a 100644 --- a/modules/core/js_modules/Hm_MessagesStore.js +++ b/modules/core/js_modules/Hm_MessagesStore.js @@ -70,7 +70,7 @@ class Hm_MessagesStore { */ markRowAsRead(uid) { const rows = Object.entries(this.rows); - const row = this.#getRowByUid(uid)?.value; + const row = this.getRowByUid(uid)?.value; if (row) { const htmlRow = $(row[1]['0']); @@ -96,7 +96,7 @@ class Hm_MessagesStore { */ getNextRowForMessage(uid) { const rows = Object.entries(this.rows); - const row = this.#getRowByUid(uid)?.index; + const row = this.getRowByUid(uid)?.index; if (row !== false) { const nextRow = rows[row + 1]; @@ -114,7 +114,7 @@ class Hm_MessagesStore { */ getPreviousRowForMessage(uid) { const rows = Object.entries(this.rows); - const row = this.#getRowByUid(uid)?.index; + const row = this.getRowByUid(uid)?.index; if (row) { const previousRow = rows[row - 1]; if (previousRow) { @@ -126,7 +126,7 @@ class Hm_MessagesStore { removeRow(uid) { const rows = Object.entries(this.rows); - const row = this.#getRowByUid(uid); + const row = this.getRowByUid(uid); if (row) { const newRows = rows.filter((_, i) => i !== row.index); this.rows = Object.fromEntries(newRows); @@ -153,14 +153,23 @@ class Hm_MessagesStore { #getRequestConfig() { let hook; - let serverId; - let folder; const config = []; if (this.path.startsWith('imap')) { hook = "ajax_imap_folder_display"; + const detail = Hm_Utils.parse_folder_path(this.path, 'imap'); - serverId = detail.server_id; - folder = detail.folder; + config.push({ name: "imap_server_id", value: detail.server_id }); + config.push({ name: "folder", value: detail.folder }); + + } else if (this.path.startsWith('feeds')) { + hook = "ajax_feed_combined"; + const serverId = this.path.split('_')[1]; + if (serverId) { + config.push({ name: "feed_server_ids", value: serverId }); + } + } else if (this.path.startsWith('github')) { + hook = "ajax_github_data"; + config.push({ name: "github_repo", value: this.path.split('_')[1] }); } else { switch (this.path) { case 'unread': @@ -170,6 +179,8 @@ class Hm_MessagesStore { hook = "ajax_imap_flagged"; break; case 'combined_inbox': + hook = "ajax_combined_message_list"; + break; case 'email': hook = "ajax_imap_combined_inbox"; break; @@ -183,15 +194,8 @@ class Hm_MessagesStore { } } - if (hook) { - config.push({ name: "hm_ajax_hook", value: hook }); - } - if (serverId) { - config.push({ name: "imap_server_id", value: serverId }); - } - if (folder) { - config.push({ name: "folder", value: folder }); - } + config.push({ name: "hm_ajax_hook", value: hook }); + return config; } @@ -217,7 +221,7 @@ class Hm_MessagesStore { * @param {String} uid * @returns {RowOutput|false} row - The row object if found, false otherwise */ - #getRowByUid(uid) { + getRowByUid(uid) { const rows = Object.entries(this.rows); const row = rows.find(([key, value]) => $(value['0']).attr('data-uid') == uid); diff --git a/modules/core/js_modules/route_handlers.js b/modules/core/js_modules/route_handlers.js index 77c3e445bb..782d9b9a24 100644 --- a/modules/core/js_modules/route_handlers.js +++ b/modules/core/js_modules/route_handlers.js @@ -21,15 +21,16 @@ function applyServersPageHandlers() { if (window.wpServersPageHandler) wpServersPageHandler(); } -function applySettingsPageHandlers() { - Hm_Utils.expand_core_settings(); +function applySettingsPageHandlers(routeParams, hash) { + if (hash) { + Hm_Utils.toggle_page_section(`.${hash}`); + } + $('.settings_subtitle').on("click", function() { return Hm_Utils.toggle_page_section($(this).data('target')); }); $('.reset_default_value_checkbox').on("click", reset_default_value_checkbox); $('.reset_default_value_select').on("click", reset_default_value_select); $('.reset_default_value_input').on("click", reset_default_value_input); $('.reset_default_timezone').on("click", reset_default_timezone); - - if (window.expand_feed_settings) expand_feed_settings(); if (window.smtpSettingsPageHandler) smtpSettingsPageHandler(); } @@ -53,7 +54,49 @@ function applyInfoPageHandlers() { if (window.github_repo_update) github_repo_update(); }, 100); + $('.config_map_page').on("click", function() { + var target = $(this).data('target'); + $('.'+target).toggle(); + }); + return () => { clearTimeout(timer); } -} \ No newline at end of file +} + +function applyMessaleListPageHandlers(routeParams) { + sortHandlerForMessageListAndSearchPage(); + Hm_Message_List.set_row_events(); + + $('.core_msg_control').on("click", function(e) { + e.preventDefault(); + Hm_Message_List.message_action($(this).data('action')); + }); + $('.toggle_link').on("click", function(e) { + e.preventDefault(); + Hm_Message_List.toggle_rows(); + }); + + if (routeParams.list_path === 'github_all') { + return applyGithubMessageListPageHandler(routeParams); + } + + // TODO: Refactor this handler to be more modular(applicable only for the imap list type) + return applyImapMessageListPageHandlers(routeParams); +} + +function applyMessagePageHandlers(routeParams) { + const path = routeParams.list_path.substr(0, 4); + + switch (path) { + case 'imap': + return applyImapMessageContentPageHandlers(routeParams); + case 'feed': + return applyFeedMessageContentPageHandlers(routeParams); + case 'gith': + return applyGithubMessageContentPageHandlers(routeParams); + + default: + break; + } +} diff --git a/modules/core/navigation/navbar.js b/modules/core/navigation/navbar.js index f158e96ef8..1a59c3820f 100644 --- a/modules/core/navigation/navbar.js +++ b/modules/core/navigation/navbar.js @@ -6,19 +6,19 @@ $(() => { }); const menuToggle = ` -