""" Operation 1: Delete exact match contacts from Temp folder (1,792 contacts) """ import json import subprocess import time import urllib.parse TENANT_ID = "dd4a82e8-85a3-44ac-8800-07945ab4d95f" CLIENT_ID = "fabb3421-8b34-484b-bc17-e46de9703418" CLIENT_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO" SCOPE = "https://graph.microsoft.com/.default" USER = "barbara@bardach.net" DATA_FILE = "D:/ClaudeTools/temp/bardach_temp_vs_main.json" OUTPUT_FILE = "D:/ClaudeTools/temp/bardach_op1_delete_exact.json" def get_token(): url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token" data = ( f"client_id={CLIENT_ID}" f"&scope={urllib.parse.quote(SCOPE)}" f"&client_secret={urllib.parse.quote(CLIENT_SECRET)}" f"&grant_type=client_credentials" ) result = subprocess.run( ["curl", "-s", "-X", "POST", url, "-H", "Content-Type: application/x-www-form-urlencoded", "-d", data], capture_output=True, text=True ) resp = json.loads(result.stdout) if "access_token" not in resp: print(f"[ERROR] Token acquisition failed: {resp}") raise Exception("Failed to get token") print("[OK] Token acquired") return resp["access_token"] def delete_contact(token, contact_id): url = f"https://graph.microsoft.com/v1.0/users/{USER}/contacts/{contact_id}" result = subprocess.run( ["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "-X", "DELETE", url, "-H", f"Authorization: Bearer {token}"], capture_output=True, text=True ) return result.stdout.strip() def main(): print("=" * 60) print("OPERATION 1: Delete exact matches from Temp (1,792 contacts)") print("=" * 60) with open(DATA_FILE, "r") as f: data = json.load(f) exact_matches = data["exact_matches"] total = len(exact_matches) print(f"[INFO] Loaded {total} exact matches to delete") token = get_token() successes = [] failures = [] start_time = time.time() for i, contact in enumerate(exact_matches): # Re-acquire token every 500 operations if i > 0 and i % 500 == 0: print(f"[INFO] Re-acquiring token at operation {i}...") token = get_token() temp_id = contact["temp_id"] status_code = delete_contact(token, temp_id) if status_code in ("204", "200"): successes.append({"temp_id": temp_id, "displayName": contact.get("displayName", "")}) else: failures.append({"temp_id": temp_id, "displayName": contact.get("displayName", ""), "status": status_code}) # Progress every 100 if (i + 1) % 100 == 0 or (i + 1) == total: elapsed = time.time() - start_time rate = (i + 1) / elapsed if elapsed > 0 else 0 print(f" [{i+1}/{total}] OK={len(successes)} FAIL={len(failures)} ({rate:.1f}/sec)") elapsed = time.time() - start_time results = { "operation": "delete_exact_matches", "total": total, "successes": len(successes), "failures": len(failures), "elapsed_seconds": round(elapsed, 1), "failed_contacts": failures } with open(OUTPUT_FILE, "w") as f: json.dump(results, f, indent=2) print(f"\n[SUCCESS] Operation 1 complete") print(f" Deleted: {len(successes)}/{total}") print(f" Failed: {len(failures)}/{total}") print(f" Time: {elapsed:.1f}s") print(f" Results: {OUTPUT_FILE}") if __name__ == "__main__": main()