feat: email verification, merchant/store password reset, seed gap fix
Some checks failed
Some checks failed
- Add EmailVerificationToken and UserPasswordResetToken models with migration - Add email verification flow: verify-email page route, resend-verification API - Block login for unverified users (EmailNotVerifiedException in auth_service) - Add forgot-password/reset-password endpoints for merchant and store auth - Add "Forgot Password?" links to merchant and store login pages - Send welcome email with verification link on merchant creation - Seed email_verification and merchant_password_reset email templates - Fix db-reset Makefile to run all init-prod seed scripts - Add UserAuthService to satisfy architecture validation rules - Add 52 new tests (unit + integration) with full coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1269,6 +1269,500 @@ If you weren't expecting this invitation, you can safely ignore this email.
|
||||
|
||||
Best regards,
|
||||
The Orion Team
|
||||
""",
|
||||
},
|
||||
# -------------------------------------------------------------------------
|
||||
# EMAIL VERIFICATION
|
||||
# -------------------------------------------------------------------------
|
||||
{
|
||||
"code": "email_verification",
|
||||
"language": "en",
|
||||
"name": "Email Verification",
|
||||
"description": "Sent to users to verify their email address",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "verification_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Verify Your Email Address",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Verify Your Email</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Hi {{ first_name }},</p>
|
||||
|
||||
<p>Please verify your email address by clicking the button below:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ verification_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Verify Email
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
This link will expire in {{ expiry_hours }} hours. If you didn't create an account, you can safely ignore this email.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
If the button doesn't work, copy and paste this link into your browser:<br>
|
||||
<a href="{{ verification_link }}" style="color: #6366f1; word-break: break-all;">{{ verification_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Best regards,<br><strong>The {{ platform_name }} Team</strong></p>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
||||
<p>This is an automated email. Please do not reply directly.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Verify Your Email
|
||||
|
||||
Hi {{ first_name }},
|
||||
|
||||
Please verify your email address by clicking the link below:
|
||||
|
||||
{{ verification_link }}
|
||||
|
||||
This link will expire in {{ expiry_hours }} hours. If you didn't create an account, you can safely ignore this email.
|
||||
|
||||
Best regards,
|
||||
The {{ platform_name }} Team
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "email_verification",
|
||||
"language": "fr",
|
||||
"name": "Verification d'email",
|
||||
"description": "Envoye aux utilisateurs pour verifier leur adresse email",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "verification_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Verifiez votre adresse email",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Verifiez votre email</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Bonjour {{ first_name }},</p>
|
||||
|
||||
<p>Veuillez verifier votre adresse email en cliquant sur le bouton ci-dessous :</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ verification_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Verifier l'email
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Ce lien expirera dans {{ expiry_hours }} heures. Si vous n'avez pas cree de compte, vous pouvez ignorer cet email.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Si le bouton ne fonctionne pas, copiez et collez ce lien dans votre navigateur :<br>
|
||||
<a href="{{ verification_link }}" style="color: #6366f1; word-break: break-all;">{{ verification_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Cordialement,<br><strong>L'equipe {{ platform_name }}</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Verifiez votre email
|
||||
|
||||
Bonjour {{ first_name }},
|
||||
|
||||
Veuillez verifier votre adresse email en cliquant sur le lien ci-dessous :
|
||||
|
||||
{{ verification_link }}
|
||||
|
||||
Ce lien expirera dans {{ expiry_hours }} heures. Si vous n'avez pas cree de compte, vous pouvez ignorer cet email.
|
||||
|
||||
Cordialement,
|
||||
L'equipe {{ platform_name }}
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "email_verification",
|
||||
"language": "de",
|
||||
"name": "E-Mail-Verifizierung",
|
||||
"description": "An Benutzer gesendet, um ihre E-Mail-Adresse zu verifizieren",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "verification_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Bestatigen Sie Ihre E-Mail-Adresse",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">E-Mail bestatigen</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Hallo {{ first_name }},</p>
|
||||
|
||||
<p>Bitte bestatigen Sie Ihre E-Mail-Adresse, indem Sie auf die Schaltflache unten klicken:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ verification_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
E-Mail bestatigen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Dieser Link lauft in {{ expiry_hours }} Stunden ab. Wenn Sie kein Konto erstellt haben, konnen Sie diese E-Mail ignorieren.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Wenn die Schaltflache nicht funktioniert, kopieren Sie diesen Link in Ihren Browser:<br>
|
||||
<a href="{{ verification_link }}" style="color: #6366f1; word-break: break-all;">{{ verification_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Mit freundlichen Grussen,<br><strong>Das {{ platform_name }}-Team</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """E-Mail bestatigen
|
||||
|
||||
Hallo {{ first_name }},
|
||||
|
||||
Bitte bestatigen Sie Ihre E-Mail-Adresse, indem Sie auf den Link unten klicken:
|
||||
|
||||
{{ verification_link }}
|
||||
|
||||
Dieser Link lauft in {{ expiry_hours }} Stunden ab. Wenn Sie kein Konto erstellt haben, konnen Sie diese E-Mail ignorieren.
|
||||
|
||||
Mit freundlichen Grussen,
|
||||
Das {{ platform_name }}-Team
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "email_verification",
|
||||
"language": "lb",
|
||||
"name": "E-Mail Verifizéierung",
|
||||
"description": "Un Benotzer gescheckt fir hir E-Mail-Adress ze verifizéieren",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "verification_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Bestategt Är E-Mail-Adress",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">E-Mail bestategen</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Moien {{ first_name }},</p>
|
||||
|
||||
<p>Bestategt w.e.g. Är E-Mail-Adress andeems Dir op de Knäppchen hei drënner klickt:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ verification_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
E-Mail bestategen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Dese Link leeft an {{ expiry_hours }} Stonnen of. Wann Dir kee Kont erstallt hutt, kennt Dir des E-Mail ignoréieren.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Wann de Knappchen net fonctionnéiert, kopéiert dese Link an Are Browser:<br>
|
||||
<a href="{{ verification_link }}" style="color: #6366f1; word-break: break-all;">{{ verification_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Mat beschte Greiss,<br><strong>D'{{ platform_name }} Team</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """E-Mail bestategen
|
||||
|
||||
Moien {{ first_name }},
|
||||
|
||||
Bestategt w.e.g. Ar E-Mail-Adress andeems Dir op de Link hei drenner klickt:
|
||||
|
||||
{{ verification_link }}
|
||||
|
||||
Dese Link leeft an {{ expiry_hours }} Stonnen of. Wann Dir kee Kont erstallt hutt, kennt Dir des E-Mail ignoréieren.
|
||||
|
||||
Mat beschte Greiss,
|
||||
D'{{ platform_name }} Team
|
||||
""",
|
||||
},
|
||||
# -------------------------------------------------------------------------
|
||||
# MERCHANT PASSWORD RESET
|
||||
# -------------------------------------------------------------------------
|
||||
{
|
||||
"code": "merchant_password_reset",
|
||||
"language": "en",
|
||||
"name": "Merchant Password Reset",
|
||||
"description": "Sent to merchants/store users when they request a password reset",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "reset_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Reset Your Password",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Reset Your Password</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Hi {{ first_name }},</p>
|
||||
|
||||
<p>We received a request to reset your password. Click the button below to create a new password:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ reset_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Reset Password
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
This link will expire in {{ expiry_hours }} hour(s). If you didn't request this password reset, you can safely ignore this email.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
If the button doesn't work, copy and paste this link into your browser:<br>
|
||||
<a href="{{ reset_link }}" style="color: #6366f1; word-break: break-all;">{{ reset_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Best regards,<br><strong>The {{ platform_name }} Team</strong></p>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center; padding: 20px; color: #9ca3af; font-size: 12px;">
|
||||
<p>This is an automated email. Please do not reply directly.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Reset Your Password
|
||||
|
||||
Hi {{ first_name }},
|
||||
|
||||
We received a request to reset your password. Click the link below to create a new password:
|
||||
|
||||
{{ reset_link }}
|
||||
|
||||
This link will expire in {{ expiry_hours }} hour(s). If you didn't request this password reset, you can safely ignore this email.
|
||||
|
||||
Best regards,
|
||||
The {{ platform_name }} Team
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "merchant_password_reset",
|
||||
"language": "fr",
|
||||
"name": "Reinitialisation mot de passe marchand",
|
||||
"description": "Envoye aux marchands lorsqu'ils demandent une reinitialisation de mot de passe",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "reset_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Reinitialiser votre mot de passe",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Reinitialiser votre mot de passe</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Bonjour {{ first_name }},</p>
|
||||
|
||||
<p>Nous avons recu une demande de reinitialisation de votre mot de passe. Cliquez sur le bouton ci-dessous pour creer un nouveau mot de passe :</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ reset_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Reinitialiser le mot de passe
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Ce lien expirera dans {{ expiry_hours }} heure(s). Si vous n'avez pas demande cette reinitialisation, vous pouvez ignorer cet email.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Si le bouton ne fonctionne pas, copiez et collez ce lien dans votre navigateur :<br>
|
||||
<a href="{{ reset_link }}" style="color: #6366f1; word-break: break-all;">{{ reset_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Cordialement,<br><strong>L'equipe {{ platform_name }}</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Reinitialiser votre mot de passe
|
||||
|
||||
Bonjour {{ first_name }},
|
||||
|
||||
Nous avons recu une demande de reinitialisation de votre mot de passe. Cliquez sur le lien ci-dessous :
|
||||
|
||||
{{ reset_link }}
|
||||
|
||||
Ce lien expirera dans {{ expiry_hours }} heure(s). Si vous n'avez pas demande cette reinitialisation, vous pouvez ignorer cet email.
|
||||
|
||||
Cordialement,
|
||||
L'equipe {{ platform_name }}
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "merchant_password_reset",
|
||||
"language": "de",
|
||||
"name": "Handler Passwort zurucksetzen",
|
||||
"description": "An Handler gesendet, wenn sie eine Passwortzurucksetzung anfordern",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "reset_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Passwort zurucksetzen",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Passwort zurucksetzen</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Hallo {{ first_name }},</p>
|
||||
|
||||
<p>Wir haben eine Anfrage zur Zurucksetzung Ihres Passworts erhalten. Klicken Sie auf die Schaltflache unten, um ein neues Passwort zu erstellen:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ reset_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Passwort zurucksetzen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Dieser Link lauft in {{ expiry_hours }} Stunde(n) ab. Wenn Sie diese Passwortzurucksetzung nicht angefordert haben, konnen Sie diese E-Mail ignorieren.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Wenn die Schaltflache nicht funktioniert, kopieren Sie diesen Link in Ihren Browser:<br>
|
||||
<a href="{{ reset_link }}" style="color: #6366f1; word-break: break-all;">{{ reset_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Mit freundlichen Grussen,<br><strong>Das {{ platform_name }}-Team</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Passwort zurucksetzen
|
||||
|
||||
Hallo {{ first_name }},
|
||||
|
||||
Wir haben eine Anfrage zur Zurucksetzung Ihres Passworts erhalten. Klicken Sie auf den Link unten:
|
||||
|
||||
{{ reset_link }}
|
||||
|
||||
Dieser Link lauft in {{ expiry_hours }} Stunde(n) ab. Wenn Sie diese Passwortzurucksetzung nicht angefordert haben, konnen Sie diese E-Mail ignorieren.
|
||||
|
||||
Mit freundlichen Grussen,
|
||||
Das {{ platform_name }}-Team
|
||||
""",
|
||||
},
|
||||
{
|
||||
"code": "merchant_password_reset",
|
||||
"language": "lb",
|
||||
"name": "Handler Passwuert zrecksetzen",
|
||||
"description": "Un Handler gescheckt wann si eng Passwuertzrecksetzung ufroen",
|
||||
"category": EmailCategory.AUTH.value,
|
||||
"is_platform_only": False,
|
||||
"variables": json.dumps([
|
||||
"first_name", "reset_link", "expiry_hours", "platform_name"
|
||||
]),
|
||||
"subject": "Passwuert zrecksetzen",
|
||||
"body_html": """<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<div style="background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%); padding: 30px; border-radius: 10px 10px 0 0;">
|
||||
<h1 style="color: white; margin: 0; font-size: 28px;">Passwuert zrecksetzen</h1>
|
||||
</div>
|
||||
|
||||
<div style="background: #f9fafb; padding: 30px; border-radius: 0 0 10px 10px;">
|
||||
<p style="font-size: 16px;">Moien {{ first_name }},</p>
|
||||
|
||||
<p>Mir hunn eng Ufro kritt fir Aert Passwuert zreckzesetzen. Klickt op de Knappchen hei drenner fir en neit Passwuert ze kreéieren:</p>
|
||||
|
||||
<div style="text-align: center; margin: 30px 0;">
|
||||
<a href="{{ reset_link }}" style="background: #6366f1; color: white; padding: 14px 28px; text-decoration: none; border-radius: 8px; font-weight: bold; display: inline-block;">
|
||||
Passwuert zrecksetzen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Dese Link leeft an {{ expiry_hours }} Stonn(en) of. Wann Dir des Passwuertzrecksetzung net ugefrot hutt, kennt Dir des E-Mail ignoréieren.
|
||||
</p>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px; margin-top: 20px;">
|
||||
Wann de Knappchen net fonctionnéiert, kopéiert dese Link an Are Browser:<br>
|
||||
<a href="{{ reset_link }}" style="color: #6366f1; word-break: break-all;">{{ reset_link }}</a>
|
||||
</p>
|
||||
|
||||
<p style="margin-top: 30px;">Mat beschte Greiss,<br><strong>D'{{ platform_name }} Team</strong></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>""",
|
||||
"body_text": """Passwuert zrecksetzen
|
||||
|
||||
Moien {{ first_name }},
|
||||
|
||||
Mir hunn eng Ufro kritt fir Aert Passwuert zreckzesetzen. Klickt op de Link hei drenner:
|
||||
|
||||
{{ reset_link }}
|
||||
|
||||
Dese Link leeft an {{ expiry_hours }} Stonn(en) of. Wann Dir des Passwuertzrecksetzung net ugefrot hutt, kennt Dir des E-Mail ignoréieren.
|
||||
|
||||
Mat beschte Greiss,
|
||||
D'{{ platform_name }} Team
|
||||
""",
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user