import logging import os import smtplib from email.message import EmailMessage import app.services.bank_scraper from app.celery_app import celery_app logger = logging.getLogger("celery_tasks") if not logger.handlers: _h = logging.StreamHandler() logger.addHandler(_h) logger.setLevel(logging.INFO) @celery_app.task(name="workers.send_email") def send_email(to: str, subject: str, body: str) -> None: if not (to and subject and body): logger.error("Email task missing fields. to=%r subject=%r body_len=%r", to, subject, len(body) if body else 0) return host = os.getenv("SMTP_HOST") if not host: logger.error("SMTP_HOST is not configured; cannot send email") return # Configuration port = int(os.getenv("SMTP_PORT", "25")) username = os.getenv("SMTP_USERNAME") password = os.getenv("SMTP_PASSWORD") use_tls = os.getenv("SMTP_USE_TLS", "0").lower() in {"1", "true", "yes"} use_ssl = os.getenv("SMTP_USE_SSL", "0").lower() in {"1", "true", "yes"} timeout = int(os.getenv("SMTP_TIMEOUT", "10")) mail_from = os.getenv("SMTP_FROM") or username or "noreply@localhost" # Build message msg = EmailMessage() msg["To"] = to msg["From"] = mail_from msg["Subject"] = subject msg.set_content(body) try: if use_ssl: with smtplib.SMTP_SSL(host=host, port=port, timeout=timeout) as smtp: if username and password: smtp.login(username, password) smtp.send_message(msg) else: with smtplib.SMTP(host=host, port=port, timeout=timeout) as smtp: # STARTTLS if requested if use_tls: smtp.starttls() if username and password: smtp.login(username, password) smtp.send_message(msg) logger.info("[Celery] Email sent | to=%s | subject=%s | body_len=%d", to, subject, len(body)) except Exception: logger.exception("Failed to send email via SMTP to=%s subject=%s host=%s port=%s tls=%s ssl=%s", to, subject, host, port, use_tls, use_ssl) @celery_app.task(name="workers.load_transactions") def load_transactions(user_id: str) -> None: if not user_id: logger.error("Load transactions task missing user_id.") return logger.info("[Celery] Starting load_transactions | user_id=%s", user_id) try: # Use synchronous bank scraper functions directly, mirroring load_all_transactions app.services.bank_scraper.load_mock_bank_transactions(user_id) app.services.bank_scraper.load_ceska_sporitelna_transactions(user_id) except Exception: logger.exception("Failed to load transactions for user_id=%s", user_id) else: logger.info("[Celery] Finished load_transactions | user_id=%s", user_id) @celery_app.task def load_all_transactions() -> None: logger.info("[Celery] Starting load_all_transactions") # Now use synchronous bank scraper functions directly app.services.bank_scraper.load_all_mock_bank_transactions() app.services.bank_scraper.load_all_ceska_sporitelna_transactions() logger.info("[Celery] Finished load_all_transactions")