mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-25 06:55:17 +02:00
Mahnungs- and SEPA-info-mails could previously only be saved as a local .eml file that still had to be manually imported into Thunderbird. Add a per-store "E-Mail-Versand" configuration (Optionen -> E-Mail-Versand, stored in repository.json alongside the rest of the club's settings, since different stores may use different mailboxes) with four delivery modes: - "Lokal speichern": today's behaviour, unchanged default for existing stores. - "Direkt versenden": sends via SMTP. - "Als Entwurf ablegen": IMAP APPENDs into a configurable drafts folder, so it shows up live in whatever mail client is already watching that account. - "Jedes Mal fragen": prompts once per generation action (not per e-mail -- a SEPA batch can cover dozens of members) with Senden/Entwürfe/Abbrechen. New ccma.services.mail_delivery module (smtplib/imaplib, no new dependency) opens one authenticated connection per batch and reuses it across all messages instead of reconnecting per recipient. Both "Verbindung testen" buttons in Options exercise the same connection path used for real delivery. The archived per-member copy of every generated e-mail is unaffected and still always written regardless of delivery mode. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
104 lines
3.4 KiB
Python
104 lines
3.4 KiB
Python
import pytest
|
|
|
|
from ccma.storage.repository import MemberRepository, RepositoryError
|
|
|
|
|
|
def test_email_settings_default_to_local_delivery_for_new_repositories(tmp_path) -> None:
|
|
repository = MemberRepository(tmp_path)
|
|
repository.initialize()
|
|
|
|
settings = repository.get_email_settings()
|
|
|
|
assert settings["delivery_mode"] == "local"
|
|
assert settings["smtp_host"] == ""
|
|
assert settings["imap_host"] == ""
|
|
|
|
|
|
def test_email_settings_round_trip_through_save_and_get(tmp_path) -> None:
|
|
repository = MemberRepository(tmp_path)
|
|
repository.initialize()
|
|
|
|
repository.save_email_settings(
|
|
delivery_mode="ask",
|
|
smtp_host="mail.example.org",
|
|
smtp_port=587,
|
|
smtp_security="starttls",
|
|
smtp_username="board@example.org",
|
|
smtp_password="secret",
|
|
imap_host="mail.example.org",
|
|
imap_port=993,
|
|
imap_security="ssl",
|
|
imap_username="board@example.org",
|
|
imap_password="secret",
|
|
imap_drafts_folder="INBOX.Entwürfe",
|
|
)
|
|
|
|
settings = repository.get_email_settings()
|
|
assert settings["delivery_mode"] == "ask"
|
|
assert settings["smtp_host"] == "mail.example.org"
|
|
assert settings["smtp_port"] == 587
|
|
assert settings["smtp_password"] == "secret"
|
|
assert settings["imap_drafts_folder"] == "INBOX.Entwürfe"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("overrides", "match"),
|
|
[
|
|
({"delivery_mode": "carrier-pigeon"}, "Ungültiger Versandmodus"),
|
|
({"smtp_security": "rot13"}, "Ungültige SMTP-Verschlüsselung"),
|
|
({"imap_security": "rot13"}, "Ungültige IMAP-Verschlüsselung"),
|
|
({"delivery_mode": "send", "smtp_host": ""}, "SMTP-Server erforderlich"),
|
|
({"delivery_mode": "drafts", "imap_host": ""}, "IMAP-Server erforderlich"),
|
|
({"delivery_mode": "ask", "imap_host": ""}, "IMAP-Server erforderlich"),
|
|
({"smtp_port": 0}, "SMTP-Port"),
|
|
({"smtp_port": 70000}, "SMTP-Port"),
|
|
({"imap_port": 0}, "IMAP-Port"),
|
|
],
|
|
)
|
|
def test_email_settings_rejects_invalid_input(tmp_path, overrides, match) -> None:
|
|
repository = MemberRepository(tmp_path)
|
|
repository.initialize()
|
|
values = {
|
|
"delivery_mode": "send",
|
|
"smtp_host": "mail.example.org",
|
|
"smtp_port": 587,
|
|
"smtp_security": "starttls",
|
|
"smtp_username": "",
|
|
"smtp_password": "",
|
|
"imap_host": "mail.example.org",
|
|
"imap_port": 993,
|
|
"imap_security": "ssl",
|
|
"imap_username": "",
|
|
"imap_password": "",
|
|
"imap_drafts_folder": "",
|
|
}
|
|
values.update(overrides)
|
|
|
|
with pytest.raises(RepositoryError, match=match):
|
|
repository.save_email_settings(**values)
|
|
|
|
|
|
def test_email_settings_local_mode_needs_no_server(tmp_path) -> None:
|
|
repository = MemberRepository(tmp_path)
|
|
repository.initialize()
|
|
|
|
repository.save_email_settings(
|
|
delivery_mode="local",
|
|
smtp_host="",
|
|
smtp_port=587,
|
|
smtp_security="starttls",
|
|
smtp_username="",
|
|
smtp_password="",
|
|
imap_host="",
|
|
imap_port=993,
|
|
imap_security="ssl",
|
|
imap_username="",
|
|
imap_password="",
|
|
imap_drafts_folder="",
|
|
)
|
|
|
|
settings = repository.get_email_settings()
|
|
assert settings["delivery_mode"] == "local"
|
|
# Blank folder falls back to a sensible default instead of staying empty.
|
|
assert settings["imap_drafts_folder"] == "INBOX.Entwürfe"
|