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]] = {
|
||||
"invited": {
|
||||
"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;\">"
|
||||
"A new invitation has been prepared for <strong>{{recipient_email}}</strong>. Use the details below to sign up."
|
||||
"</div>"
|
||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
||||
"<tr>"
|
||||
"<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;\">Invite code</div>"
|
||||
"<div style=\"font-size:24px; font-weight:800; letter-spacing:0.06em;\">{{invite_code}}</div>"
|
||||
"</td>"
|
||||
"<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;\">Invited by</div>"
|
||||
"<div style=\"font-size:20px; font-weight:700;\">{{inviter_username}}</div>"
|
||||
"</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;\">"
|
||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#9aa3b8; margin-bottom:8px;\">Invite label</div>"
|
||||
"<div style=\"font-size:18px; font-weight:700;\">{{invite_label}}</div>"
|
||||
"</td>"
|
||||
"<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>"
|
||||
"<div style=\"font-size:16px; font-weight:700;\">{{invite_expires_at}}</div>"
|
||||
"<div style=\"margin-top:6px; font-size:13px; color:#9aa3b8;\">Remaining uses: {{invite_remaining_uses}}</div>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"<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>"
|
||||
"<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_stat_grid(
|
||||
[
|
||||
_build_email_stat_card("Invite code", "{{invite_code}}"),
|
||||
_build_email_stat_card("Invited by", "{{inviter_username}}"),
|
||||
_build_email_stat_card("Invite label", "{{invite_label}}"),
|
||||
_build_email_stat_card(
|
||||
"Access window",
|
||||
"{{invite_expires_at}}",
|
||||
"Remaining uses: {{invite_remaining_uses}}",
|
||||
),
|
||||
]
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"Invitation details",
|
||||
"<div style=\"white-space:pre-line;\">{{invite_description}}</div>",
|
||||
variant="brand",
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"Message from admin",
|
||||
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||
variant="neutral",
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"What happens next",
|
||||
_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": {
|
||||
@@ -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;\">"
|
||||
"Your account is live and ready to use. Everything below mirrors the current site behavior."
|
||||
"</div>"
|
||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
||||
"<tr>"
|
||||
"<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;\">Username</div>"
|
||||
"<div style=\"font-size:22px; font-weight:800;\">{{username}}</div>"
|
||||
"</td>"
|
||||
"<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>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</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;\">"
|
||||
"<div style=\"font-size:15px; font-weight:700; margin:0 0 10px;\">What to do next</div>"
|
||||
"<ol style=\"margin:0; padding-left:20px; color:#dbe5ff; line-height:1.8; font-size:14px;\">"
|
||||
"<li>Open Magent and sign in using your shared credentials.</li>"
|
||||
"<li>Search or review requests without refreshing every page.</li>"
|
||||
"<li>Use the invite tools in your profile if your account allows it.</li>"
|
||||
"</ol>"
|
||||
"</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_stat_grid(
|
||||
[
|
||||
_build_email_stat_card("Username", "{{username}}"),
|
||||
_build_email_stat_card("Role", "{{role}}"),
|
||||
_build_email_stat_card("Magent", "{{app_url}}"),
|
||||
_build_email_stat_card("Guides", "{{how_it_works_url}}"),
|
||||
]
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"What to do next",
|
||||
_build_email_list(
|
||||
[
|
||||
"Open Magent and sign in using your shared credentials.",
|
||||
"Search all requests or review your own activity without refreshing the page.",
|
||||
"Use the invite tools in your profile if your account allows it.",
|
||||
],
|
||||
ordered=True,
|
||||
),
|
||||
variant="success",
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"Additional notes",
|
||||
"<div style=\"white-space:pre-line;\">{{message}}</div>",
|
||||
variant="neutral",
|
||||
)
|
||||
),
|
||||
},
|
||||
"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;\">"
|
||||
"Please review this account notice carefully. This message was sent by an administrator."
|
||||
"</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;\">"
|
||||
"<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>"
|
||||
"</div>"
|
||||
"<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>"
|
||||
"<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_grid(
|
||||
[
|
||||
_build_email_stat_card("Account", "{{username}}"),
|
||||
_build_email_stat_card("Role", "{{role}}"),
|
||||
_build_email_stat_card("Application", "{{app_name}}"),
|
||||
_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": {
|
||||
@@ -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;\">"
|
||||
"Your account access has changed. Review the details below."
|
||||
"</div>"
|
||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin:0 0 18px; border-collapse:collapse;\">"
|
||||
"<tr>"
|
||||
"<td style=\"padding:18px; background:#251418; border:1px solid rgba(239,68,68,0.32); border-radius:18px; color:#ffd0d0;\">"
|
||||
"<div style=\"font-size:11px; letter-spacing:0.12em; text-transform:uppercase; color:#ff9b9b; margin-bottom:8px;\">Reason</div>"
|
||||
"<div style=\"font-size:18px; font-weight:800; line-height:1.5; white-space:pre-line;\">{{reason}}</div>"
|
||||
"</td>"
|
||||
"</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_stat_grid(
|
||||
[
|
||||
_build_email_stat_card("Account", "{{username}}"),
|
||||
_build_email_stat_card("Status", "Restricted"),
|
||||
_build_email_stat_card("Application", "{{app_name}}"),
|
||||
_build_email_stat_card("Guidance", "{{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="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),
|
||||
"Admin",
|
||||
),
|
||||
"message": _normalize_display_text(message, ""),
|
||||
"message": _normalize_display_text(message, "No additional note."),
|
||||
"reason": _normalize_display_text(reason, "Not specified"),
|
||||
"recipient_email": _normalize_display_text(resolved_recipient, "No email supplied"),
|
||||
"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")
|
||||
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"
|
||||
body_text = (
|
||||
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;\">"
|
||||
"This is a live test email from Magent. If this renders correctly, the HTML template shell and SMTP handoff are both working."
|
||||
"</div>"
|
||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
||||
"<tr>"
|
||||
"<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;\">Build</div>"
|
||||
f"<div style=\"font-size:22px; font-weight:800;\">{html.escape(BUILD_NUMBER)}</div>"
|
||||
"</td>"
|
||||
"<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;\">Application URL</div>"
|
||||
f"<div style=\"font-size:16px; font-weight:700; line-height:1.5;\">{html.escape(application_url)}</div>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
"<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;\">"
|
||||
"Use this test when changing SMTP settings, relay targets, or branding."
|
||||
"</div>"
|
||||
+ _build_email_stat_grid(
|
||||
[
|
||||
_build_email_stat_card("Recipient", resolved_email),
|
||||
_build_email_stat_card("Build", BUILD_NUMBER),
|
||||
_build_email_stat_card("SMTP target", smtp_target),
|
||||
_build_email_stat_card("Security", security_mode, auth_mode),
|
||||
_build_email_stat_card("Application URL", application_url),
|
||||
_build_email_stat_card("Template shell", "Branded HTML", "Logo, gradient, action buttons"),
|
||||
]
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"What this verifies",
|
||||
_build_email_list(
|
||||
[
|
||||
"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_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"A password reset was requested for <strong>{html.escape(username)}</strong>."
|
||||
"</div>"
|
||||
"<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse:separate; border-spacing:10px 10px; margin:0 0 18px;\">"
|
||||
"<tr>"
|
||||
"<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;\">Account</div>"
|
||||
f"<div style=\"font-size:22px; font-weight:800;\">{html.escape(username)}</div>"
|
||||
"</td>"
|
||||
"<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>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"</table>"
|
||||
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>."
|
||||
"</div>"
|
||||
"<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;\">"
|
||||
"If you did not request this reset, ignore this email. No changes will be applied until the reset link is opened and completed."
|
||||
"</div>"
|
||||
+ _build_email_stat_grid(
|
||||
[
|
||||
_build_email_stat_card("Account", username),
|
||||
_build_email_stat_card("Expires", expires_at),
|
||||
_build_email_stat_card("Credentials updated", provider_label),
|
||||
_build_email_stat_card("Delivery target", resolved_email),
|
||||
]
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"What will be updated",
|
||||
f"This reset will update the password used for <strong>{html.escape(provider_label)}</strong>.",
|
||||
variant="brand",
|
||||
)
|
||||
+ _build_email_panel(
|
||||
"What happens next",
|
||||
_build_email_list(
|
||||
[
|
||||
"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_url=reset_url,
|
||||
|
||||
4
frontend/package-lock.json
generated
4
frontend/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "magent-frontend",
|
||||
"version": "0303261629",
|
||||
"version": "0303261702",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "magent-frontend",
|
||||
"version": "0303261629",
|
||||
"version": "0303261702",
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.4",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "magent-frontend",
|
||||
"private": true,
|
||||
"version": "0303261629",
|
||||
"version": "0303261702",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
|
||||
Reference in New Issue
Block a user