web_UI working - needs more tweaking
This commit is contained in:
355
email_server/server_web_ui/templates/settings.html
Normal file
355
email_server/server_web_ui/templates/settings.html
Normal file
@@ -0,0 +1,355 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Server Settings - Email Server{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.setting-section {
|
||||
border-left: 4px solid var(--bs-primary);
|
||||
padding-left: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
.setting-description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--bs-secondary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>
|
||||
<i class="bi bi-sliders me-2"></i>
|
||||
Server Settings
|
||||
</h2>
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-outline-warning" onclick="resetToDefaults()">
|
||||
<i class="bi bi-arrow-clockwise me-2"></i>
|
||||
Reset to Defaults
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-info" onclick="exportSettings()">
|
||||
<i class="bi bi-download me-2"></i>
|
||||
Export Config
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="{{ url_for('email.update_settings') }}">
|
||||
<!-- Server Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-server me-2"></i>
|
||||
Server Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">SMTP Port</label>
|
||||
<div class="setting-description">Port for SMTP connections (standard: 25, 587)</div>
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
name="Server.SMTP_PORT"
|
||||
value="{{ settings['Server']['SMTP_PORT'] }}"
|
||||
min="1" max="65535">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">SMTP TLS Port</label>
|
||||
<div class="setting-description">Port for SMTP over TLS connections (standard: 465)</div>
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
name="Server.SMTP_TLS_PORT"
|
||||
value="{{ settings['Server']['SMTP_TLS_PORT'] }}"
|
||||
min="1" max="65535">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Bind IP Address</label>
|
||||
<div class="setting-description">IP address to bind the server to (0.0.0.0 for all interfaces)</div>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="Server.BIND_IP"
|
||||
value="{{ settings['Server']['BIND_IP'] }}"
|
||||
pattern="^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Hostname</label>
|
||||
<div class="setting-description">Server hostname for HELO/EHLO commands</div>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
name="Server.hostname"
|
||||
value="{{ settings['Server']['hostname'] }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Database Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-database me-2"></i>
|
||||
Database Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Database URL</label>
|
||||
<div class="setting-description">SQLite database file path or connection string</div>
|
||||
<input type="text"
|
||||
class="form-control font-monospace"
|
||||
name="Database.DATABASE_URL"
|
||||
value="{{ settings['Database']['DATABASE_URL'] }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logging Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-journal-text me-2"></i>
|
||||
Logging Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Log Level</label>
|
||||
<div class="setting-description">Minimum log level to record</div>
|
||||
<select class="form-select" name="Logging.LOG_LEVEL">
|
||||
<option value="DEBUG" {{ 'selected' if settings['Logging']['LOG_LEVEL'] == 'DEBUG' else '' }}>DEBUG</option>
|
||||
<option value="INFO" {{ 'selected' if settings['Logging']['LOG_LEVEL'] == 'INFO' else '' }}>INFO</option>
|
||||
<option value="WARNING" {{ 'selected' if settings['Logging']['LOG_LEVEL'] == 'WARNING' else '' }}>WARNING</option>
|
||||
<option value="ERROR" {{ 'selected' if settings['Logging']['LOG_LEVEL'] == 'ERROR' else '' }}>ERROR</option>
|
||||
<option value="CRITICAL" {{ 'selected' if settings['Logging']['LOG_LEVEL'] == 'CRITICAL' else '' }}>CRITICAL</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Hide aiosmtpd INFO Messages</label>
|
||||
<div class="setting-description">Reduce verbose logging from aiosmtpd library</div>
|
||||
<select class="form-select" name="Logging.hide_info_aiosmtpd">
|
||||
<option value="true" {{ 'selected' if settings['Logging']['hide_info_aiosmtpd'] == 'true' else '' }}>Yes</option>
|
||||
<option value="false" {{ 'selected' if settings['Logging']['hide_info_aiosmtpd'] == 'false' else '' }}>No</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Relay Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-arrow-repeat me-2"></i>
|
||||
Email Relay Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Relay Timeout (seconds)</label>
|
||||
<div class="setting-description">Timeout for external SMTP connections when relaying emails</div>
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
name="Relay.RELAY_TIMEOUT"
|
||||
value="{{ settings['Relay']['RELAY_TIMEOUT'] }}"
|
||||
min="5" max="300">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TLS Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-shield-lock me-2"></i>
|
||||
TLS/SSL Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">TLS Certificate File</label>
|
||||
<div class="setting-description">Path to SSL certificate file (.crt or .pem)</div>
|
||||
<input type="text"
|
||||
class="form-control font-monospace"
|
||||
name="TLS.TLS_CERT_FILE"
|
||||
value="{{ settings['TLS']['TLS_CERT_FILE'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">TLS Private Key File</label>
|
||||
<div class="setting-description">Path to SSL private key file (.key or .pem)</div>
|
||||
<input type="text"
|
||||
class="form-control font-monospace"
|
||||
name="TLS.TLS_KEY_FILE"
|
||||
value="{{ settings['TLS']['TLS_KEY_FILE'] }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DKIM Settings -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-key me-2"></i>
|
||||
DKIM Configuration
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="setting-section">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">DKIM Key Size</label>
|
||||
<div class="setting-description">RSA key size for new DKIM keys (larger = more secure, slower)</div>
|
||||
<select class="form-select" name="DKIM.DKIM_KEY_SIZE">
|
||||
<option value="1024" {{ 'selected' if settings['DKIM']['DKIM_KEY_SIZE'] == '1024' else '' }}>1024 bits</option>
|
||||
<option value="2048" {{ 'selected' if settings['DKIM']['DKIM_KEY_SIZE'] == '2048' else '' }}>2048 bits (Recommended)</option>
|
||||
<option value="4096" {{ 'selected' if settings['DKIM']['DKIM_KEY_SIZE'] == '4096' else '' }}>4096 bits</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Save Button -->
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="alert alert-warning d-flex align-items-center mb-0">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<small>Server restart required after changing settings</small>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-save me-2"></i>
|
||||
Save Settings
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Reset Confirmation Modal -->
|
||||
<div class="modal fade" id="resetModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Reset Settings</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to reset all settings to their default values?</p>
|
||||
<p class="text-warning"><strong>Warning:</strong> This action cannot be undone.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-warning" onclick="confirmReset()">Reset Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
function resetToDefaults() {
|
||||
new bootstrap.Modal(document.getElementById('resetModal')).show();
|
||||
}
|
||||
|
||||
function confirmReset() {
|
||||
// This would need to be implemented as a separate endpoint
|
||||
// For now, just redirect to a reset URL
|
||||
window.location.href = '{{ url_for("email.settings") }}?reset=true';
|
||||
}
|
||||
|
||||
function exportSettings() {
|
||||
// Create a downloadable config file
|
||||
const settings = {};
|
||||
const formData = new FormData(document.querySelector('form'));
|
||||
|
||||
for (let [key, value] of formData.entries()) {
|
||||
const [section, setting] = key.split('.');
|
||||
if (!settings[section]) {
|
||||
settings[section] = {};
|
||||
}
|
||||
settings[section][setting] = value;
|
||||
}
|
||||
|
||||
const configText = generateConfigFile(settings);
|
||||
downloadFile('settings.ini', configText);
|
||||
}
|
||||
|
||||
function generateConfigFile(settings) {
|
||||
let config = '';
|
||||
for (const [section, values] of Object.entries(settings)) {
|
||||
config += `[${section}]\n`;
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
config += `${key} = ${value}\n`;
|
||||
}
|
||||
config += '\n';
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
function downloadFile(filename, content) {
|
||||
const element = document.createElement('a');
|
||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(content));
|
||||
element.setAttribute('download', filename);
|
||||
element.style.display = 'none';
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
document.body.removeChild(element);
|
||||
}
|
||||
|
||||
// Form validation
|
||||
document.querySelector('form').addEventListener('submit', function(e) {
|
||||
// Basic validation
|
||||
const ports = ['Server.SMTP_PORT', 'Server.SMTP_TLS_PORT'];
|
||||
for (const portField of ports) {
|
||||
const input = document.querySelector(`[name="${portField}"]`);
|
||||
const port = parseInt(input.value);
|
||||
if (port < 1 || port > 65535) {
|
||||
e.preventDefault();
|
||||
alert(`Invalid port number: ${port}. Must be between 1 and 65535.`);
|
||||
input.focus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if ports are different
|
||||
const smtpPort = document.querySelector('[name="Server.SMTP_PORT"]').value;
|
||||
const tlsPort = document.querySelector('[name="Server.SMTP_TLS_PORT"]').value;
|
||||
if (smtpPort === tlsPort) {
|
||||
e.preventDefault();
|
||||
alert('SMTP and TLS ports must be different.');
|
||||
return;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user