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>
This commit is contained in:
161
temp/bardach_merge_delete_remaining.py
Normal file
161
temp/bardach_merge_delete_remaining.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/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")
|
||||
Reference in New Issue
Block a user