Files
Olaf 102d8e533c
Build LinkLog Development Image / development-image (push) Successful in 11s
Initial config with email service test
2026-08-25 23:23:28 +02:00

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();