File size: 4,823 Bytes
1abc143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5abadff
1abc143
 
 
 
 
 
 
 
 
5abadff
 
1abc143
5abadff
 
 
 
 
 
 
 
1abc143
5abadff
 
 
 
 
1abc143
5abadff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1abc143
5abadff
 
 
 
 
 
 
1abc143
5abadff
 
 
 
1abc143
5abadff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1abc143
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/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")