102 lines
3.5 KiB
Python
102 lines
3.5 KiB
Python
|
|
"""Clear all three UFC documents, after saving local copies.
|
||
|
|
|
||
|
|
The user asked to remove every document from the UFC resolution:
|
||
|
|
1. ysterbaard_resolutions.signed_letter
|
||
|
|
2. ysterbaard_director_resignations.letter
|
||
|
|
3. ysterbaard_director_resignations.signature
|
||
|
|
|
||
|
|
PocketBase file deletion is irreversible, so the bytes are copied into
|
||
|
|
scripts/_backup_ufc_docs/ first. This script never deletes the record itself —
|
||
|
|
only the file fields, which is what "remove the documents" means here.
|
||
|
|
"""
|
||
|
|
import io
|
||
|
|
import json
|
||
|
|
import urllib.error
|
||
|
|
import urllib.parse
|
||
|
|
import urllib.request
|
||
|
|
from pathlib import Path
|
||
|
|
from pypdf import PdfReader
|
||
|
|
|
||
|
|
JEI = Path(r"C:\Users\SJ\.minimax-agent\projects\JEI")
|
||
|
|
WORKFLOW = Path(r"C:\Users\SJ\.minimax-agent\projects\Workflow")
|
||
|
|
BACKUP = WORKFLOW / "scripts" / "_backup_ufc_docs"
|
||
|
|
|
||
|
|
env = {}
|
||
|
|
for line in (JEI / ".env.local").read_text(encoding="utf-8").splitlines():
|
||
|
|
line = line.strip()
|
||
|
|
if line and not line.startswith("#") and "=" in line:
|
||
|
|
k, v = line.split("=", 1)
|
||
|
|
env[k.strip()] = v.strip().strip('"').strip("'")
|
||
|
|
PB = env.get("NEXT_PUBLIC_PB_URL") or env["PB_URL"]
|
||
|
|
TOK = env["PB_TOKEN"]
|
||
|
|
|
||
|
|
TARGETS = [
|
||
|
|
("pbc_266170881", "e0dbxprazb70rqx", "signed_letter", "resolution_signed_letter"),
|
||
|
|
("ysterbaard_director_resignations", "8cfie18uhgy0n0o", "letter", "resignation_letter"),
|
||
|
|
("ysterbaard_director_resignations", "8cfie18uhgy0n0o", "signature", "resignation_signature"),
|
||
|
|
]
|
||
|
|
|
||
|
|
APPLY = "--apply" in __import__("sys").argv
|
||
|
|
|
||
|
|
|
||
|
|
def req(url, method="GET", body=None, ctype="application/json"):
|
||
|
|
r = urllib.request.Request(url, data=body, method=method,
|
||
|
|
headers={"Authorization": TOK, "Content-Type": ctype})
|
||
|
|
try:
|
||
|
|
with urllib.request.urlopen(r, timeout=120) as resp:
|
||
|
|
return resp.status, resp.read()
|
||
|
|
except urllib.error.HTTPError as e:
|
||
|
|
return e.code, e.read()
|
||
|
|
|
||
|
|
|
||
|
|
BACKUP.mkdir(parents=True, exist_ok=True)
|
||
|
|
|
||
|
|
for col, rid, field, label in TARGETS:
|
||
|
|
status, raw = req(f"{PB}/api/collections/{col}/records/{rid}")
|
||
|
|
rec = json.loads(raw)
|
||
|
|
fname = rec.get(field)
|
||
|
|
if not fname:
|
||
|
|
print(f"{label}: already empty")
|
||
|
|
continue
|
||
|
|
|
||
|
|
# 1) Back the bytes up locally.
|
||
|
|
furl = f"{PB}/api/files/{col}/{rid}/{urllib.parse.quote(fname)}"
|
||
|
|
status, blob = req(furl)
|
||
|
|
if status == 200:
|
||
|
|
out = BACKUP / f"{label}_{fname}"
|
||
|
|
out.write_bytes(blob)
|
||
|
|
try:
|
||
|
|
rd = PdfReader(io.BytesIO(blob))
|
||
|
|
imgs = sum(len(p.images) for p in rd.pages)
|
||
|
|
pages = len(rd.pages)
|
||
|
|
except Exception:
|
||
|
|
imgs, pages = "?", "?"
|
||
|
|
print(f"{label}: backed up {len(blob)} B -> {out.name} (pages={pages}, signature_images={imgs})")
|
||
|
|
else:
|
||
|
|
print(f"{label}: BACKUP FAILED HTTP {status} — aborting, nothing cleared")
|
||
|
|
raise SystemExit(1)
|
||
|
|
|
||
|
|
if not APPLY:
|
||
|
|
print(f" (dry run) would clear {field} on {col}/{rid}")
|
||
|
|
continue
|
||
|
|
|
||
|
|
# 2) Clear the file field.
|
||
|
|
status, raw = req(
|
||
|
|
f"{PB}/api/collections/{col}/records/{rid}",
|
||
|
|
method="PATCH",
|
||
|
|
body=json.dumps({field: ""}).encode(),
|
||
|
|
)
|
||
|
|
if status != 200:
|
||
|
|
print(f" FAILED to clear {field}: HTTP {status} {raw[:200]}")
|
||
|
|
continue
|
||
|
|
now = json.loads(raw).get(field)
|
||
|
|
print(f" cleared {field} -> {now!r}")
|
||
|
|
|
||
|
|
if not APPLY:
|
||
|
|
print("\nDRY RUN — re-run with --apply")
|
||
|
|
else:
|
||
|
|
print("\n=== final state ===")
|
||
|
|
for col, rid, field, label in TARGETS:
|
||
|
|
_, raw = req(f"{PB}/api/collections/{col}/records/{rid}")
|
||
|
|
print(f" {label:26s} {field:15s} = {json.loads(raw).get(field)!r}")
|
||
|
|
print(f"\nlocal backups in: {BACKUP}")
|