""" Send welcome activation emails to users who never logged in. These users were imported (batch import, admin panel, WhatsApp registration) with passwords but never received welcome emails or password reset links. This script generates reset tokens (72h validity) and sends a welcoming activation email with a link to set their password. Usage: # Preview who would receive emails (no sending) python3 send_welcome_activation.py --dry-run # Send test email to admin python3 send_welcome_activation.py --test-email maciej.pienczyn@inpi.pl # Send to a specific user by ID python3 send_welcome_activation.py --user-id 53 # Send to all never-logged-in users (requires confirmation) python3 send_welcome_activation.py --send-all Run on production server with DATABASE_URL set. """ import os import sys import argparse import secrets from datetime import datetime, timedelta # Add project root to path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from database import SessionLocal, User import email_service TOKEN_VALIDITY_HOURS = 72 BASE_URL = 'https://nordabiznes.pl' def get_never_logged_in_users(db): """Find all active, verified users who never logged in.""" return ( db.query(User) .filter( User.last_login.is_(None), User.is_active.is_(True), ) .order_by(User.id) .all() ) def send_activation_email(db, user): """Generate token and send welcome activation email to a user.""" token = secrets.token_urlsafe(32) expires = datetime.now() + timedelta(hours=TOKEN_VALIDITY_HOURS) user.reset_token = token user.reset_token_expires = expires db.commit() reset_url = f"{BASE_URL}/reset-password/{token}" success = email_service.send_welcome_activation_email( email=user.email, name=user.name, reset_url=reset_url ) return success def cmd_dry_run(db): """Show users who would receive activation emails.""" users = get_never_logged_in_users(db) if not users: print("Brak użytkowników do aktywacji (wszyscy się zalogowali).") return print(f"Użytkownicy, którzy nigdy się nie zalogowali ({len(users)}):\n") print(f"{'ID':>4} {'Imię i nazwisko':<30} {'Email':<40} {'Aktywny':>7} {'Zweryfikowany':>13}") print("-" * 100) for u in users: print(f"{u.id:>4} {u.name:<30} {u.email:<40} {'tak' if u.is_active else 'nie':>7} {'tak' if u.is_verified else 'nie':>13}") print(f"\nRazem: {len(users)} użytkowników") print("\nAby wysłać e-mail testowy: --test-email ") print("Aby wysłać do jednej osoby: --user-id ") def cmd_test_email(db, test_email): """Send a test activation email to specified address.""" # Find or create a fake context for the test print(f"Wysyłanie testowego e-maila powitalnego do: {test_email}") token = secrets.token_urlsafe(32) reset_url = f"{BASE_URL}/reset-password/{token}" # Use test data success = email_service.send_welcome_activation_email( email=test_email, name="Testowy Użytkownik", reset_url=reset_url ) if success: print(f" OK: E-mail testowy wysłany do {test_email}") print(f" Link (nieaktywny - testowy token): {reset_url}") else: print(f" FAIL: Nie udało się wysłać e-maila do {test_email}") sys.exit(1) def cmd_send_user(db, user_id): """Send activation email to a specific user.""" user = db.query(User).get(user_id) if not user: print(f"ERROR: Nie znaleziono użytkownika o ID {user_id}") sys.exit(1) if not user.is_active: print(f"ERROR: Użytkownik {user.name} (ID {user_id}) jest nieaktywny") sys.exit(1) if user.last_login is not None: print(f"SKIP: Użytkownik {user.name} (ID {user_id}) już się logował ({user.last_login})") return print(f"Wysyłanie e-maila powitalnego do: {user.name} <{user.email}> (ID {user_id})") success = send_activation_email(db, user) if success: print(f" OK: E-mail wysłany do {user.name} <{user.email}>") else: print(f" FAIL: Nie udało się wysłać e-maila do {user.name} <{user.email}>") sys.exit(1) def cmd_send_all(db): """Send activation emails to all never-logged-in users (with confirmation).""" users = get_never_logged_in_users(db) if not users: print("Brak użytkowników do aktywacji.") return print(f"Wysyłka do {len(users)} użytkowników:\n") for u in users: print(f" {u.id:>4} {u.name:<30} {u.email}") confirm = input(f"\nCzy wysłać e-maile do {len(users)} użytkowników? (tak/nie): ") if confirm.strip().lower() != 'tak': print("Anulowano.") return results = {'sent': [], 'failed': []} for user in users: try: success = send_activation_email(db, user) if success: results['sent'].append(f"{user.name} <{user.email}>") print(f" OK: {user.name} <{user.email}>") else: results['failed'].append(f"{user.name} <{user.email}>") print(f" FAIL: {user.name} <{user.email}>") except Exception as e: results['failed'].append(f"{user.name} <{user.email}>: {e}") print(f" ERROR: {user.name} <{user.email}>: {e}") print(f"\n{'='*50}") print(f"Wysłano: {len(results['sent'])}") print(f"Błędy: {len(results['failed'])}") if results['failed']: print("\nSzczegóły błędów:") for f in results['failed']: print(f" - {f}") def main(): parser = argparse.ArgumentParser( description='Wyślij e-maile powitalne do użytkowników, którzy nigdy się nie zalogowali.' ) group = parser.add_mutually_exclusive_group(required=True) group.add_argument('--dry-run', action='store_true', help='Pokaż listę użytkowników bez wysyłania e-maili') group.add_argument('--test-email', type=str, help='Wyślij testowy e-mail na podany adres') group.add_argument('--user-id', type=int, help='Wyślij e-mail do użytkownika o podanym ID') group.add_argument('--send-all', action='store_true', help='Wyślij e-maile do wszystkich niezalogowanych (wymaga potwierdzenia)') args = parser.parse_args() if not args.dry_run and not email_service.is_configured(): print("ERROR: Email service not configured. Set Azure credentials in .env") sys.exit(1) db = SessionLocal() try: if args.dry_run: cmd_dry_run(db) elif args.test_email: cmd_test_email(db, args.test_email) elif args.user_id: cmd_send_user(db, args.user_id) elif args.send_all: cmd_send_all(db) finally: db.close() if __name__ == '__main__': main()