""" Final Verification: Count remaining Temp contacts and summarize all operations. """ import json import subprocess 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" TEMP_FOLDER_ID = None # Will be resolved dynamically 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") return resp["access_token"] def count_temp_contacts(token): """Count contacts in Temp folder using $count.""" url = ( f"https://graph.microsoft.com/v1.0/users/{USER}" f"/contactFolders/{TEMP_FOLDER_ID}/contacts?$count=true&$top=1&$select=id" ) result = subprocess.run( ["curl", "-s", "-X", "GET", url, "-H", f"Authorization: Bearer {token}", "-H", "ConsistencyLevel: eventual"], capture_output=True, text=True ) resp = json.loads(result.stdout) count = resp.get("@odata.count") if count is not None: return count # Fallback: page through all print("[INFO] @odata.count not available, paging through contacts...") total = 0 page_url = ( f"https://graph.microsoft.com/v1.0/users/{USER}" f"/contactFolders/{TEMP_FOLDER_ID}/contacts?$top=100&$select=id" ) while page_url: result = subprocess.run( ["curl", "-s", "-X", "GET", page_url, "-H", f"Authorization: Bearer {token}"], capture_output=True, text=True ) resp = json.loads(result.stdout) contacts = resp.get("value", []) total += len(contacts) page_url = resp.get("@odata.nextLink") if total % 500 == 0 and total > 0: print(f" ...counted {total} so far") return total def main(): print("=" * 60) print("FINAL VERIFICATION") print("=" * 60) token = get_token() print("[OK] Token acquired") # Find Temp folder ID global TEMP_FOLDER_ID url = f"https://graph.microsoft.com/v1.0/users/{USER}/contactFolders" result = subprocess.run( ["curl", "-s", "-X", "GET", url, "-H", f"Authorization: Bearer {token}"], capture_output=True, text=True ) folders = json.loads(result.stdout).get("value", []) for f in folders: if "temp" in f.get("displayName", "").lower(): TEMP_FOLDER_ID = f["id"] print(f"[INFO] Found Temp folder: '{f['displayName']}' -> {TEMP_FOLDER_ID[:40]}...") break if not TEMP_FOLDER_ID: print("[ERROR] Could not find Temp contact folder!") for f in folders: print(f" Folder: {f.get('displayName')} -> {f['id'][:40]}...") return # Count remaining Temp contacts print("\n[INFO] Counting remaining Temp contacts...") remaining = count_temp_contacts(token) print(f"[INFO] Remaining Temp contacts: {remaining}") print(f"[INFO] Expected: ~3,888 (matches_with_extras)") # Load operation results print("\n--- OPERATION SUMMARIES ---") for op_file, label in [ ("D:/ClaudeTools/temp/bardach_op1_delete_exact.json", "Op1: Delete Exact Matches"), ("D:/ClaudeTools/temp/bardach_op2_move_unique.json", "Op2: Move Unique Contacts"), ("D:/ClaudeTools/temp/bardach_op3_delete_blank.json", "Op3: Delete Blank Contacts"), ]: try: with open(op_file, "r") as f: r = json.load(f) print(f"\n {label}:") print(f" Total: {r['total']}") print(f" Successes: {r['successes']}") print(f" Failures: {r['failures']}") if r.get("elapsed_seconds"): print(f" Time: {r['elapsed_seconds']}s") if r.get("method"): print(f" Method: {r['method']}") except FileNotFoundError: print(f"\n {label}: [NOT FOUND] {op_file}") except Exception as e: print(f"\n {label}: [ERROR] {e}") print(f"\n{'=' * 60}") print(f"Remaining Temp contacts: {remaining}") diff = remaining - 3888 if abs(diff) < 10: print(f"[OK] Close to expected (~3,888), difference: {diff}") else: print(f"[WARNING] Difference from expected (3,888): {diff}") print("=" * 60) if __name__ == "__main__": main()