mirror of
https://github.com/itflow-org/itflow
synced 2026-07-26 18:27:14 +00:00
Add URI Tabs to mail settings keeps the tab active upon saving
This commit is contained in:
@@ -4,7 +4,7 @@ require_once "../config.php";
|
||||
require_once "../functions.php";
|
||||
require_once "../includes/check_login.php";
|
||||
|
||||
$settings_mail_path = '/admin/settings_mail.php';
|
||||
$settings_mail_path = '/admin/settings_mail.php?tab=oauth';
|
||||
|
||||
if (!isset($session_is_admin) || !$session_is_admin) {
|
||||
flashAlert("Admin access required.", 'error');
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
|
||||
|
||||
// Saves and tests return to the tab they were submitted from (see settings_mail.php)
|
||||
$mail_tabs = ['smtp', 'imap', 'oauth', 'from', 'tests'];
|
||||
$mail_tab_redirect = 'settings_mail.php';
|
||||
if (isset($_POST['tab']) && in_array($_POST['tab'], $mail_tabs, true)) {
|
||||
$mail_tab_redirect .= '?tab=' . $_POST['tab'];
|
||||
}
|
||||
|
||||
if (!defined('MICROSOFT_OAUTH_BASE_URL')) {
|
||||
define('MICROSOFT_OAUTH_BASE_URL', 'https://login.microsoftonline.com/');
|
||||
}
|
||||
@@ -30,12 +37,12 @@ if (isset($_POST['oauth_connect_microsoft_mail'])) {
|
||||
// the provider dropdowns live in different forms and are never posted here
|
||||
if ($config_imap_provider !== 'microsoft_oauth' && $config_smtp_provider !== 'microsoft_oauth') {
|
||||
flashAlert("Please set the SMTP or IMAP Provider to Microsoft 365 (OAuth) and save it before connecting.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_tenant_id)) {
|
||||
flashAlert("Missing Microsoft OAuth settings. Please provide Client ID, Client Secret, and Tenant ID first.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
if (defined('BASE_URL') && !empty(BASE_URL)) {
|
||||
@@ -99,7 +106,7 @@ if (isset($_POST['edit_mail_smtp_settings'])) {
|
||||
|
||||
flashAlert("SMTP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
|
||||
}
|
||||
|
||||
@@ -129,7 +136,7 @@ if (isset($_POST['edit_mail_imap_settings'])) {
|
||||
|
||||
flashAlert("IMAP Mail Settings updated");
|
||||
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
|
||||
}
|
||||
|
||||
@@ -154,7 +161,7 @@ if (isset($_POST['edit_mail_oauth_settings'])) {
|
||||
|
||||
logAudit("Settings", "Edit", "$session_name edited mail OAuth settings");
|
||||
flashAlert("Mail OAuth Settings updated");
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_from_settings'])) {
|
||||
@@ -179,7 +186,7 @@ if (isset($_POST['edit_mail_from_settings'])) {
|
||||
|
||||
flashAlert("Mail From Settings updated");
|
||||
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
|
||||
}
|
||||
|
||||
@@ -226,7 +233,7 @@ if (isset($_POST['test_email_smtp'])) {
|
||||
flashAlert("Failed to add test mail to queue", 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
|
||||
}
|
||||
|
||||
@@ -276,7 +283,7 @@ if (isset($_POST['test_email_imap'])) {
|
||||
|
||||
if (empty($host) || empty($port) || empty($username)) {
|
||||
flashAlert("<strong>IMAP connection failed:</strong> Missing host, port, or username.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$token_is_expired = function (?string $expires_at): bool {
|
||||
@@ -320,7 +327,7 @@ if (isset($_POST['test_email_imap'])) {
|
||||
} else {
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_refresh_token)) {
|
||||
flashAlert("<strong>IMAP OAuth failed:</strong> Missing OAuth client credentials or refresh token.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
if ($provider === 'google_oauth') {
|
||||
@@ -333,7 +340,7 @@ if (isset($_POST['test_email_imap'])) {
|
||||
} else {
|
||||
if (empty($config_mail_oauth_tenant_id)) {
|
||||
flashAlert("<strong>IMAP OAuth failed:</strong> Microsoft tenant ID is required.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$token_url = MICROSOFT_OAUTH_BASE_URL . rawurlencode($config_mail_oauth_tenant_id) . "/oauth2/v2.0/token";
|
||||
@@ -347,13 +354,13 @@ if (isset($_POST['test_email_imap'])) {
|
||||
|
||||
if (!$response['ok']) {
|
||||
flashAlert("<strong>IMAP OAuth failed:</strong> Could not refresh access token.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$json = json_decode($response['body'], true);
|
||||
if (!is_array($json) || empty($json['access_token'])) {
|
||||
flashAlert("<strong>IMAP OAuth failed:</strong> Token response did not include an access token.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$password = $json['access_token'];
|
||||
@@ -405,7 +412,7 @@ if (isset($_POST['test_email_imap'])) {
|
||||
flashAlert("<strong>IMAP connection failed.</strong> Check the host, port, encryption, and credentials.", 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
|
||||
@@ -417,7 +424,7 @@ if (isset($_POST['test_oauth_token_refresh'])) {
|
||||
|
||||
if ($provider !== 'google_oauth' && $provider !== 'microsoft_oauth') {
|
||||
flashAlert("OAuth token test failed: unsupported provider.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$oauth_client_id = escapeSql($config_mail_oauth_client_id ?? '');
|
||||
@@ -427,12 +434,12 @@ if (isset($_POST['test_oauth_token_refresh'])) {
|
||||
|
||||
if (empty($oauth_client_id) || empty($oauth_client_secret) || empty($oauth_refresh_token)) {
|
||||
flashAlert("OAuth token test failed: missing client ID, client secret, or refresh token.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
if ($provider === 'microsoft_oauth' && empty($oauth_tenant_id)) {
|
||||
flashAlert("OAuth token test failed: Microsoft tenant ID is required.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$token_url = 'https://oauth2.googleapis.com/token';
|
||||
@@ -461,14 +468,14 @@ if (isset($_POST['test_oauth_token_refresh'])) {
|
||||
if ($raw_body === false || $http_code < 200 || $http_code >= 300) {
|
||||
$err_msg = !empty($curl_err) ? $curl_err : "HTTP $http_code";
|
||||
flashAlert("OAuth token test failed: $err_msg", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$json = json_decode($raw_body, true);
|
||||
|
||||
if (!is_array($json) || empty($json['access_token'])) {
|
||||
flashAlert("OAuth token test failed: access token missing in provider response.", 'error');
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
$new_access_token = escapeSql($json['access_token']);
|
||||
@@ -490,5 +497,5 @@ if (isset($_POST['test_oauth_token_refresh'])) {
|
||||
logAudit("Settings", "Edit", "$session_name tested OAuth token refresh for $provider_label mail settings");
|
||||
|
||||
flashAlert("OAuth token refresh successful for $provider_label. Access token expires at $new_expires_at.");
|
||||
redirect();
|
||||
redirect($mail_tab_redirect);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,17 @@ $imap_on = !empty($config_imap_provider);
|
||||
$oauth_needed = in_array($config_smtp_provider, ['google_oauth', 'microsoft_oauth'], true)
|
||||
|| in_array($config_imap_provider, ['google_oauth', 'microsoft_oauth'], true);
|
||||
|
||||
// ---- Active tab -------------------------------------------------------------
|
||||
// The tab lives in the URL (?tab=imap) so it can be linked, bookmarked, survives a
|
||||
// reload, and lets the POST handlers send you back to the tab you saved from
|
||||
$mail_tabs = ['smtp', 'imap', 'oauth', 'from', 'tests'];
|
||||
$active_tab = isset($_GET['tab']) && in_array($_GET['tab'], $mail_tabs, true) ? $_GET['tab'] : 'smtp';
|
||||
|
||||
// A direct link to the OAuth tab reveals it even when no OAuth provider is selected yet
|
||||
if ($active_tab === 'oauth') {
|
||||
$oauth_needed = true;
|
||||
}
|
||||
|
||||
// ---- OAuth callback URI (for Entra App Registration) ------------------------
|
||||
if (defined('BASE_URL') && !empty(BASE_URL)) {
|
||||
$mail_oauth_callback_uri = rtrim((string) BASE_URL, '/') . '/admin/oauth_microsoft_mail_callback.php';
|
||||
@@ -63,27 +74,27 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
|
||||
<ul class="nav nav-tabs" id="mailTabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#tab-smtp" data-target="#tab-smtp">
|
||||
<a class="nav-link <?php if ($active_tab === 'smtp') { echo 'active'; } ?>" href="?tab=smtp" data-target="#tab-smtp">
|
||||
<i class="fas fa-fw fa-paper-plane mr-1"></i>Sending<?php echo renderMailStatusDot($smtp_on); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#tab-imap" data-target="#tab-imap">
|
||||
<a class="nav-link <?php if ($active_tab === 'imap') { echo 'active'; } ?>" href="?tab=imap" data-target="#tab-imap">
|
||||
<i class="fas fa-fw fa-inbox mr-1"></i>Receiving<?php echo renderMailStatusDot($imap_on); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" id="tabitem-oauth" style="<?php echo $oauth_needed ? '' : 'display:none;'; ?>">
|
||||
<a class="nav-link" href="#tab-oauth" data-target="#tab-oauth">
|
||||
<a class="nav-link <?php if ($active_tab === 'oauth') { echo 'active'; } ?>" href="?tab=oauth" data-target="#tab-oauth">
|
||||
<i class="fas fa-fw fa-key mr-1"></i>OAuth
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#tab-from" data-target="#tab-from">
|
||||
<a class="nav-link <?php if ($active_tab === 'from') { echo 'active'; } ?>" href="?tab=from" data-target="#tab-from">
|
||||
<i class="fas fa-fw fa-at mr-1"></i>From Addresses
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#tab-tests" data-target="#tab-tests">
|
||||
<a class="nav-link <?php if ($active_tab === 'tests') { echo 'active'; } ?>" href="?tab=tests" data-target="#tab-tests">
|
||||
<i class="fas fa-fw fa-vial mr-1"></i>Tests
|
||||
</a>
|
||||
</li>
|
||||
@@ -92,9 +103,10 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
<div class="tab-content pt-4">
|
||||
|
||||
<!-- ============================ SENDING / SMTP ============================ -->
|
||||
<div class="tab-pane fade show active" id="tab-smtp" role="tabpanel">
|
||||
<div class="tab-pane fade <?php if ($active_tab === 'smtp') { echo 'show active'; } ?>" id="tab-smtp" role="tabpanel">
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="smtp">
|
||||
|
||||
<div class="form-group">
|
||||
<label>SMTP Provider <small class="text-muted">— outbound</small></label>
|
||||
@@ -172,9 +184,10 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
</div>
|
||||
|
||||
<!-- ============================ RECEIVING / IMAP ============================ -->
|
||||
<div class="tab-pane fade" id="tab-imap" role="tabpanel">
|
||||
<div class="tab-pane fade <?php if ($active_tab === 'imap') { echo 'show active'; } ?>" id="tab-imap" role="tabpanel">
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="imap">
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP Provider <small class="text-muted">— inbound ticket inbox</small></label>
|
||||
@@ -252,9 +265,10 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
</div>
|
||||
|
||||
<!-- ============================ OAUTH ============================ -->
|
||||
<div class="tab-pane fade" id="tab-oauth" role="tabpanel">
|
||||
<div class="tab-pane fade <?php if ($active_tab === 'oauth') { echo 'show active'; } ?>" id="tab-oauth" role="tabpanel">
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="oauth">
|
||||
|
||||
<div class="alert alert-secondary" id="oauth_hint">
|
||||
<i class="fas fa-fw fa-info-circle mr-2"></i>These credentials are shared by any Sending or Receiving provider set to Google / Microsoft OAuth.
|
||||
@@ -318,9 +332,10 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
</div>
|
||||
|
||||
<!-- ============================ FROM ADDRESSES ============================ -->
|
||||
<div class="tab-pane fade" id="tab-from" role="tabpanel">
|
||||
<div class="tab-pane fade <?php if ($active_tab === 'from') { echo 'show active'; } ?>" id="tab-from" role="tabpanel">
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="from">
|
||||
|
||||
<p class="text-muted">Each From address must be allowed to send on behalf of the SMTP user.</p>
|
||||
|
||||
@@ -361,7 +376,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
</div>
|
||||
|
||||
<!-- ============================ TESTS ============================ -->
|
||||
<div class="tab-pane fade" id="tab-tests" role="tabpanel">
|
||||
<div class="tab-pane fade <?php if ($active_tab === 'tests') { echo 'show active'; } ?>" id="tab-tests" role="tabpanel">
|
||||
|
||||
<?php if (!$send_ready && !$imap_ready && !$oauth_has_required_fields) { ?>
|
||||
<div class="alert alert-secondary mb-0">
|
||||
@@ -374,6 +389,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
<h6 class="text-bold"><i class="fas fa-fw fa-paper-plane mr-2"></i>Send a Test Email</h6>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="tests">
|
||||
<div class="input-group">
|
||||
<select class="form-control select2" name="test_email" required>
|
||||
<option value="">- Select a From address -</option>
|
||||
@@ -396,6 +412,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
<h6 class="text-bold"><i class="fas fa-fw fa-plug mr-2"></i>Test IMAP Connection</h6>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="tests">
|
||||
<button type="submit" name="test_email_imap" class="btn btn-success"><i class="fas fa-fw fa-inbox mr-2"></i>Test IMAP</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -406,6 +423,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
<h6 class="text-bold"><i class="fas fa-fw fa-sync-alt mr-2"></i>Test OAuth Token Refresh</h6>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<input type="hidden" name="tab" value="tests">
|
||||
<input type="hidden" name="oauth_provider" value="<?php echo htmlspecialchars($oauth_provider_for_test); ?>">
|
||||
<p class="text-muted mb-2">Validates the refresh token and stores a new access token for <?php echo $oauth_provider_for_test === 'microsoft_oauth' ? 'Microsoft 365' : 'Google Workspace'; ?>.</p>
|
||||
<button type="submit" name="test_oauth_token_refresh" class="btn btn-success"><i class="fas fa-fw fa-sync-alt mr-2"></i>Test OAuth Token Refresh</button>
|
||||
@@ -434,11 +452,22 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
});
|
||||
|
||||
// ---- Self-contained tab controller (no dependency on the BS tab plugin) ----
|
||||
// Set when the page was opened directly on the OAuth tab - stops the provider pass hiding it
|
||||
const forcedOauthTab = <?php echo $active_tab === 'oauth' ? 'true' : 'false'; ?>;
|
||||
const navLinks = Array.from(document.querySelectorAll('#mailTabs .nav-link'));
|
||||
const panes = ['tab-smtp', 'tab-imap', 'tab-oauth', 'tab-from', 'tab-tests']
|
||||
.map(id => document.getElementById(id)).filter(Boolean);
|
||||
|
||||
// Server rendered the initial tab; keep the URL honest as the user clicks around
|
||||
function syncTabUrl(target) {
|
||||
const tab = target.replace('#tab-', '');
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('tab', tab);
|
||||
history.replaceState(null, '', url);
|
||||
}
|
||||
|
||||
function activateTab(target) {
|
||||
syncTabUrl(target);
|
||||
navLinks.forEach(l => l.classList.toggle('active', l.getAttribute('data-target') === target));
|
||||
panes.forEach(p => {
|
||||
const on = ('#' + p.id) === target;
|
||||
@@ -508,7 +537,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
const anyOauth = isOauth(sv) || isOauth(iv);
|
||||
const anyMs = sv === 'microsoft_oauth' || iv === 'microsoft_oauth';
|
||||
|
||||
show(oauthTabItem, anyOauth);
|
||||
show(oauthTabItem, anyOauth || forcedOauthTab);
|
||||
toggle(tenantRow, anyMs);
|
||||
toggle(msConnect, anyMs);
|
||||
if (oauthClientId) oauthClientId.placeholder = anyMs
|
||||
@@ -520,7 +549,7 @@ $imap_ready = $imap_standard_ready || $imap_oauth_ready;
|
||||
: anyOauth ? '<i class="fas fa-fw fa-info-circle mr-2"></i>Google Workspace: Client ID / Secret from Google Cloud; refresh token obtained via the consent flow.'
|
||||
: '<i class="fas fa-fw fa-info-circle mr-2"></i>These credentials are shared by any Sending or Receiving provider set to Google / Microsoft OAuth.';
|
||||
|
||||
if (!anyOauth) {
|
||||
if (!anyOauth && !forcedOauthTab) {
|
||||
const oauthLink = document.querySelector('#mailTabs .nav-link[data-target="#tab-oauth"]');
|
||||
if (oauthLink && oauthLink.classList.contains('active')) activateTab('#tab-smtp');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user