Refuse the welcome mail on a read-only store before it renders anything

generate_and_send_welcome_mail() arrived with the mail templates, after the
read-only guards were added to the other services, and never got one. On a
read-only store it therefore rendered the mail, could hand it to the mail
server, and only failed when it tried to create the archive directory in the
member file -- surfacing a PermissionError instead of the ReadOnlyStoreError
every other write path reports.

The guard now sits at the top, next to the delivery-mode check, so nothing is
rendered, sent or written. The read-only test covers this path (and the SEPA
batch alongside it) and asserts that nothing at all was left behind: no export
file, no archive directory, no "sent" event.

Its member carries an e-mail address now -- without one the mail services bail
out for that reason, and the write the test exists for is never reached.

Note that the SEPA CSV/XML export keeps writing without a guard on purpose: it
writes to a path the board picks outside the store, which a read-only store has
no say over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Marcel Peterkau
2026-08-29 01:09:05 +02:00
co-authored by Claude Opus 5
parent 6a841c9bdd
commit e87f859101
2 changed files with 57 additions and 0 deletions
+3
View File
@@ -141,6 +141,9 @@ def generate_and_send_welcome_mail(
) -> GeneratedWelcomeMail:
if delivery_mode not in {"local", "send", "drafts"}:
raise RepositoryError(f"Unbekannter Versandmodus: {delivery_mode}")
# The mail is archived in the member file, so a read-only store rules the whole
# path out -- said here, before anything is rendered or handed to a mail server.
repository.assert_writable()
member = repository.get_member(member_id)
if not member.email.strip():
raise RepositoryError("Für das Mitglied ist keine E-Mail-Adresse hinterlegt.")