feat: Implementar funcionalidades de Tarefas e Saúde
- Criadas APIs para Health (métricas de saúde) * Registrar peso, altura, % gordura, medidas * Histórico completo de medições * Estatísticas e resumo - Criadas APIs para Tasks (tarefas) * Criar, editar e deletar tarefas * Filtros por status e data * Estatísticas detalhadas * Prioridades (baixa, média, alta) - Frontend implementado: * Página Health.tsx - registro de métricas * Página Tasks.tsx - gerenciamento de tarefas * Página Progress.tsx - visualização de progresso * Dashboard integrado com estatísticas reais - Schemas e modelos atualizados - Todas as funcionalidades testadas e operacionais
This commit is contained in:
246
backend/app/services/email.py
Normal file
246
backend/app/services/email.py
Normal file
@@ -0,0 +1,246 @@
|
||||
from sendgrid import SendGridAPIClient
|
||||
from sendgrid.helpers.mail import Mail, Email, To, Content
|
||||
import logging
|
||||
from app.core.config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def send_verification_email(to_email: str, username: str, verification_token: str):
|
||||
"""Envia email de verificação para novo usuário"""
|
||||
|
||||
verification_url = f"{settings.FRONTEND_URL}/verify-email/{verification_token}"
|
||||
|
||||
# Template do email
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f3f4f6;
|
||||
padding: 20px;
|
||||
}}
|
||||
.container {{
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
}}
|
||||
.header {{
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}}
|
||||
.logo {{
|
||||
font-size: 2.5rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin: 0;
|
||||
}}
|
||||
.content {{
|
||||
color: #374151;
|
||||
line-height: 1.6;
|
||||
}}
|
||||
.button {{
|
||||
display: inline-block;
|
||||
margin: 30px 0;
|
||||
padding: 15px 40px;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
border-radius: 12px;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}}
|
||||
.footer {{
|
||||
margin-top: 40px;
|
||||
padding-top: 20px;
|
||||
border-top: 2px solid #e5e7eb;
|
||||
color: #6b7280;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}}
|
||||
.highlight {{
|
||||
color: #10b981;
|
||||
font-weight: 700;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1 class="logo">🚀 VIDA180</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h2>Olá, <span class="highlight">{username}</span>! 👋</h2>
|
||||
|
||||
<p>Seja muito bem-vindo(a) ao <strong>Vida180</strong>! 🎉</p>
|
||||
|
||||
<p>Estamos muito felizes em ter você conosco nessa jornada de transformação!</p>
|
||||
|
||||
<p>Para ativar sua conta e começar a usar todas as funcionalidades, clique no botão abaixo:</p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{verification_url}" class="button">
|
||||
✅ Verificar Meu Email
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Ou copie e cole este link no seu navegador:<br>
|
||||
<a href="{verification_url}" style="color: #10b981;">{verification_url}</a>
|
||||
</p>
|
||||
|
||||
<p>Após verificar seu email, você terá acesso completo a:</p>
|
||||
<ul>
|
||||
<li>🎯 <strong>Hábitos:</strong> Construa rotinas poderosas</li>
|
||||
<li>📝 <strong>Tarefas:</strong> Organize seu dia</li>
|
||||
<li>💪 <strong>Saúde:</strong> Acompanhe sua evolução física</li>
|
||||
<li>📊 <strong>Progresso:</strong> Visualize sua transformação</li>
|
||||
</ul>
|
||||
|
||||
<p><strong>A transformação acontece um dia de cada vez!</strong> 💪</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>
|
||||
Este email foi enviado porque você se cadastrou no Vida180.<br>
|
||||
Se você não criou esta conta, pode ignorar este email.
|
||||
</p>
|
||||
<p style="margin-top: 20px;">
|
||||
<strong>Vida180</strong> - Transforme sua vida, um dia de cada vez 🚀
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
try:
|
||||
message = Mail(
|
||||
from_email=Email(settings.SENDGRID_FROM_EMAIL, settings.SENDGRID_FROM_NAME),
|
||||
to_emails=To(to_email),
|
||||
subject=f"🚀 Bem-vindo ao Vida180! Confirme seu email",
|
||||
html_content=Content("text/html", html_content)
|
||||
)
|
||||
|
||||
sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
|
||||
response = sg.send(message)
|
||||
|
||||
logger.info(f"Email enviado para {to_email} - Status: {response.status_code}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erro ao enviar email para {to_email}: {str(e)}")
|
||||
return False
|
||||
|
||||
def send_password_reset_email(to_email: str, username: str, reset_token: str):
|
||||
"""Envia email de reset de senha"""
|
||||
|
||||
reset_url = f"{settings.FRONTEND_URL}/reset-password/{reset_token}"
|
||||
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{
|
||||
font-family: 'Arial', sans-serif;
|
||||
background-color: #f3f4f6;
|
||||
padding: 20px;
|
||||
}}
|
||||
.container {{
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
}}
|
||||
.header {{
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}}
|
||||
.logo {{
|
||||
font-size: 2.5rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin: 0;
|
||||
}}
|
||||
.button {{
|
||||
display: inline-block;
|
||||
margin: 30px 0;
|
||||
padding: 15px 40px;
|
||||
background: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
|
||||
color: white !important;
|
||||
text-decoration: none;
|
||||
border-radius: 12px;
|
||||
font-weight: 700;
|
||||
}}
|
||||
.alert {{
|
||||
background: #fef3c7;
|
||||
border-left: 4px solid #f59e0b;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
border-radius: 8px;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1 class="logo">🚀 VIDA180</h1>
|
||||
</div>
|
||||
|
||||
<h2>Olá, {username}! 👋</h2>
|
||||
|
||||
<p>Recebemos uma solicitação para redefinir sua senha.</p>
|
||||
|
||||
<div class="alert">
|
||||
⚠️ Se você não solicitou a alteração de senha, ignore este email e sua senha permanecerá a mesma.
|
||||
</div>
|
||||
|
||||
<p>Para criar uma nova senha, clique no botão abaixo:</p>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{reset_url}" class="button">
|
||||
🔑 Redefinir Minha Senha
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<p style="color: #6b7280; font-size: 14px;">
|
||||
Este link expira em 24 horas.
|
||||
</p>
|
||||
|
||||
<div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid #e5e7eb; color: #6b7280; font-size: 14px; text-align: center;">
|
||||
<strong>Vida180</strong> - Transforme sua vida, um dia de cada vez 🚀
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
try:
|
||||
message = Mail(
|
||||
from_email=Email(settings.SENDGRID_FROM_EMAIL, settings.SENDGRID_FROM_NAME),
|
||||
to_emails=To(to_email),
|
||||
subject="🔑 Redefinir senha - Vida180",
|
||||
html_content=Content("text/html", html_content)
|
||||
)
|
||||
|
||||
sg = SendGridAPIClient(settings.SENDGRID_API_KEY)
|
||||
response = sg.send(message)
|
||||
|
||||
logger.info(f"Email de reset enviado para {to_email}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erro ao enviar email de reset: {str(e)}")
|
||||
return False
|
||||
Reference in New Issue
Block a user