Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """ | |
| One-time Backfill Script: Send notifications for existing listings matching alerts. | |
| This script: | |
| 1. Fetches all active search_alerts | |
| 2. Fetches all published listings | |
| 3. Checks each listing against each alert | |
| 4. Sends DM notifications for matches (avoiding duplicates) | |
| Usage: | |
| cd python-Backend/lojiz-backend/AIDA | |
| python -m scripts.backfill_alerts | |
| Or run as standalone: | |
| python scripts/backfill_alerts.py | |
| """ | |
| import asyncio | |
| import sys | |
| import os | |
| # Add parent directory to path for imports | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from datetime import datetime | |
| from typing import List, Dict, Any | |
| async def run_backfill(): | |
| """Main backfill function.""" | |
| # Import after path setup | |
| from app.database import get_db, connect_db, disconnect_db | |
| from app.models.search_alert import SearchAlert | |
| from app.services.alert_service import check_listing_matches_alert, notify_user_of_match | |
| print("="*60) | |
| print(" ALERT BACKFILL SCRIPT") | |
| print("="*60) | |
| print(f"Started at: {datetime.now().isoformat()}") | |
| print() | |
| # Initialize DB Connection | |
| await connect_db() | |
| try: | |
| db = await get_db() | |
| # 1. Fetch all active alerts | |
| print(" Fetching active search alerts...") | |
| alerts_cursor = db.search_alerts.find({"is_active": True}) | |
| alerts = [SearchAlert(**doc) async for doc in alerts_cursor] | |
| print(f" Found {len(alerts)} active alerts") | |
| if not alerts: | |
| print(" No active alerts found. Nothing to backfill.") | |
| return | |
| # Print alert summary | |
| for alert in alerts: | |
| print(f" - User {alert.user_id}: '{alert.user_query}'") | |
| print() | |
| # 2. Fetch all published listings | |
| print(" Fetching published listings...") | |
| listings_cursor = db.listings.find({"status": "active"}) | |
| listings = await listings_cursor.to_list(length=1000) # Limit for safety | |
| print(f" Found {len(listings)} active listings") | |
| print() | |
| if not listings: | |
| print(" No active listings found. Nothing to match.") | |
| return | |
| # 3. Check each listing against each alert | |
| print(" Checking matches...") | |
| matches_found = 0 | |
| notifications_sent = 0 | |
| skipped_duplicates = 0 | |
| for listing in listings: | |
| listing_id = str(listing["_id"]) | |
| listing_title = listing.get("title", "Untitled") | |
| listing_location = listing.get("location", "Unknown") | |
| for alert in alerts: | |
| # Check if this alert already received notification for this listing | |
| # (We store notified listing IDs in alert to prevent duplicate notifications) | |
| notified_listings = alert.notified_listing_ids or [] | |
| if listing_id in notified_listings: | |
| skipped_duplicates += 1 | |
| continue | |
| # Check if listing matches alert criteria | |
| if await check_listing_matches_alert(listing, alert): | |
| matches_found += 1 | |
| print(f" MATCH: '{listing_title}' ({listing_location}) -> User {alert.user_id}") | |
| try: | |
| # Send notification | |
| await notify_user_of_match(alert, listing) | |
| notifications_sent += 1 | |
| # Mark listing as notified for this alert (prevent duplicates) | |
| await db.search_alerts.update_one( | |
| {"_id": alert.id}, | |
| {"$addToSet": {"notified_listing_ids": listing_id}} | |
| ) | |
| print(f" Notification sent!") | |
| except Exception as e: | |
| print(f" Failed to notify: {e}") | |
| # 4. Summary | |
| print() | |
| print("="*60) | |
| print(" BACKFILL SUMMARY") | |
| print("="*60) | |
| print(f" Alerts processed: {len(alerts)}") | |
| print(f" Listings checked: {len(listings)}") | |
| print(f" Matches found: {matches_found}") | |
| print(f" Notifications sent: {notifications_sent}") | |
| print(f" Duplicates skipped: {skipped_duplicates}") | |
| print() | |
| print(f"Completed at: {datetime.now().isoformat()}") | |
| print("="*60) | |
| finally: | |
| await disconnect_db() | |
| if __name__ == "__main__": | |
| print("\n" + " Starting Alert Backfill Script..." + "\n") | |
| asyncio.run(run_backfill()) | |
| print("\n" + " Script completed!" + "\n") | |