Update all email templates with uniform branded graphics
This commit is contained in:
@@ -1 +1 @@
|
|||||||
0303261629
|
0303261702
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -136,6 +136,108 @@ TEMPLATE_PRESENTATION: Dict[str, Dict[str, str]] = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _build_email_stat_card(label: str, value: str, detail: str = "") -> str:
|
||||||
|
detail_html = (
|
||||||
|
f"<div style=\"margin-top:8px; font-size:13px; line-height:1.6; color:#9aa3b8; word-break:break-word;\">"
|
||||||
|
f"{html.escape(detail)}</div>"
|
||||||
|
if detail
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
"<div style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); "
|
||||||
|
"border-radius:16px; color:#e9ecf5;\">"
|
||||||
|
f"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; "
|
||||||
|
f"margin-bottom:8px;\">{html.escape(label)}</div>"
|
||||||
|
f"<div style=\"font-size:20px; font-weight:800; line-height:1.45; word-break:break-word;\">"
|
||||||
|
f"{html.escape(value)}</div>"
|
||||||
|
f"{detail_html}"
|
||||||
|
"</div>"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_email_stat_grid(cards: list[str]) -> str:
|
||||||
|
if not cards:
|
||||||
|
return ""
|
||||||
|
rows: list[str] = []
|
||||||
|
for index in range(0, len(cards), 2):
|
||||||
|
left = cards[index]
|
||||||
|
right = cards[index + 1] if index + 1 < len(cards) else ""
|
||||||
|
rows.append(
|
||||||
|
"<tr>"
|
||||||
|
f"<td width=\"50%\" style=\"vertical-align:top; padding:0 5px 10px 0;\">{left}</td>"
|
||||||
|
f"<td width=\"50%\" style=\"vertical-align:top; padding:0 0 10px 5px;\">{right}</td>"
|
||||||
|
"</tr>"
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" "
|
||||||
|
"style=\"border-collapse:collapse; margin:0 0 18px;\">"
|
||||||
|
f"{''.join(rows)}"
|
||||||
|
"</table>"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_email_list(items: list[str], *, ordered: bool = False) -> str:
|
||||||
|
tag = "ol" if ordered else "ul"
|
||||||
|
marker = "padding-left:20px;" if ordered else "padding-left:18px;"
|
||||||
|
rendered_items = "".join(
|
||||||
|
f"<li style=\"margin:0 0 8px;\">{html.escape(item)}</li>" for item in items if item
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
f"<{tag} style=\"margin:0; {marker} color:#dbe5ff; line-height:1.8; font-size:14px;\">"
|
||||||
|
f"{rendered_items}"
|
||||||
|
f"</{tag}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_email_panel(title: str, body_html: str, *, variant: str = "neutral") -> str:
|
||||||
|
styles = {
|
||||||
|
"neutral": {
|
||||||
|
"background": "#101726",
|
||||||
|
"border": "rgba(255,255,255,0.08)",
|
||||||
|
"eyebrow": "#9aa3b8",
|
||||||
|
"text": "#dbe5ff",
|
||||||
|
},
|
||||||
|
"brand": {
|
||||||
|
"background": "#101726",
|
||||||
|
"border": "rgba(59,130,246,0.22)",
|
||||||
|
"eyebrow": "#9dbfff",
|
||||||
|
"text": "#dbe5ff",
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"background": "#122016",
|
||||||
|
"border": "rgba(34,197,94,0.24)",
|
||||||
|
"eyebrow": "#9de7b5",
|
||||||
|
"text": "#d9f9e4",
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"background": "#241814",
|
||||||
|
"border": "rgba(251,146,60,0.34)",
|
||||||
|
"eyebrow": "#fbbd7b",
|
||||||
|
"text": "#ffe0ba",
|
||||||
|
},
|
||||||
|
"danger": {
|
||||||
|
"background": "#251418",
|
||||||
|
"border": "rgba(239,68,68,0.32)",
|
||||||
|
"eyebrow": "#ff9b9b",
|
||||||
|
"text": "#ffd0d0",
|
||||||
|
},
|
||||||
|
}.get(variant, {
|
||||||
|
"background": "#101726",
|
||||||
|
"border": "rgba(255,255,255,0.08)",
|
||||||
|
"eyebrow": "#9aa3b8",
|
||||||
|
"text": "#dbe5ff",
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
f"<div style=\"margin:0 0 18px; padding:18px; background:{styles['background']}; "
|
||||||
|
f"border:1px solid {styles['border']}; border-radius:18px; color:{styles['text']};\">"
|
||||||
|
f"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:{styles['eyebrow']}; "
|
||||||
|
f"margin-bottom:10px;\">{html.escape(title)}</div>"
|
||||||
|
f"<div style=\"font-size:14px; line-height:1.8; color:{styles['text']};\">{body_html}</div>"
|
||||||
|
"</div>"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
||||||
"invited": {
|
"invited": {
|
||||||
"subject": "{{app_name}} invite for {{recipient_email}}",
|
"subject": "{{app_name}} invite for {{recipient_email}}",
|
||||||
@@ -156,31 +258,40 @@ DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
|||||||
"<div style=\"margin:0 0 20px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
"<div style=\"margin:0 0 20px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
"A new invitation has been prepared for <strong>{{recipient_email}}</strong>. Use the details below to sign up."
|
"A new invitation has been prepared for <strong>{{recipient_email}}</strong>. Use the details below to sign up."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
+ _build_email_stat_grid(
|
||||||
"<tr>"
|
[
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
_build_email_stat_card("Invite code", "{{invite_code}}"),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Invite code</div>"
|
_build_email_stat_card("Invited by", "{{inviter_username}}"),
|
||||||
"<div style=\"font-size:24px; font-weight:800; letter-spacing:0.06em;\">{{invite_code}}</div>"
|
_build_email_stat_card("Invite label", "{{invite_label}}"),
|
||||||
"</td>"
|
_build_email_stat_card(
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
"Access window",
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Invited by</div>"
|
"{{invite_expires_at}}",
|
||||||
"<div style=\"font-size:20px; font-weight:700;\">{{inviter_username}}</div>"
|
"Remaining uses: {{invite_remaining_uses}}",
|
||||||
"</td>"
|
),
|
||||||
"</tr>"
|
]
|
||||||
"<tr>"
|
)
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
+ _build_email_panel(
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Invite label</div>"
|
"Invitation details",
|
||||||
"<div style=\"font-size:18px; font-weight:700;\">{{invite_label}}</div>"
|
"<div style=\"white-space:pre-line;\">{{invite_description}}</div>",
|
||||||
"</td>"
|
variant="brand",
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
)
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Access window</div>"
|
+ _build_email_panel(
|
||||||
"<div style=\"font-size:16px; font-weight:700;\">{{invite_expires_at}}</div>"
|
"Message from admin",
|
||||||
"<div style=\"margin-top:6px; font-size:13px; color:#9aa3b8;\">Remaining uses: {{invite_remaining_uses}}</div>"
|
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||||
"</td>"
|
variant="neutral",
|
||||||
"</tr>"
|
)
|
||||||
"</table>"
|
+ _build_email_panel(
|
||||||
"<div style=\"margin:0 0 18px; padding:18px; background:#101726; border:1px solid rgba(59,130,246,0.22); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.7; white-space:pre-line;\">{{invite_description}}</div>"
|
"What happens next",
|
||||||
"<div style=\"margin:0; padding:18px; background:#101726; border:1px dashed rgba(255,107,43,0.38); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.7; white-space:pre-line;\">{{message}}</div>"
|
_build_email_list(
|
||||||
|
[
|
||||||
|
"Open the invite link and complete the signup flow.",
|
||||||
|
"Sign in using the shared credentials for Magent and Seerr.",
|
||||||
|
"Use the How it works page if you want a quick overview first.",
|
||||||
|
],
|
||||||
|
ordered=True,
|
||||||
|
),
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"welcome": {
|
"welcome": {
|
||||||
@@ -197,27 +308,31 @@ DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
|||||||
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
"Your account is live and ready to use. Everything below mirrors the current site behavior."
|
"Your account is live and ready to use. Everything below mirrors the current site behavior."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
+ _build_email_stat_grid(
|
||||||
"<tr>"
|
[
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
_build_email_stat_card("Username", "{{username}}"),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Username</div>"
|
_build_email_stat_card("Role", "{{role}}"),
|
||||||
"<div style=\"font-size:22px; font-weight:800;\">{{username}}</div>"
|
_build_email_stat_card("Magent", "{{app_url}}"),
|
||||||
"</td>"
|
_build_email_stat_card("Guides", "{{how_it_works_url}}"),
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
]
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Role</div>"
|
)
|
||||||
"<div style=\"font-size:22px; font-weight:800;\">{{role}}</div>"
|
+ _build_email_panel(
|
||||||
"</td>"
|
"What to do next",
|
||||||
"</tr>"
|
_build_email_list(
|
||||||
"</table>"
|
[
|
||||||
"<div style=\"margin:0 0 18px; padding:18px; background:#101726; border:1px solid rgba(34,197,94,0.24); border-radius:18px; color:#dbe5ff;\">"
|
"Open Magent and sign in using your shared credentials.",
|
||||||
"<div style=\"font-size:15px; font-weight:700; margin:0 0 10px;\">What to do next</div>"
|
"Search all requests or review your own activity without refreshing the page.",
|
||||||
"<ol style=\"margin:0; padding-left:20px; color:#dbe5ff; line-height:1.8; font-size:14px;\">"
|
"Use the invite tools in your profile if your account allows it.",
|
||||||
"<li>Open Magent and sign in using your shared credentials.</li>"
|
],
|
||||||
"<li>Search or review requests without refreshing every page.</li>"
|
ordered=True,
|
||||||
"<li>Use the invite tools in your profile if your account allows it.</li>"
|
),
|
||||||
"</ol>"
|
variant="success",
|
||||||
"</div>"
|
)
|
||||||
"<div style=\"margin:0; padding:18px; background:#101726; border:1px dashed rgba(59,130,246,0.32); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.7; white-space:pre-line;\">{{message}}</div>"
|
+ _build_email_panel(
|
||||||
|
"Additional notes",
|
||||||
|
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
@@ -233,12 +348,35 @@ DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
|||||||
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
"Please review this account notice carefully. This message was sent by an administrator."
|
"Please review this account notice carefully. This message was sent by an administrator."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<div style=\"margin:0 0 18px; padding:18px; background:#241814; border:1px solid rgba(251,146,60,0.34); border-radius:18px; color:#ffe0ba;\">"
|
+ _build_email_stat_grid(
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#fbbd7b; margin-bottom:8px;\">Reason</div>"
|
[
|
||||||
"<div style=\"font-size:18px; font-weight:800; line-height:1.5; white-space:pre-line;\">{{reason}}</div>"
|
_build_email_stat_card("Account", "{{username}}"),
|
||||||
"</div>"
|
_build_email_stat_card("Role", "{{role}}"),
|
||||||
"<div style=\"margin:0 0 18px; padding:18px; background:#101726; border:1px solid rgba(255,255,255,0.08); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.8; white-space:pre-line;\">{{message}}</div>"
|
_build_email_stat_card("Application", "{{app_name}}"),
|
||||||
"<div style=\"margin:0; color:#9aa3b8; font-size:13px; line-height:1.7;\">If you need help or think this was sent in error, contact the site administrator.</div>"
|
_build_email_stat_card("Support", "{{how_it_works_url}}"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"Reason",
|
||||||
|
"<div style=\"font-size:18px; font-weight:800; line-height:1.6; white-space:pre-line;\">{{reason}}</div>",
|
||||||
|
variant="warning",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"Administrator note",
|
||||||
|
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"What to do next",
|
||||||
|
_build_email_list(
|
||||||
|
[
|
||||||
|
"Review the note above and confirm you understand what needs to change.",
|
||||||
|
"If you need help, reply through your usual support path or contact an administrator.",
|
||||||
|
"Keep this email for reference until the matter is resolved.",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"banned": {
|
"banned": {
|
||||||
@@ -253,15 +391,35 @@ DEFAULT_TEMPLATES: Dict[str, Dict[str, str]] = {
|
|||||||
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
"Your account access has changed. Review the details below."
|
"Your account access has changed. Review the details below."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin:0 0 18px; border-collapse:collapse;\">"
|
+ _build_email_stat_grid(
|
||||||
"<tr>"
|
[
|
||||||
"<td style=\"padding:18px; background:#251418; border:1px solid rgba(239,68,68,0.32); border-radius:18px; color:#ffd0d0;\">"
|
_build_email_stat_card("Account", "{{username}}"),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#ff9b9b; margin-bottom:8px;\">Reason</div>"
|
_build_email_stat_card("Status", "Restricted"),
|
||||||
"<div style=\"font-size:18px; font-weight:800; line-height:1.5; white-space:pre-line;\">{{reason}}</div>"
|
_build_email_stat_card("Application", "{{app_name}}"),
|
||||||
"</td>"
|
_build_email_stat_card("Guidance", "{{how_it_works_url}}"),
|
||||||
"</tr>"
|
]
|
||||||
"</table>"
|
)
|
||||||
"<div style=\"margin:0; padding:18px; background:#101726; border:1px solid rgba(255,255,255,0.08); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.8; white-space:pre-line;\">{{message}}</div>"
|
+ _build_email_panel(
|
||||||
|
"Reason",
|
||||||
|
"<div style=\"font-size:18px; font-weight:800; line-height:1.6; white-space:pre-line;\">{{reason}}</div>",
|
||||||
|
variant="danger",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"Administrator note",
|
||||||
|
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"What this means",
|
||||||
|
_build_email_list(
|
||||||
|
[
|
||||||
|
"Your access has been removed or restricted across the linked services.",
|
||||||
|
"If you believe this is incorrect, contact the site administrator directly.",
|
||||||
|
"Do not rely on old links or cached sessions after this change.",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -481,7 +639,7 @@ def build_invite_email_context(
|
|||||||
invite.get("created_by") if invite else (user.get("username") if user else None),
|
invite.get("created_by") if invite else (user.get("username") if user else None),
|
||||||
"Admin",
|
"Admin",
|
||||||
),
|
),
|
||||||
"message": _normalize_display_text(message, ""),
|
"message": _normalize_display_text(message, "No additional note."),
|
||||||
"reason": _normalize_display_text(reason, "Not specified"),
|
"reason": _normalize_display_text(reason, "Not specified"),
|
||||||
"recipient_email": _normalize_display_text(resolved_recipient, "No email supplied"),
|
"recipient_email": _normalize_display_text(resolved_recipient, "No email supplied"),
|
||||||
"role": _normalize_display_text(user.get("role") if user else None, "user"),
|
"role": _normalize_display_text(user.get("role") if user else None, "user"),
|
||||||
@@ -835,6 +993,13 @@ async def send_test_email(recipient_email: Optional[str] = None) -> Dict[str, st
|
|||||||
|
|
||||||
application_url = _normalize_display_text(runtime.magent_application_url, "Not configured")
|
application_url = _normalize_display_text(runtime.magent_application_url, "Not configured")
|
||||||
primary_url = application_url if application_url.lower().startswith(("http://", "https://")) else ""
|
primary_url = application_url if application_url.lower().startswith(("http://", "https://")) else ""
|
||||||
|
smtp_target = f"{_normalize_display_text(runtime.magent_notify_email_smtp_host, 'Not configured')}:{int(runtime.magent_notify_email_smtp_port or 587)}"
|
||||||
|
security_mode = "SSL" if runtime.magent_notify_email_use_ssl else ("STARTTLS" if runtime.magent_notify_email_use_tls else "Plain SMTP")
|
||||||
|
auth_mode = "Authenticated" if (
|
||||||
|
_normalize_display_text(runtime.magent_notify_email_smtp_username)
|
||||||
|
and _normalize_display_text(runtime.magent_notify_email_smtp_password)
|
||||||
|
) else "No SMTP auth"
|
||||||
|
delivery_warning = smtp_email_delivery_warning()
|
||||||
subject = f"{env_settings.app_name} email test"
|
subject = f"{env_settings.app_name} email test"
|
||||||
body_text = (
|
body_text = (
|
||||||
f"This is a test email from {env_settings.app_name}.\n\n"
|
f"This is a test email from {env_settings.app_name}.\n\n"
|
||||||
@@ -852,21 +1017,36 @@ async def send_test_email(recipient_email: Optional[str] = None) -> Dict[str, st
|
|||||||
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
"This is a live test email from Magent. If this renders correctly, the HTML template shell and SMTP handoff are both working."
|
"This is a live test email from Magent. If this renders correctly, the HTML template shell and SMTP handoff are both working."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
+ _build_email_stat_grid(
|
||||||
"<tr>"
|
[
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
_build_email_stat_card("Recipient", resolved_email),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Build</div>"
|
_build_email_stat_card("Build", BUILD_NUMBER),
|
||||||
f"<div style=\"font-size:22px; font-weight:800;\">{html.escape(BUILD_NUMBER)}</div>"
|
_build_email_stat_card("SMTP target", smtp_target),
|
||||||
"</td>"
|
_build_email_stat_card("Security", security_mode, auth_mode),
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
_build_email_stat_card("Application URL", application_url),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Application URL</div>"
|
_build_email_stat_card("Template shell", "Branded HTML", "Logo, gradient, action buttons"),
|
||||||
f"<div style=\"font-size:16px; font-weight:700; line-height:1.5;\">{html.escape(application_url)}</div>"
|
]
|
||||||
"</td>"
|
)
|
||||||
"</tr>"
|
+ _build_email_panel(
|
||||||
"</table>"
|
"What this verifies",
|
||||||
"<div style=\"margin:0; padding:18px; background:#101726; border:1px dashed rgba(59,130,246,0.32); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.7;\">"
|
_build_email_list(
|
||||||
"Use this test when changing SMTP settings, relay targets, or branding."
|
[
|
||||||
"</div>"
|
"Magent can build the HTML template shell correctly.",
|
||||||
|
"The configured SMTP route accepts and relays the message.",
|
||||||
|
"Branding, links, and build metadata are rendering consistently.",
|
||||||
|
]
|
||||||
|
),
|
||||||
|
variant="brand",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"Delivery notes",
|
||||||
|
(
|
||||||
|
f"<div style=\"white-space:pre-line;\">{html.escape(delivery_warning)}</div>"
|
||||||
|
if delivery_warning
|
||||||
|
else "Use this test when changing SMTP settings, relay targets, or branding."
|
||||||
|
),
|
||||||
|
variant="warning" if delivery_warning else "neutral",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
primary_label="Open Magent" if primary_url else "",
|
primary_label="Open Magent" if primary_url else "",
|
||||||
primary_url=primary_url,
|
primary_url=primary_url,
|
||||||
@@ -933,24 +1113,36 @@ async def send_password_reset_email(
|
|||||||
f"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
f"<div style=\"margin:0 0 18px; color:#e9ecf5; font-size:15px; line-height:1.7;\">"
|
||||||
f"A password reset was requested for <strong>{html.escape(username)}</strong>."
|
f"A password reset was requested for <strong>{html.escape(username)}</strong>."
|
||||||
"</div>"
|
"</div>"
|
||||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
+ _build_email_stat_grid(
|
||||||
"<tr>"
|
[
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
_build_email_stat_card("Account", username),
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Account</div>"
|
_build_email_stat_card("Expires", expires_at),
|
||||||
f"<div style=\"font-size:22px; font-weight:800;\">{html.escape(username)}</div>"
|
_build_email_stat_card("Credentials updated", provider_label),
|
||||||
"</td>"
|
_build_email_stat_card("Delivery target", resolved_email),
|
||||||
"<td width=\"50%\" style=\"padding:16px; background:#151c2d; border:1px solid rgba(255,255,255,0.08); border-radius:16px; color:#e9ecf5;\">"
|
]
|
||||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Expires</div>"
|
)
|
||||||
f"<div style=\"font-size:16px; font-weight:700; line-height:1.5;\">{html.escape(expires_at)}</div>"
|
+ _build_email_panel(
|
||||||
"</td>"
|
"What will be updated",
|
||||||
"</tr>"
|
f"This reset will update the password used for <strong>{html.escape(provider_label)}</strong>.",
|
||||||
"</table>"
|
variant="brand",
|
||||||
f"<div style=\"margin:0 0 18px; padding:18px; background:#101726; border:1px solid rgba(59,130,246,0.22); border-radius:18px; color:#dbe5ff; font-size:14px; line-height:1.7;\">"
|
)
|
||||||
f"This reset will update the password used for <strong>{html.escape(provider_label)}</strong>."
|
+ _build_email_panel(
|
||||||
"</div>"
|
"What happens next",
|
||||||
"<div style=\"margin:0; padding:18px; background:#1a1220; border:1px dashed rgba(255,107,43,0.38); border-radius:18px; color:#ffd3bf; font-size:14px; line-height:1.7;\">"
|
_build_email_list(
|
||||||
"If you did not request this reset, ignore this email. No changes will be applied until the reset link is opened and completed."
|
[
|
||||||
"</div>"
|
"Open the reset link and choose a new password.",
|
||||||
|
"Complete the form before the expiry time shown above.",
|
||||||
|
"Use the new password the next time you sign in.",
|
||||||
|
],
|
||||||
|
ordered=True,
|
||||||
|
),
|
||||||
|
variant="neutral",
|
||||||
|
)
|
||||||
|
+ _build_email_panel(
|
||||||
|
"Safety note",
|
||||||
|
"If you did not request this reset, ignore this email. No changes will be applied until the reset link is opened and completed.",
|
||||||
|
variant="warning",
|
||||||
|
)
|
||||||
),
|
),
|
||||||
primary_label="Reset password",
|
primary_label="Reset password",
|
||||||
primary_url=reset_url,
|
primary_url=reset_url,
|
||||||
|
|||||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"version": "0303261629",
|
"version": "0303261702",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"version": "0303261629",
|
"version": "0303261702",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "16.1.6",
|
"next": "16.1.6",
|
||||||
"react": "19.2.4",
|
"react": "19.2.4",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "magent-frontend",
|
"name": "magent-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0303261629",
|
"version": "0303261702",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
|
|||||||
Reference in New Issue
Block a user