Files
openpanel/templates/tabler/settings/general.html
2024-10-25 01:44:26 +02:00

586 lines
26 KiB
HTML

{% extends 'base.html' %}
{% block content %}
<form method="post" id="general_form" action="">
<!-- Page header -->
<div class="page-header mt-0 d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<!-- Page pre-title -->
<div class="page-pretitle">
Settings
</div>
<h2 class="page-title">
General
</h2>
</div>
<!-- Page title actions -->
<div class="col-auto ms-auto d-print-none">
<div class="btn-list">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</div>
</div>
</div>
</div>
<div id="toastContainer" class="position-static"></div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="row row-deck row-cards">
<div class="col-lg-12">
<span id="public_ip_for_js" style="display:none;">{{ public_ip }}</span>
<div class="card">
<div class="card-header">
<h4 class="card-title">Global Settings</h4>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">Both panels are accessible on:</label>
<div class="row form-selectgroup form-selectgroup-boxes d-flex">
<div class="col-lg-6">
<label class="form-selectgroup-item flex-fill">
<input type="radio" name="form-domain-name-is-set" id="customDomain" value="domain_name" class="form-selectgroup-input" {% if config_data['DEFAULT']['force_domain'] %}checked=""{% endif %}>
<div class="form-selectgroup-label d-flex align-items-center p-3">
<div class="me-3">
<span class="form-selectgroup-check"></span>
</div>
<div>
<div class="font-weight-medium">Custom Domain Name <span
class="form-help"
data-bs-toggle="popover"
data-bs-placement="top"
data-bs-content="<p class='mb-0'>Make sure that the domain is set as server hostname and is a <a target='_blank' id='linkWikipediaFQDN' href='https://en.wikipedia.org/wiki/FQDN'>FQDN</a>.</p>"
data-bs-html="true"
>?</span></div>
<input type="text" class="form-control" name="force_domain" placeholder="{{ server_hostname }}" value="{% if 'force_domain' in config_data['DEFAULT'] and config_data['DEFAULT']['force_domain'] %}{{ config_data['DEFAULT']['force_domain'] }}{% else %}{{ server_hostname }}{% endif %}">
</div>
</div>
</label>
</div>
<div class="col-lg-6">
<label class="form-selectgroup-item flex-fill">
<input type="radio" name="form-domain-name-not-set-use-shared-ip" value="ip_address" class="form-selectgroup-input" id="serverIPAddress" {% if not config_data['DEFAULT']['force_domain'] %}checked=""{% endif %}>
<div class="form-selectgroup-label d-flex align-items-center p-3">
<div class="me-3">
<span class="form-selectgroup-check"></span>
</div>
<div>
<div class="font-weight-medium">Server IP address</div>
<input type="text" class="form-control" name="force_domain_is_empty" placeholder="Input placeholder" value="{{public_ip}}" disabled="">
</div>
</div>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">AdminPanel Settings</h4>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">AdminPanel port:</label>
<div class="input-group input-group-flat">
<span class="input-group-text" id="2087_prepend">
{% if force_domain %}
https://{{ config_data['DEFAULT']['force_domain'] }}:
{% else %}
http://{{ public_ip }}:
{% endif %}
</span>
<input type="number" class="form-control ps-0" name="2087_port" value="2087" autocomplete="off" min="1000" max="33000" disabled>
</div>
</div>
<div class="mb-3">
<label class="form-label">Force SSL:</label>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="ssl_checkbox" {%if config_data['DEFAULT']['ssl'] == 'yes' %}checked=""{% endif %} name="ssl">
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">OpenPanel Settings</h4>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">OpenPanel port:</label>
<div class="input-group input-group-flat">
<span class="input-group-text" id="2083_prepend">
{% if force_domain %}
https://{{ config_data['DEFAULT']['force_domain'] }}:
{% else %}
http://{{ public_ip }}:
{% endif %}
</span>
<input type="number" class="form-control ps-0" name="2083_port" autocomplete="off" value="{{ config_data['DEFAULT']['port'] }}" min="1000" max="33000">
</div>
</div>
<div class="mb-3">
<label class="form-label">OpenPanel is also available on:</label>
<div class="input-group input-group-flat">
<span class="input-group-text" id="2083_prepend">https://customer-domain.com/</span>
<input type="text" class="form-control ps-0" name="openpanel_proxy" autocomplete="off" placeholder="openpanel" value="{% if 'openpanel_proxy' in config_data['DEFAULT'] and config_data['DEFAULT']['openpanel_proxy'] %}{{ config_data['DEFAULT']['openpanel_proxy'] }}{% endif %}">
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Update preferences</h4>
<div id="update_is_available" style="display:none;" class="ribbon bg-primary">Update is available!</div>
</div>
<div class="card-body">
<div class="mb-3">
<div class="row d-flex">
<div class="col-lg-6">
<p>Local OpenPanel version: <b id="local_version">{{panel_version}}</b></p>
<p>Latest OpenPanel version: <b id="latest_version">{{panel_version}}</b><a href="https://openpanel.com/docs/changelog/{{panel_version}}" target="_blank" style="display:none;" id="view_changelog">View Changelog</a></p>
</div>
<div class="col-lg-6">
<a href="#" data-bs-toggle="modal" id="update_now_button" data-bs-target="#update_now_modal" style="display:none;" class="btn"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-refresh"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4" /><path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4" /></svg> Update now
</a>
</div>
</div>
</div>
<div class="mb-3">
<div class="row form-selectgroup form-selectgroup-boxes d-flex">
<div class="col-lg-6">
<label class="form-selectgroup-item flex-fill">
<input type="checkbox" name="autoupdate" value="on" class="form-selectgroup-input" {%if config_data['PANEL']['autoupdate'] == 'on' %}checked=""{% endif %}>
<div class="form-selectgroup-label d-flex align-items-center p-3">
<div class="me-3">
<span class="form-selectgroup-check"></span>
</div>
<div class="form-selectgroup-label-content d-flex align-items-center">
<div>
<div class="font-weight-medium">Auto Updates</div>
<div class="text-secondary">Automatically update to all <b>major</b> versions of OpenPanel <a href="https://openpanel.com/docs/admin/intro/#enable-automatic-updates" target="_blank">(&nbsp;<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 15l6 -6" /><path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" /><path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" /></svg> Docs)</a></div>
</div>
</div>
</div>
</label>
</div>
<div class="col-lg-6">
<label class="form-selectgroup-item flex-fill">
<input type="checkbox" name="autopatch" value="on" class="form-selectgroup-input" {%if config_data['PANEL']['autopatch'] == 'on'%}checked=""{% endif %}>
<div class="form-selectgroup-label d-flex align-items-center p-3">
<div class="me-3">
<span class="form-selectgroup-check"></span>
</div>
<div class="form-selectgroup-label-content d-flex align-items-center">
<div>
<div class="font-weight-medium">Auto Patches</div>
<div class="text-secondary">Automatically update to all <b>minor</b> versions of OpenPanel <a href="https://openpanel.com/docs/admin/intro/#disable-automatic-updates" target="_blank">(&nbsp;<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-link" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 15l6 -6" /><path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" /><path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" /></svg> Docs)</a></div>
</div>
</div>
</div>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
<!-- run update process now - confirm modal -->
<div class="modal modal-blur fade" id="update_now_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-sm modal-dialog-centered" role="document">
<div class="modal-content">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="modal-status bg-success"></div>
<div class="modal-body text-center py-4">
<!-- Modal content goes here -->
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-green icon-lg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M9 12l2 2l4 -4" /></svg>
<h3>Confirm update to OpenPanel <span id="version_in_modal"></span></h3>
<div class="text-secondary">The update process for OpenPanel will last approximately 5 minutes. During this period, access to both OpenPanel and OpenAdmin interfaces will be temporarily unavailable. However, user websites will remain operational without any interruption.</div>
<div class="mt-2 text-secondary">Please confirm to start the update now.
</div>
</div>
<div class="modal-footer">
<div class="w-100">
<div class="row">
<div class="col"><a href="#" class="btn w-100" data-bs-dismiss="modal">
Cancel update
</a></div>
<div class="col"><button id="start_update_btn" class="btn btn-success w-100">
Start update process
</button></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!--script src="{{ url_for('static', filename='pages/general_settings.js') }}" defer></script-->
<script>
document.addEventListener("DOMContentLoaded", function() {
// Get the radio buttons and port input fields
var domainRadio = document.querySelector('input[name="form-domain-name-is-set"]');
var ipRadio = document.querySelector('input[name="form-domain-name-not-set-use-shared-ip"]');
var adminPortInput = document.querySelector('input[name="2087_port"]');
var adminPortPrepend = document.getElementById('2087_prepend');
var openPortInput = document.querySelector('input[name="2083_port"]');
var openPortPrepend = document.getElementById('2083_prepend');
var sslCheckbox = document.getElementById('ssl_checkbox');
// Add event listener for Force SSL checkbox
sslCheckbox.addEventListener("change", function () {
// Update the protocol in the prepend text based on the checkbox state
updatePrependText();
});
// Add event listeners for radio buttons
domainRadio.addEventListener("change", function() {
if (domainRadio.checked) {
// Update the prepend text for AdminPanel and OpenPanel ports
updatePrependText();
}
});
ipRadio.addEventListener("change", function() {
if (ipRadio.checked) {
// Update the prepend text for AdminPanel and OpenPanel ports
var protocol = sslCheckbox.checked ? "https://" : "http://";
adminPortPrepend.textContent = protocol + "{{ public_ip }}:";
openPortPrepend.textContent = protocol + "{{ public_ip }}:";
}
});
// Add event listener for custom domain input
var domainInput = document.querySelector('input[name="force_domain"]');
domainInput.addEventListener("input", function() {
// If the user starts typing, check domainRadio and uncheck ipRadio
if (!domainRadio.checked) {
domainRadio.checked = true;
ipRadio.checked = false;
// Update the prepend text for AdminPanel and OpenPanel ports
updatePrependText();
}
// If domainInput is empty, switch to ipRadio
if (domainInput.value.trim() === "") {
domainRadio.checked = false;
ipRadio.checked = true;
// Update the prepend text for AdminPanel and OpenPanel ports
updatePrependText();
} else {
// Update the prepend text for AdminPanel and OpenPanel ports based on the custom domain input
updatePrependText();
}
});
// Function to update prepend text for AdminPanel and OpenPanel ports
function updatePrependText() {
var protocol = sslCheckbox.checked ? "https://" : "http://";
// Retrieve the public IP address text from the element
var publicIp = document.getElementById('public_ip_for_js').textContent;
if (ipRadio.checked) {
adminPortPrepend.textContent = protocol + publicIp + ":";
openPortPrepend.textContent = protocol + publicIp + ":";
}
if (domainRadio.checked) {
var customDomain = domainInput.value.trim();
adminPortPrepend.textContent = protocol + customDomain + ":";
openPortPrepend.textContent = protocol + customDomain + ":";
}
}
// UPDATE BUTTON
$('#start_update_btn').click(function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '/settings/general/update_now',
success: function(response) {
$('#update_now_modal .modal-body').html('<div class="text-center py-4">' + response.message + '</div>');
$('#update_now_modal .modal-footer').html('');
},
error: function(error) {
$('#update_now_modal .modal-body').html('<div class="text-danger">Failed to start the update process. Please try again later.</div>');
}
});
});
});
document.addEventListener('DOMContentLoaded', function () {
const customDomainCheckbox = document.getElementById('customDomain');
const serverIPAddressCheckbox = document.getElementById('serverIPAddress');
customDomainCheckbox.addEventListener('change', function () {
serverIPAddressCheckbox.checked = false;
});
serverIPAddressCheckbox.addEventListener('change', function () {
customDomainCheckbox.checked = false;
});
});
document.addEventListener("DOMContentLoaded", function () {
var form = document.getElementById('general_form');
var toastContainer = document.createElement('div');
toastContainer.classList.add('toast-container', 'position-fixed', 'bottom-0', 'end-0', 'p-3');
document.body.appendChild(toastContainer);
form.addEventListener('submit', function (event) {
event.preventDefault(); // Prevent the default form submission
// Perform AJAX submission
var formData = new FormData(form);
fetch(form.action, {
method: form.method,
body: formData,
})
.then(response => response.json())
.then(data => {
// Check for success messages
if (data.success_messages && data.success_messages.length > 0) {
// Display success toasts
displayToasts(data.success_messages, 'success');
// Check for the specific success message
if (data.success_messages.some(msg => msg.includes("Panels are accessible on IP address"))) {
// Display a new toast for redirection message
var portValue = document.querySelector('input[name="2087_port"]').value;
var public_ip = "{{ public_ip }}";
// Construct the redirect URL
var redirectURL = `http://${public_ip}:${portValue}/settings/general`;
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
// Redirect after 5 seconds
setTimeout(function() {
// Redirect the user
window.location.href = redirectURL;
}, 5000);
} else if (data.success_messages.some(msg => msg.includes("is set as the domain name for both panels"))) {
// Redirect for the new success message condition
var portValue = document.querySelector('input[name="2087_port"]').value;
var server_hostname = "{{ server_hostname }}";
// Construct the redirect URL
var redirectURL = `https://${server_hostname}:${portValue}/settings/general`;
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
// Redirect after 5 seconds
setTimeout(function() {
// Redirect the user
window.location.href = redirectURL;
}, 5000);
}
}
// Check for error messages
if (data.error_messages && data.error_messages.length > 0) {
displayToasts(data.error_messages, 'error');
// Check for the specific error message when domain is set and already has a valid ssl
if (data.error_messages.some(msg => msg.includes("Restarting the panel services to apply the newly generated SSL and force domain"))) {
// Handle the error condition
var portValue = document.querySelector('input[name="2087_port"]').value;
var server_hostname = "{{ server_hostname }}";
// Construct the redirect URL
var redirectURL = `https://${server_hostname}:${portValue}/settings/general`;
displayToasts([`Redirecting to: ${redirectURL}`], 'info');
// Redirect after 5 seconds
setTimeout(function() {
// Redirect the user
window.location.href = redirectURL;
}, 5000);
}
}
})
.catch(error => console.error('Error:', error));
});
// Function to display Bootstrap Toasts
function displayToasts(messages, type) {
// Combine multiple messages into a single string
var combinedMessage = messages.join('<br>');
var toastDiv = document.createElement('div');
toastDiv.classList.add('toast');
toastDiv.setAttribute('role', 'alert');
toastDiv.setAttribute('aria-live', 'assertive');
toastDiv.setAttribute('aria-atomic', 'true');
toastDiv.innerHTML = `
<div class="toast-header">
<!-- Add SVG icons based on the message type -->
${type === 'success' ? successIcon : type === 'info' ? infoIcon : dangerIcon}
<strong class="me-auto">${type.charAt(0).toUpperCase() + type.slice(1)}</strong>
<small>${new Date().toLocaleTimeString()}</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
${combinedMessage}
</div>
`;
toastContainer.appendChild(toastDiv);
// Use Bootstrap Toast to show the toast
var toast = new bootstrap.Toast(toastDiv);
toast.show();
}
// SVG icons for success and danger
var successIcon = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="green" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 12l5 5l10 -10"></path></svg>
`;
var infoIcon = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="blue" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 9h.01"></path><path d="M11 12h1v4h1"></path></svg>
`;
var dangerIcon = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon alert-icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="red" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 8v4"></path><path d="M12 16h.01"></path></svg>
`;
});
// CHEKC FOR UPDATES
const versionUrl = 'https://update.openpanel.com/';
fetch(versionUrl)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(latestVersion => {
const localVersion = document.getElementById('local_version').textContent;
document.getElementById('latest_version').textContent = latestVersion;
document.getElementById('version_in_modal').textContent = latestVersion;
const changelogLink = document.getElementById('view_changelog');
changelogLink.href = `https://openpanel.com/docs/changelog/${latestVersion}`;
if (isVersionNewer(latestVersion, localVersion)) {
document.getElementById('update_is_available').style.display = 'flex';
document.getElementById('update_now_button').style.display = 'flex';
document.getElementById('view_changelog').style.display = 'inline';
}
})
.catch(error => {
console.error('There was a problem with the fetch operation:', error);
});
function isVersionNewer(version1, version2) {
const v1 = version1.split('.').map(Number);
const v2 = version2.split('.').map(Number);
for (let i = 0; i < Math.max(v1.length, v2.length); i++) {
const num1 = v1[i] || 0;
const num2 = v2[i] || 0;
if (num1 > num2) return true;
if (num1 < num2) return false;
}
return false;
}
</script>
{% endblock %}