From e96468a98e4c74625ab2541ea6337bb5d5382c3d Mon Sep 17 00:00:00 2001 From: christer kahasha <62720246+christer77@users.noreply.github.com> Date: Thu, 14 Nov 2024 17:26:52 +0100 Subject: [PATCH 01/11] [FIX]Error Ocurred when attempting Microsoft's email oauth2 setup --- .env.example | 8 ++++++++ config/oauth2.php | 10 ++++++++++ modules/core/functions.php | 1 + modules/imap/functions.php | 3 +++ modules/imap/hm-imap.php | 1 - modules/nux/services.php | 4 ++-- tests/phpunit/modules/core/functions.php | 2 +- 7 files changed, 25 insertions(+), 4 deletions(-) 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/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/core/functions.php b/modules/core/functions.php index bea403918b..d4bc8f80ba 100644 --- a/modules/core/functions.php +++ b/modules/core/functions.php @@ -255,6 +255,7 @@ function get_oauth2_data($config) { return [ 'gmail' => $config->get('gmail',[]), 'outlook' => $config->get('outlook',[]), + 'office365' => $config->get('office365',[]), ]; }} diff --git a/modules/imap/functions.php b/modules/imap/functions.php index 60bb98cd11..d2f4f82575 100644 --- a/modules/imap/functions.php +++ b/modules/imap/functions.php @@ -853,6 +853,9 @@ function imap_refresh_oauth2_token($server, $config) { elseif ($server['server'] == 'imap-mail.outlook.com') { $details = $oauth2_data['outlook']; } + elseif ($server['server'] == 'imap-mail.office365.com') { + $details = $oauth2_data['office365']; + } if (!empty($details)) { $oauth2 = new Hm_Oauth2($details['client_id'], $details['client_secret'], $details['client_uri']); $result = $oauth2->refresh_token($details['refresh_uri'], $server['refresh_token']); diff --git a/modules/imap/hm-imap.php b/modules/imap/hm-imap.php index dba860da47..96977849ac 100644 --- a/modules/imap/hm-imap.php +++ b/modules/imap/hm-imap.php @@ -320,7 +320,6 @@ public function authenticate($username, $password) { } return $authed; } - /** * attempt starttls diff --git a/modules/nux/services.php b/modules/nux/services.php index 39c97d0d91..c17ca633db 100644 --- a/modules/nux/services.php +++ b/modules/nux/services.php @@ -62,9 +62,9 @@ 'name' => 'Office365', 'scope' => 'wl.imap', 'smtp' => array( - 'server' => 'outlook.office365.com', + 'server' => 'smtp.office365.com', 'port' => 587, - 'tls'=> 'yes' + 'tls'=> false ) )); diff --git a/tests/phpunit/modules/core/functions.php b/tests/phpunit/modules/core/functions.php index 818cf4018e..a358f3f1f4 100644 --- a/tests/phpunit/modules/core/functions.php +++ b/tests/phpunit/modules/core/functions.php @@ -84,7 +84,7 @@ public function test_is_email_address() { */ public function test_get_oauth2_data() { $mock_config = new Hm_Mock_Config(); - $this->assertEquals(array('gmail' => [],'outlook' => []), (get_oauth2_data($mock_config))); + $this->assertEquals(array('gmail' => [],'outlook' => [],'office365' => []), (get_oauth2_data($mock_config))); } /** * @preserveGlobalState disabled From 8f54cf70b9be07649ba3ce2026dc1ad034885e74 Mon Sep 17 00:00:00 2001 From: Steven Ngesera Date: Fri, 29 Nov 2024 13:44:00 +0300 Subject: [PATCH 02/11] refactor(sieve): fixed error all to undefined function get_sieve_host_from_services --- modules/sievefilters/hm-sieve.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sievefilters/hm-sieve.php b/modules/sievefilters/hm-sieve.php index c555941ff0..9c50f6a7b0 100644 --- a/modules/sievefilters/hm-sieve.php +++ b/modules/sievefilters/hm-sieve.php @@ -1,6 +1,8 @@ Date: Fri, 29 Nov 2024 22:41:52 +0100 Subject: [PATCH 03/11] refactor(workflow): pr title validation update (#1389) Adds 4 new types for pr scopes observed in cypht: - frontend - backend - frontend/backend - backend/frontend Furhtermore a comprehensive guide was added to the pull request template to make it easier for people to fullfill this requirement. adjust scopes according to requirements updated scopes according to agreement adjusted example in PR template --- .github/PULL_REQUEST_TEMPLATE.md | 13 +++++++++++++ .github/workflows/test.lint.pr.yml | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) 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..d76c3b1cb2 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 + unit + e2e other - cypht # Configure that a scope must always be provided. requireScope: true # Configure which scopes (newline delimited) are disallowed in PR From 80873a92a4941b004e4d38bbe6afbd1ff6bfff7d Mon Sep 17 00:00:00 2001 From: Merci Jacob <68013195+mercihabam@users.noreply.github.com> Date: Sat, 30 Nov 2024 11:59:38 +0200 Subject: [PATCH 04/11] refactor(backend): change the navigation modules load order in the final js bundle (#1394) --- scripts/config_gen.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/config_gen.php b/scripts/config_gen.php index 059acd8d2c..31c32c099e 100644 --- a/scripts/config_gen.php +++ b/scripts/config_gen.php @@ -176,6 +176,7 @@ function get_module_assignments($settings) { $js = ''; $css = ''; $assets = array(); + $core = false; $js_exclude_dependencies = explode(',', ($settings['js_exclude_deps'] ?? '')); $filters = array('allowed_output' => array(), 'allowed_get' => array(), 'allowed_cookie' => array(), 'allowed_post' => array(), 'allowed_server' => array(), 'allowed_pages' => array()); @@ -185,9 +186,8 @@ function get_module_assignments($settings) { foreach ($mods as $mod) { printf("scanning module %s ...\n", $mod); if ($mod === 'core') { - foreach (glob('modules/core/navigation/*.js') as $js_module) { - $js .= file_get_contents($js_module); - } + // We'll load the navigation modules last, after all other modules have been loaded, as they depend on the others. + $core = true; } $directoriesPattern = str_replace('/', DIRECTORY_SEPARATOR, "{*,*/*}"); foreach (glob('modules' . DIRECTORY_SEPARATOR . $mod . DIRECTORY_SEPARATOR . 'js_modules' . DIRECTORY_SEPARATOR . $directoriesPattern . '*.js', GLOB_BRACE) as $js_module) { @@ -213,6 +213,13 @@ function get_module_assignments($settings) { $assets[] = sprintf("modules/%s/assets", $mod); } } + + if ($core) { + foreach (glob('modules/core/navigation/*.js') as $js_module) { + $js .= file_get_contents($js_module); + } + } + // load pcss3t.cs only if one of: ['contacts','local_contacts','ldap_contacts','gmail_contacts'] is enabled if(count(array_intersect(['contacts','local_contacts','ldap_contacts','gmail_contacts'], $mods)) > 0){ if (is_readable(sprintf("third_party/contact-group.css", 'third_party'))) { From 3044bf822fbc9b06422af96a3cdd4a28bf9061a5 Mon Sep 17 00:00:00 2001 From: Merci Jacob <68013195+mercihabam@users.noreply.github.com> Date: Sat, 30 Nov 2024 16:24:37 +0200 Subject: [PATCH 05/11] feat(frontend/backend): allow searching for messages in all subfolders of a given folder (#1395) --- .../js_modules/route_handlers.js | 1 - modules/advanced_search/modules.php | 13 ++++--- modules/advanced_search/setup.php | 1 + modules/advanced_search/site.js | 35 +++++++++++++++---- 4 files changed, 39 insertions(+), 11 deletions(-) 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 6b08f1e093..eaf230250b 100644 --- a/modules/advanced_search/modules.php +++ b/modules/advanced_search/modules.php @@ -91,10 +91,15 @@ 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($imap, $flags, $params, $limit); - } elseif ($this->request->post['all_special_folders']) { + } elseif ($searchInSpecialFolders) { $msg_list = $this->special_folders_search($imap, $flags, $params, $limit); + } else if ($includeSubfolders) { + $msg_list = $this->all_folders_search($imap, $flags, $params, $limit, $this->folder); } else if (!$imap->select_mailbox($this->folder)) { return; } else { @@ -105,8 +110,8 @@ public function process() { $this->out('imap_server_ids', array($this->imap_id)); } - private function all_folders_search($imap, $flags, $params, $limit) { - $folders = $imap->get_mailbox_list(); + private function all_folders_search($imap, $flags, $params, $limit, $parent = '') { + $folders = $imap->get_mailbox_list(mailbox:$parent); $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); } } From 412b5adbd9ada0743d68ef788cbace54123153d5 Mon Sep 17 00:00:00 2001 From: Merci Jacob <68013195+mercihabam@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:38:38 +0200 Subject: [PATCH 06/11] fix(frontend): fix the sidebar content alignment and reorganize misplaced content. (#1397) --- modules/calendar/setup.php | 2 +- modules/contacts/setup.php | 2 +- modules/core/navigation/navbar.js | 2 +- modules/core/output_modules.php | 44 ++++++-------- modules/core/setup.php | 1 - modules/core/site.css | 59 +++++++++++-------- modules/history/setup.php | 2 +- modules/smtp/setup.php | 4 +- tests/phpunit/modules/core/output_modules.php | 25 +++----- .../modules/core/output_modules_debug.php | 4 +- tests/selenium/folder_list.py | 5 +- tests/selenium/pages.py | 2 +- 12 files changed, 70 insertions(+), 82 deletions(-) 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/navigation/navbar.js b/modules/core/navigation/navbar.js index f158e96ef8..0a39cbe90c 100644 --- a/modules/core/navigation/navbar.js +++ b/modules/core/navigation/navbar.js @@ -6,7 +6,7 @@ $(() => { }); const menuToggle = ` -