Coverage for app/backend/src/couchers/email/dump_emails.py: 0%
48 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 04:01 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 04:01 +0000
1"""
2Dumps emails subjects and html/plaintext bodies with dummy data.
3"""
5import inspect
6import re
7import sys
8from argparse import ArgumentParser
9from dataclasses import dataclass
10from datetime import UTC
11from pathlib import Path
13import couchers.email.emails
14from couchers.email.emails import EmailBase
15from couchers.email.rendering import (
16 EmailFooter,
17 UnsubscribeInfo,
18 UnsubscribeLink,
19 render_html_body,
20 render_plaintext_body,
21)
22from couchers.i18n import LocalizationContext
23from couchers.templating import template_folder
26@dataclass
27class CommandLineArgs:
28 filter: str
29 outdir: Path
30 locale: str
32 @staticmethod
33 def parse(args: list[str]) -> CommandLineArgs:
34 parser = ArgumentParser(description=__doc__)
35 parser.add_argument("--filter", type=str, default="*", help="A filter for email classes to dump.")
36 parser.add_argument(
37 "--outdir", type=Path, default=template_folder, help="The directory to write email bodies to."
38 )
39 parser.add_argument("--locale", type=str, default="en", help="The locale to use.")
40 parsed_args = parser.parse_args(args)
41 return CommandLineArgs(**parsed_args.__dict__)
44def main() -> None:
45 args = CommandLineArgs.parse(sys.argv[1:])
46 loc_context = LocalizationContext(locale=args.locale, timezone=UTC)
48 footer = EmailFooter(
49 timezone_name="UTC",
50 unsubscribe_info=UnsubscribeInfo(
51 manage_notifications_url="https://example.com/manage-notifications",
52 do_not_email_url="https://example.com/do-not-email",
53 topic_action_link=UnsubscribeLink(text="topic-action", url="https://example.com/unsubscribe"),
54 ),
55 )
57 filter_regex = re.compile(re.escape(args.filter).replace(r"\*", ".*?"))
59 for _, klass in inspect.getmembers(couchers.email.emails, lambda o: inspect.isclass(o) and o.__base__ == EmailBase):
60 email_class: type[EmailBase] = klass
61 if filter_regex.fullmatch(email_class.__name__):
62 dump_email(email_class.dummy_data(), footer, loc_context, args.outdir)
65def dump_email(email: EmailBase, footer: EmailFooter, loc_context: LocalizationContext, outdir: Path) -> None:
66 """Dumps an email's subject and plaintext+html body to a file."""
67 subject_line = email.get_subject_line(loc_context)
68 preview_line = email.get_preview_line(loc_context)
69 blocks = email.get_body_blocks(loc_context)
71 outdir.mkdir(exist_ok=True)
73 print(f"Dumping email class {email.__class__.__name__}")
74 print(f" Subject: {subject_line}")
76 html_path = outdir / f"{email.__class__.__name__}.html"
77 print(f" Rendering html to {html_path}...")
78 html = render_html_body(
79 subject=subject_line, preview=preview_line, blocks=blocks, footer=footer, loc_context=loc_context
80 )
81 html_path.write_text(html)
83 plaintext_path = outdir / f"{email.__class__.__name__}.txt"
84 print(f" Rendering plaintext to {plaintext_path}...")
85 plaintext = render_plaintext_body(blocks=blocks, footer=footer, loc_context=loc_context)
86 plaintext_path.write_text(plaintext)
89if __name__ == "__main__":
90 main()