refactoring

This commit is contained in:
2026-09-02 08:38:03 +02:00
parent 649ff0d7c5
commit 38f255c1a4
48 changed files with 6998 additions and 5577 deletions
+130
View File
@@ -0,0 +1,130 @@
/* Mail and password-reset administration view. */
class MailAdmin {
/**
* goal : Connect mail settings, test delivery and TLS controls to the API.
* pre : The mail administration form exists in the document.
* post : Save, test and TLS-change events are handled by this controller.
* result : A directly usable mail administration controller.
*/
constructor(api, translate) {
this.api = api;
this.translate = translate;
this.form = document.getElementById("mail-settings-form");
this.status = document.getElementById("mail-settings-status");
this.testButton = document.getElementById("mail-test-button");
this.tls = document.getElementById("mail-smtp-tls");
this.acceptUntrusted = document.getElementById(
"mail-smtp-accept-untrusted-certificates");
this.form.addEventListener("submit", (event) => this.#save(event));
this.testButton.addEventListener("click", () => this.#test());
this.tls.addEventListener("change", () => this.#syncTlsControls());
}
/**
* goal : Load stored mail settings and initialize the test recipient.
* pre : The current session has administrator permission.
* post : All form controls represent the stored server configuration.
* result : A promise that resolves after the form has been initialized.
*/
async load(currentUserEmail = "") {
const settings = await this.api("/api/admin/mail-settings");
document.getElementById("mail-public-url").value =
settings.publicUrl || window.location.origin;
document.getElementById("mail-smtp-host").value = settings.smtpHost || "";
document.getElementById("mail-smtp-port").value = settings.smtpPort || "587";
document.getElementById("mail-smtp-from").value = settings.smtpFrom || "";
document.getElementById("mail-smtp-user").value = settings.smtpUser || "";
document.getElementById("mail-smtp-password").value = "";
this.tls.checked = settings.smtpTls !== false;
this.acceptUntrusted.checked = settings.smtpAcceptUntrustedCertificates === true;
document.getElementById("mail-reset-limit").value = settings.resetLimit || "2";
document.getElementById("mail-test-recipient").value = currentUserEmail;
document.getElementById("mail-password-help").textContent = settings.hasPassword
? this.translate(
"smtp-password-kept", "A password is stored; leave empty to keep it.")
: "";
this.status.textContent = "";
this.acceptUntrusted.disabled = !this.tls.checked;
}
/** Read the mail form using the public server API field names. */
#formData() {
return {
publicUrl: document.getElementById("mail-public-url").value,
smtpHost: document.getElementById("mail-smtp-host").value,
smtpPort: document.getElementById("mail-smtp-port").value,
smtpFrom: document.getElementById("mail-smtp-from").value,
smtpUser: document.getElementById("mail-smtp-user").value,
smtpPassword: document.getElementById("mail-smtp-password").value,
smtpTls: this.tls.checked,
smtpAcceptUntrustedCertificates: this.acceptUntrusted.checked,
resetLimit: document.getElementById("mail-reset-limit").value
};
}
/** Store the current mail settings and retain an omitted password. */
async #save(event) {
event.preventDefault();
try {
await this.api("/api/admin/mail-settings", {
method: "PUT",
body: JSON.stringify(this.#formData())
});
document.getElementById("mail-smtp-password").value = "";
document.getElementById("mail-password-help").textContent = this.translate(
"smtp-password-kept", "A password is stored; leave empty to keep it.");
this.status.textContent = this.translate("saved", "Saved");
} catch (error) {
this.status.textContent = error.message;
}
}
/** Send one test message using the unsaved values currently in the form. */
async #test() {
const recipient = document.getElementById("mail-test-recipient").value.trim();
this.testButton.disabled = true;
this.status.textContent = this.translate(
"sending-test-mail", "Sending test email…");
try {
await this.api("/api/admin/mail-settings/test", {
method: "POST",
body: JSON.stringify({ ...this.#formData(), recipient })
});
this.status.textContent = this.translate(
"test-mail-sent", "Test email accepted by SMTP server");
} catch (error) {
console.error("SMTP test failed", error);
this.status.textContent = this.#smtpErrorMessage(error);
} finally {
this.testButton.disabled = false;
}
}
/** Translate known TLS failures and retain other server error messages. */
#smtpErrorMessage(error) {
const message = error && error.message ? error.message : String(error);
const certificateFailure = message.includes("certificate verify failed") ||
message.includes("TLS certificate verification failed");
if (certificateFailure) {
return this.translate(
"smtp-certificate-verification-failed",
"The SMTP server certificate could not be verified. Install a valid certificate, or select the local-server exception if this is a trusted local SMTP server.");
}
if (message.includes("no protocols available")) {
return this.translate(
"smtp-no-modern-tls",
"The SMTP connection attempted an obsolete TLS protocol. Install the current Racket Wiki version, which negotiates modern TLS automatically.");
}
return message;
}
/** Disable the certificate exception whenever STARTTLS is disabled. */
#syncTlsControls() {
this.acceptUntrusted.disabled = !this.tls.checked;
if (this.acceptUntrusted.disabled) this.acceptUntrusted.checked = false;
}
}
export { MailAdmin };