From 7e8dadcbdc59b4b282f666623f97f687823d7795 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Thu, 6 Nov 2025 21:58:03 +0200 Subject: [PATCH] =?UTF-8?q?Adaug=C4=83=20trimitere=20ZIP=20pe=20email=20?= =?UTF-8?q?=C8=99i=20elimin=C4=83=20emoji-uri=20din=20mesaje?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /scrape_zip trimite ZIP pe ambele canale (Telegram + email) - /zip trimite ZIP și pe email, nu doar pe Telegram - Elimină emoji-uri din mesajele Telegram user-facing - Adaugă ghid "NO EMOJIS" în CLAUDE.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- CLAUDE.md | 4 +++ notifications.py | 65 +++++++++++++++++++++++++++++++++++++++++ telegram_trigger_bot.py | 21 +++++++++++-- 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 5c295a5..4eee4de 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,6 +10,10 @@ BTGO Scraper - Playwright automation for extracting account balances and transac **⚠️ CRITICAL**: Docker/headless mode is **BLOCKED by WAF**. ONLY works locally with `HEADLESS=false`. +## Coding Guidelines + +**NO EMOJIS**: Do not use emojis in user-facing messages (Telegram, email, notifications). Use plain text only. + ## Running the Scraper ```powershell diff --git a/notifications.py b/notifications.py index 1c1fbd6..753bb32 100644 --- a/notifications.py +++ b/notifications.py @@ -45,6 +45,13 @@ class EmailNotifier: logging.error("Email configuration incomplete") return False + # Check if SEND_AS_ZIP flag is set (from Telegram bot /scrape_zip command) + send_as_zip = os.getenv('SEND_AS_ZIP', 'false').lower() == 'true' + + if send_as_zip: + logging.info("SEND_AS_ZIP flag detected - sending email with ZIP archive") + return self._send_with_zip(files, accounts) + # Create message msg = MIMEMultipart() msg['From'] = self.config.EMAIL_FROM @@ -138,6 +145,64 @@ class EmailNotifier: logging.error(f"Failed to send email with ZIP: {e}") return False + def send_existing_zip(self, zip_path: Path, accounts: list) -> bool: + """ + Send email with existing ZIP file + + Args: + zip_path: Path to existing ZIP file + accounts: List of account data with balances + + Returns: + True if successful, False otherwise + """ + if not self.enabled: + logging.info("Email notifications disabled") + return False + + try: + # Validate config + if not all([self.config.SMTP_SERVER, self.config.EMAIL_FROM, self.config.EMAIL_TO]): + logging.error("Email configuration incomplete") + return False + + if not zip_path.exists(): + logging.error(f"ZIP file not found: {zip_path}") + return False + + # Create message + msg = MIMEMultipart() + msg['From'] = self.config.EMAIL_FROM + msg['To'] = self.config.EMAIL_TO + msg['Subject'] = f'BTGO Export (ZIP) - {datetime.now().strftime("%Y-%m-%d %H:%M")}' + + # Email body + body = self._create_email_body([str(zip_path)], accounts, is_zip=True) + msg.attach(MIMEText(body, 'html')) + + # Attach ZIP file + with open(zip_path, 'rb') as f: + part = MIMEBase('application', 'zip') + part.set_payload(f.read()) + encoders.encode_base64(part) + part.add_header('Content-Disposition', f'attachment; filename={zip_path.name}') + msg.attach(part) + + # Send email + logging.info(f"Sending email with existing ZIP to {self.config.EMAIL_TO}...") + with smtplib.SMTP(self.config.SMTP_SERVER, self.config.SMTP_PORT) as server: + server.starttls() + if self.config.SMTP_USERNAME and self.config.SMTP_PASSWORD: + server.login(self.config.SMTP_USERNAME, self.config.SMTP_PASSWORD) + server.send_message(msg) + + logging.info(f"✓ Email with ZIP sent successfully to {self.config.EMAIL_TO}") + return True + + except Exception as e: + logging.error(f"Failed to send email with existing ZIP: {e}") + return False + def _create_email_body(self, files: List[str], accounts: list, is_zip: bool = False) -> str: """Create HTML email body""" file_list = '
'.join([f'• {Path(f).name}' for f in files]) diff --git a/telegram_trigger_bot.py b/telegram_trigger_bot.py index 50b8678..93e4afa 100644 --- a/telegram_trigger_bot.py +++ b/telegram_trigger_bot.py @@ -15,6 +15,8 @@ from datetime import datetime import glob import requests from dotenv import load_dotenv +from config import Config +from notifications import EmailNotifier # Load environment load_dotenv() @@ -238,7 +240,7 @@ class TelegramTriggerBot: return # Construiește mesaj cu solduri - caption = f"📦 *BTGO Export (ZIP)*\n\n" + caption = f"*BTGO Export (ZIP)*\n\n" caption += f"Timp: {datetime.fromtimestamp(solduri_time).strftime('%Y-%m-%d %H:%M:%S')}\n" caption += f"Dimensiune: {zip_size:.2f} MB\n" caption += f"Fișiere: {len(files_to_zip)}\n\n" @@ -256,7 +258,7 @@ class TelegramTriggerBot: caption += f"Conturi: {len(transaction_files)}" # Trimite ZIP-ul - self.send_message(chat_id, "📦 *Creare arhivă ZIP...*", reply_to_message_id) + self.send_message(chat_id, "*Creare arhivă ZIP...*", reply_to_message_id) url = f"{self.base_url}/sendDocument" with open(zip_path, 'rb') as f: @@ -277,6 +279,21 @@ class TelegramTriggerBot: logging.error(f"Eroare trimitere ZIP: {response.text}") self.send_message(chat_id, f"*EROARE*\n\nNu s-a putut trimite arhiva.", reply_to_message_id) + # Trimite și pe email dacă este configurat + try: + config = Config() + if config.EMAIL_ENABLED: + email_notifier = EmailNotifier(config) + logging.info("Trimitere ZIP pe email...") + if email_notifier.send_existing_zip(zip_path, accounts_data): + logging.info("✓ ZIP trimis cu succes pe email") + else: + logging.warning("Nu s-a putut trimite ZIP-ul pe email") + else: + logging.info("Email notifications disabled - skipping email") + except Exception as e: + logging.error(f"Eroare trimitere ZIP pe email: {e}") + # Șterge fișierul ZIP temporar zip_path.unlink()