Adds the full Next.js app (app/, components/, lib/, scripts/, assets/, docs/, Dockerfile, compose, configs) to version control. Security: - CIPC BizPortal customer-code logins (Login 1 + Login 3) now read CIPC_LOGIN1_CODE / CIPC_LOGIN1_PASSWORD / CIPC_LOGIN3_CODE / CIPC_LOGIN3_PASSWORD from .env.local instead of source. - BizPortal personal login in apply-bizportal route reads BIZPORTAL_ID_NO / BIZPORTAL_PASSWORD. - Added .env.example as the committed template. .gitignore excludes .env*, node_modules, .next, logs, sqlite, Playwright storage_state.json (live CIPC cookies), scratch dirs, client PDFs and debug screenshots.
61 lines
No EOL
2.3 KiB
Python
61 lines
No EOL
2.3 KiB
Python
"""Replace the blank regenerated template with the genuinely signed resolution.
|
|
|
|
Uses the app's own upload endpoint so the same MIME/size validation and filename
|
|
handling apply as when the operator uploads from the UI.
|
|
"""
|
|
import json
|
|
import mimetypes
|
|
import urllib.request
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
BASE = "http://localhost:6001"
|
|
SRC = Path(
|
|
r"C:\Users\SJ\.minimax\v2\assets\2026\10\12\13-41-56-012-asset_20261012-134156-012_a0299b3ae338_88b7c484-UFC - Shareholders Resolution Director Sune Resigned.pdf"
|
|
)
|
|
|
|
TARGETS = [
|
|
("ysterbaard_resolutions", "e0dbxprazb70rqx", "signed_letter"),
|
|
("ysterbaard_director_resignations", "8cfie18uhgy0n0o", "signature"),
|
|
]
|
|
|
|
|
|
def post_file(url: str, path: Path, field: str = "file", upload_name: str | None = None):
|
|
boundary = uuid.uuid4().hex
|
|
# The source file on disk carries an asset-slug prefix; send a clean name so
|
|
# the stored file is recognisable in the PB admin UI and on the documents page.
|
|
filename = upload_name or path.name
|
|
ctype = mimetypes.guess_type(filename)[0] or "application/pdf"
|
|
body = b"".join([
|
|
f"--{boundary}\r\n".encode(),
|
|
f'Content-Disposition: form-data; name="{field}"; filename="{filename}"\r\n'.encode(),
|
|
f"Content-Type: {ctype}\r\n\r\n".encode(),
|
|
path.read_bytes(),
|
|
f"\r\n--{boundary}--\r\n".encode(),
|
|
])
|
|
req = urllib.request.Request(
|
|
url, data=body, method="POST",
|
|
headers={"Content-Type": f"multipart/form-data; boundary={boundary}"},
|
|
)
|
|
with urllib.request.urlopen(req, timeout=180) as r:
|
|
return json.loads(r.read().decode())
|
|
|
|
|
|
if not SRC.exists():
|
|
raise SystemExit(f"source file missing: {SRC}")
|
|
|
|
print(f"source: {SRC.name} ({SRC.stat().st_size} bytes)")
|
|
print()
|
|
|
|
CLEAN_NAME = "UFC - Shareholders Resolution Director Sune Resigned.pdf"
|
|
|
|
for collection, record_id, field in TARGETS:
|
|
url = f"{BASE}/api/resolutions/{record_id}/upload?collection={collection}&field={field}"
|
|
try:
|
|
res = post_file(url, SRC, upload_name=CLEAN_NAME)
|
|
print(f"OK {collection}.{field}")
|
|
print(f" stored as: {res.get('stored')}")
|
|
print(f" bytes: {res.get('bytes')}")
|
|
except urllib.error.HTTPError as e:
|
|
print(f"FAIL {collection}.{field}: HTTP {e.code} {e.read().decode()[:300]}")
|
|
print() |