Files
claudetools/temp/bardach_merge_delete_remaining.py
Mike Swanson fa15b03180 sync: Auto-sync from ACG-M-L5090 at 2026-03-10 19:11:00
Synced files:
- Quote wizard frontend (all components, hooks, types, config)
- API updates (config, models, routers, schemas, services)
- Client work (bg-builders, gurushow)
- Scripts (BGB Lesley termination, CIPP, Datto, migration)
- Temp files (Bardach contacts, VWP investigation, misc)
- Credentials and session logs
- Email service, PHP API, session logs

Machine: ACG-M-L5090
Timestamp: 2026-03-10 19:11:00

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 19:59:08 -07:00

162 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""
Bardach Contact Delete: Delete remaining Temp contacts.
Treats 404 as success (contact already gone).
Merges were already completed successfully (70/70).
"""
import json
import subprocess
import time
import sys
from datetime import datetime
sys.stdout.reconfigure(line_buffering=True)
sys.stderr.reconfigure(line_buffering=True)
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"
BASE_URL = f"https://graph.microsoft.com/v1.0/users/{USER}/contacts"
DATA_FILE = "D:/ClaudeTools/temp/bardach_temp_vs_main.json"
THROTTLE_DELAY = 0.25 # slightly faster since deletes are simple
def get_token():
url = f"https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token"
cmd = [
"curl", "-s", "-X", "POST", url,
"-H", "Content-Type: application/x-www-form-urlencoded",
"-d", f"client_id={CLIENT_ID}&scope={SCOPE}&client_secret={CLIENT_SECRET}&grant_type=client_credentials"
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
data = json.loads(result.stdout)
if "access_token" not in data:
print(f"[ERROR] Token failed: {data}")
sys.exit(1)
print(f"[OK] Token acquired at {datetime.now().strftime('%H:%M:%S')}")
return data["access_token"]
def api_delete(token, contact_id):
"""DELETE a contact. Returns status code as string."""
url = f"{BASE_URL}/{contact_id}"
cmd = [
"curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
"-X", "DELETE", url,
"-H", f"Authorization: Bearer {token}"
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
return result.stdout.strip()
def api_get(token, url):
cmd = [
"curl", "-s", "-X", "GET", url,
"-H", f"Authorization: Bearer {token}",
"-H", "Content-Type: application/json"
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
return json.loads(result.stdout)
# Load data
with open(DATA_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
matches = data["matches_with_extras"]
exact_matches = data.get("exact_matches", [])
all_temp_ids = []
for m in matches:
all_temp_ids.append((m["temp_id"], m["displayName"]))
for m in exact_matches:
all_temp_ids.append((m["temp_id"], m["displayName"]))
print(f"[INFO] Total Temp contacts to delete: {len(all_temp_ids)}")
token = get_token()
deleted_ok = 0
already_gone = 0
real_errors = 0
error_details = []
for i, (tid, name) in enumerate(all_temp_ids):
if i > 0 and i % 500 == 0:
token = get_token()
if i > 0 and i % 200 == 0:
print(f" [INFO] Progress {i}/{len(all_temp_ids)}: {deleted_ok} deleted, {already_gone} already gone, {real_errors} errors")
code = api_delete(token, tid)
time.sleep(THROTTLE_DELAY)
if code in ("204", "200"):
deleted_ok += 1
elif code == "404":
already_gone += 1
else:
real_errors += 1
if real_errors <= 10:
print(f" [ERROR] {name}: HTTP {code}")
error_details.append({"name": name, "code": code, "temp_id": tid})
print(f"\n[OK] Delete complete:")
print(f" Deleted now: {deleted_ok}")
print(f" Already gone: {already_gone}")
print(f" Errors: {real_errors}")
# Verification
print("\n" + "=" * 70)
print("VERIFICATION")
print("=" * 70)
token = get_token()
# Check Temp folder
folders_url = f"https://graph.microsoft.com/v1.0/users/{USER}/contactFolders?$filter=displayName eq 'Temp'"
folders_resp = api_get(token, folders_url)
time.sleep(0.5)
if "value" in folders_resp and folders_resp["value"]:
temp_folder_id = folders_resp["value"][0]["id"]
count_url = f"https://graph.microsoft.com/v1.0/users/{USER}/contactFolders/{temp_folder_id}/contacts?$top=1&$select=displayName&$count=true"
count_resp = api_get(token, count_url)
remaining = len(count_resp.get("value", []))
odata_count = count_resp.get("@odata.count", "N/A")
has_more = "@odata.nextLink" in count_resp
print(f" Temp folder: odata.count={odata_count}, first page={remaining}, has_more={has_more}")
if remaining > 0:
print(f" First remaining: {count_resp['value'][0].get('displayName', '?')}")
else:
print(f" Temp folder: not found or empty")
# Check Main contacts
main_count_url = f"{BASE_URL}?$top=1&$select=displayName&$count=true"
main_resp = api_get(token, main_count_url)
main_odata = main_resp.get("@odata.count", "N/A")
print(f" Main contacts: odata.count={main_odata}")
# Save results
results = {
"timestamp": datetime.now().isoformat(),
"merge_step": "Completed previously: 70/70 patches successful",
"deletes": {
"total_attempted": len(all_temp_ids),
"deleted_now": deleted_ok,
"already_gone": already_gone,
"errors": real_errors,
"error_samples": error_details[:20],
},
"verification": {
"temp_odata_count": str(odata_count) if 'odata_count' in dir() else "N/A",
"main_odata_count": str(main_odata),
}
}
with open("D:/ClaudeTools/temp/bardach_merge_results.json", "w", encoding="utf-8") as f:
json.dump(results, f, indent=2, default=str)
print(f"\n[OK] Results saved to bardach_merge_results.json")