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 = `
-