123 lines
4.4 KiB
JavaScript
123 lines
4.4 KiB
JavaScript
// Copyright © 2026 Olaf Kolkman
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
const setupForm = document.querySelector('#setup-form');
|
|
const testMailButton = document.querySelector('#test-mail-button');
|
|
const completeSetupButton = document.querySelector('#complete-setup-button');
|
|
const setupStatus = document.querySelector('#setup-status');
|
|
const setupTimer = document.querySelector('#setup-timer');
|
|
let nextAllowedAt = null;
|
|
let timerHandle = null;
|
|
|
|
function updateTimer() {
|
|
if (timerHandle) window.clearTimeout(timerHandle);
|
|
if (!nextAllowedAt) {
|
|
setupTimer.textContent = '';
|
|
testMailButton.disabled = !setupForm.dataset.saved;
|
|
return;
|
|
}
|
|
const seconds = Math.max(0, Math.ceil((nextAllowedAt - Date.now()) / 1000));
|
|
if (seconds === 0) {
|
|
nextAllowedAt = null;
|
|
updateTimer();
|
|
return;
|
|
}
|
|
const minutes = Math.floor(seconds / 60);
|
|
setupTimer.textContent = `Next test mail available in ${minutes ? `${minutes}m ` : ''}${seconds % 60}s.`;
|
|
testMailButton.disabled = true;
|
|
timerHandle = window.setTimeout(updateTimer, 1000);
|
|
}
|
|
|
|
function applyStatus(result) {
|
|
setupForm.dataset.saved = result.pending ? 'true' : '';
|
|
testMailButton.disabled = !result.pending;
|
|
const smtpDefaults = result.smtp_defaults || {};
|
|
for (const [name, value] of Object.entries(smtpDefaults)) {
|
|
const field = setupForm.elements[name];
|
|
if (!field || field.value || field.type === 'checkbox') continue;
|
|
field.value = value;
|
|
}
|
|
if (typeof smtpDefaults.smtp_use_tls === 'boolean') {
|
|
setupForm.elements.smtp_use_tls.checked = smtpDefaults.smtp_use_tls;
|
|
}
|
|
if (result.next_allowed_at) nextAllowedAt = Date.parse(result.next_allowed_at);
|
|
updateTimer();
|
|
}
|
|
|
|
async function loadSetupStatus() {
|
|
const response = await fetch('/api/setup/status');
|
|
if (!response.ok) return;
|
|
applyStatus(await response.json());
|
|
}
|
|
|
|
setupForm.addEventListener('submit', async (event) => {
|
|
event.preventDefault();
|
|
const form = event.currentTarget;
|
|
const values = Object.fromEntries(new FormData(form));
|
|
values.smtp_port = Number(values.smtp_port);
|
|
values.smtp_use_tls = form.elements.smtp_use_tls.checked;
|
|
try {
|
|
const response = await fetch('/api/setup/configuration', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify(values),
|
|
});
|
|
const result = await response.json();
|
|
if (!response.ok) throw new Error(result.detail || 'Setup failed');
|
|
setupStatus.textContent = result.message;
|
|
setupStatus.style.color = '#94e2d5';
|
|
form.dataset.saved = 'true';
|
|
testMailButton.disabled = false;
|
|
} catch (error) {
|
|
setupStatus.textContent = error.message;
|
|
setupStatus.style.color = '#f38ba8';
|
|
}
|
|
});
|
|
|
|
testMailButton.addEventListener('click', async () => {
|
|
testMailButton.disabled = true;
|
|
try {
|
|
const response = await fetch('/api/setup/test-mail', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({email: setupForm.elements.email.value}),
|
|
});
|
|
const result = await response.json();
|
|
if (!response.ok) {
|
|
if (response.status === 429 && response.headers.get('Retry-After')) {
|
|
nextAllowedAt = Date.now() + Number(response.headers.get('Retry-After')) * 1000;
|
|
updateTimer();
|
|
}
|
|
throw new Error(result.detail || 'Test mail failed');
|
|
}
|
|
setupStatus.textContent = `${result.message} ${result.sends_remaining} sends remaining.`;
|
|
setupStatus.style.color = '#94e2d5';
|
|
if (result.next_allowed_at) nextAllowedAt = Date.parse(result.next_allowed_at);
|
|
updateTimer();
|
|
completeSetupButton.hidden = false;
|
|
} catch (error) {
|
|
setupStatus.textContent = error.message;
|
|
setupStatus.style.color = '#f38ba8';
|
|
if (!nextAllowedAt) testMailButton.disabled = false;
|
|
}
|
|
});
|
|
|
|
completeSetupButton.addEventListener('click', async () => {
|
|
const response = await fetch('/api/setup/complete', {method: 'POST'});
|
|
const result = await response.json();
|
|
if (!response.ok) {
|
|
setupStatus.textContent = result.detail || 'Could not complete setup.';
|
|
setupStatus.style.color = '#f38ba8';
|
|
return;
|
|
}
|
|
setupStatus.style.color = '#94e2d5';
|
|
setupStatus.textContent = '';
|
|
setupStatus.append(document.createTextNode(`${result.message} `));
|
|
const homeLink = document.createElement('a');
|
|
homeLink.href = '/';
|
|
homeLink.textContent = 'Home';
|
|
setupStatus.append(homeLink);
|
|
setupForm.replaceChildren(setupStatus);
|
|
});
|
|
|
|
loadSetupStatus(); |