utils.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import logging
  2. from datetime import datetime, timedelta
  3. from pathlib import Path
  4. from typing import Any, Dict, Optional
  5. import emails
  6. from emails.template import JinjaTemplate
  7. from jose import jwt
  8. from core.config import settings
  9. def send_email(
  10. email_to: str,
  11. subject_template: str = "",
  12. html_template: str = "",
  13. environment: Dict[str, Any] = {},
  14. ) -> None:
  15. assert settings.EMAILS_ENABLED, "no provided configuration for email variables"
  16. message = emails.Message(
  17. subject=JinjaTemplate(subject_template),
  18. html=JinjaTemplate(html_template),
  19. mail_from=(settings.EMAILS_FROM_NAME, settings.EMAILS_FROM_EMAIL),
  20. )
  21. smtp_options = {"host": settings.SMTP_HOST, "port": settings.SMTP_PORT}
  22. if settings.SMTP_TLS:
  23. smtp_options["tls"] = True
  24. if settings.SMTP_USER:
  25. smtp_options["user"] = settings.SMTP_USER
  26. if settings.SMTP_PASSWORD:
  27. smtp_options["password"] = settings.SMTP_PASSWORD
  28. response = message.send(to=email_to, render=environment, smtp=smtp_options)
  29. logging.info(f"send email result: {response}")
  30. def send_test_email(email_to: str) -> None:
  31. project_name = settings.PROJECT_NAME
  32. subject = f"{project_name} - Test email"
  33. with open(Path(settings.EMAIL_TEMPLATES_DIR) / "test_email.html") as f:
  34. template_str = f.read()
  35. send_email(
  36. email_to=email_to,
  37. subject_template=subject,
  38. html_template=template_str,
  39. environment={"project_name": settings.PROJECT_NAME, "email": email_to},
  40. )
  41. def send_reset_password_email(email_to: str, email: str, token: str) -> None:
  42. project_name = settings.PROJECT_NAME
  43. subject = f"{project_name} - Password recovery for user {email}"
  44. with open(Path(settings.EMAIL_TEMPLATES_DIR) / "reset_password.html") as f:
  45. template_str = f.read()
  46. server_host = settings.SERVER_HOST
  47. link = f"{server_host}/reset-password?token={token}"
  48. send_email(
  49. email_to=email_to,
  50. subject_template=subject,
  51. html_template=template_str,
  52. environment={
  53. "project_name": settings.PROJECT_NAME,
  54. "username": email,
  55. "email": email_to,
  56. "valid_hours": settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS,
  57. "link": link,
  58. },
  59. )
  60. def send_new_account_email(email_to: str, username: str, password: str) -> None:
  61. project_name = settings.PROJECT_NAME
  62. subject = f"{project_name} - New account for user {username}"
  63. with open(Path(settings.EMAIL_TEMPLATES_DIR) / "new_account.html") as f:
  64. template_str = f.read()
  65. link = settings.SERVER_HOST
  66. send_email(
  67. email_to=email_to,
  68. subject_template=subject,
  69. html_template=template_str,
  70. environment={
  71. "project_name": settings.PROJECT_NAME,
  72. "username": username,
  73. "password": password,
  74. "email": email_to,
  75. "link": link,
  76. },
  77. )
  78. def generate_password_reset_token(email: str) -> str:
  79. delta = timedelta(hours=settings.EMAIL_RESET_TOKEN_EXPIRE_HOURS)
  80. now = datetime.utcnow()
  81. expires = now + delta
  82. exp = expires.timestamp()
  83. encoded_jwt = jwt.encode(
  84. {"exp": exp, "nbf": now, "sub": email}, settings.SECRET_KEY, algorithm="HS256",
  85. )
  86. return encoded_jwt
  87. def verify_password_reset_token(token: str) -> Optional[str]:
  88. try:
  89. decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
  90. return decoded_token["email"]
  91. except jwt.JWTError:
  92. return None