""" Weekly Digest Email Service Sends weekly digest emails to users who have email_digest enabled. Run via cron job: 0 9 * * 0 (Sunday at 9am) """ import os import sys # Add backend to path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from datetime import datetime, timedelta from sqlmodel import Session, select, func from database import engine from models import User, Show, Performance, Review, Rating, ChaseSong, Attendance def get_weekly_stats(session: Session, user_id: int, start_date: datetime, end_date: datetime): """Get user's activity stats for the week""" # Shows attended this week shows_attended = session.exec( select(func.count(Attendance.id)) .where(Attendance.user_id == user_id) .where(Attendance.created_at >= start_date) .where(Attendance.created_at < end_date) ).one() or 0 # Reviews written this week reviews_written = session.exec( select(func.count(Review.id)) .where(Review.user_id == user_id) .where(Review.created_at >= start_date) .where(Review.created_at < end_date) ).one() or 0 # Ratings given this week ratings_given = session.exec( select(func.count(Rating.id)) .where(Rating.user_id == user_id) .where(Rating.created_at >= start_date) .where(Rating.created_at < end_date) ).one() or 0 # Check for caught chase songs chase_caught = session.exec( select(func.count(ChaseSong.id)) .where(ChaseSong.user_id == user_id) .where(ChaseSong.caught_at >= start_date) .where(ChaseSong.caught_at < end_date) ).one() or 0 return { "shows_attended": shows_attended, "reviews_written": reviews_written, "ratings_given": ratings_given, "chase_caught": chase_caught } def get_community_highlights(session: Session, start_date: datetime, end_date: datetime): """Get community highlights for the week""" # New shows added new_shows = session.exec( select(func.count(Show.id)) .where(Show.date >= start_date.date()) .where(Show.date < end_date.date()) ).one() or 0 # Total reviews this week total_reviews = session.exec( select(func.count(Review.id)) .where(Review.created_at >= start_date) .where(Review.created_at < end_date) ).one() or 0 # Most reviewed performance this week top_perf = session.exec( select(Performance.id, func.count(Review.id).label("count")) .join(Review, Review.performance_id == Performance.id) .where(Review.created_at >= start_date) .where(Review.created_at < end_date) .group_by(Performance.id) .order_by(func.count(Review.id).desc()) .limit(1) ).first() return { "new_shows": new_shows, "total_reviews": total_reviews, "top_performance_id": top_perf[0] if top_perf else None } def send_digest_email(user, stats: dict, highlights: dict, frontend_url: str): """Send the weekly digest email to a user""" from services.email_service import email_service subject = "Your Weekly Elmeg Digest" # Build activity section activity_items = [] if stats["shows_attended"] > 0: activity_items.append(f"šŸŽµ Attended {stats['shows_attended']} show{'s' if stats['shows_attended'] > 1 else ''}") if stats["reviews_written"] > 0: activity_items.append(f"āœļø Wrote {stats['reviews_written']} review{'s' if stats['reviews_written'] > 1 else ''}") if stats["ratings_given"] > 0: activity_items.append(f"⭐ Gave {stats['ratings_given']} rating{'s' if stats['ratings_given'] > 1 else ''}") if stats["chase_caught"] > 0: activity_items.append(f"šŸŽÆ Caught {stats['chase_caught']} chase song{'s' if stats['chase_caught'] > 1 else ''}!") activity_html = "" if activity_items: activity_html = "" else: activity_html = "

No activity this week. Get out there and catch some shows!

" html_content = f"""

Weekly Digest

Your Activity

{activity_html}

Community Highlights

Visit Elmeg

You're receiving this because you enabled weekly digests. Manage preferences

""" text_content = f""" Weekly Elmeg Digest YOUR ACTIVITY: - Attended {stats['shows_attended']} shows - Wrote {stats['reviews_written']} reviews - Gave {stats['ratings_given']} ratings - Caught {stats['chase_caught']} chase songs COMMUNITY HIGHLIGHTS: - {highlights['new_shows']} new shows added - {highlights['total_reviews']} reviews written Visit Elmeg: {frontend_url} To disable weekly digests, visit {frontend_url}/settings """ return email_service.send_email(user.email, subject, html_content, text_content) def send_weekly_digests(): """Main function to send all weekly digest emails""" print("=" * 60) print("WEEKLY DIGEST EMAIL SENDER") print("=" * 60) # Calculate date range (last 7 days) end_date = datetime.utcnow() start_date = end_date - timedelta(days=7) print(f"Period: {start_date.date()} to {end_date.date()}") from services.email_service import email_service frontend_url = email_service.frontend_url with Session(engine) as session: # Get community highlights (shared across all emails) highlights = get_community_highlights(session, start_date, end_date) print(f"Community stats: {highlights['new_shows']} shows, {highlights['total_reviews']} reviews") # Find all users with email_digest enabled users_with_digest = session.exec( select(User) .where(User.is_active == True) .where(User.email_verified == True) ).all() sent_count = 0 skipped_count = 0 for user in users_with_digest: # Check if user has digest enabled if not user.preferences or not user.preferences.email_digest: skipped_count += 1 continue # Get user's stats stats = get_weekly_stats(session, user.id, start_date, end_date) # Send the digest try: success = send_digest_email(user, stats, highlights, frontend_url) if success: sent_count += 1 print(f" āœ“ Sent to {user.email}") else: print(f" āœ— Failed for {user.email}") except Exception as e: print(f" āœ— Error for {user.email}: {e}") print(f"\nāœ“ Sent {sent_count} digest emails, skipped {skipped_count}") if __name__ == "__main__": send_weekly_digests()