""" delete_shadow_users.py ====================== One-time utility to wipe all shadow users (and their listings) from MongoDB. Run from the AIDA/ directory: python scripts/delete_shadow_users.py Pass --dry-run to preview what would be deleted without actually deleting: python scripts/delete_shadow_users.py --dry-run """ import asyncio import logging import os import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from app.database import connect_db, get_db, disconnect_db logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") logger = logging.getLogger(__name__) DRY_RUN = "--dry-run" in sys.argv async def run(): await connect_db() try: db = await get_db() # ── 1. Find all shadow users ────────────────────────────────────── shadow_cursor = db.users.find( {"account_type": "shadow"}, {"_id": 1, "display_name": 1, "whatsapp_number": 1}, ) shadow_users = await shadow_cursor.to_list(length=None) if not shadow_users: logger.info("No shadow users found — nothing to delete.") return logger.info(f"Found {len(shadow_users)} shadow user(s):") for u in shadow_users: logger.info( f" • {u.get('display_name', '—')} | {u.get('whatsapp_number', '—')} | id={u['_id']}" ) if DRY_RUN: logger.info("\n[DRY RUN] No changes made. Remove --dry-run to execute.") return # ── 2. Collect their IDs ────────────────────────────────────────── ids = [str(u["_id"]) for u in shadow_users] # ── 3. Delete their listings ───────────────────────────────────── listings_result = await db.listings.delete_many({"owner_id": {"$in": ids}}) logger.info(f"Deleted {listings_result.deleted_count} listing(s) owned by shadow users.") # ── 4. Delete the shadow users themselves ───────────────────────── from bson import ObjectId oids = [u["_id"] for u in shadow_users] users_result = await db.users.delete_many({"_id": {"$in": oids}}) logger.info(f"Deleted {users_result.deleted_count} shadow user(s).") logger.info("\n✅ Done. All shadow users and their listings have been removed.") finally: await disconnect_db() if __name__ == "__main__": asyncio.run(run())