"""Synthetic enterprise portal (runs ON THE EXECUTOR NODE, loopback only). Generic: driven by the scenario's portal/portal.json. Serves: login, document library (downloads from inputs/), record tables (HTML + JSON API), forms whose submissions are appended to out/portal_submissions.json. It never holds information absent from inputs/ (information constancy across arms). Usage: python -m wp42.portal --workspace --port [--token ]""" from __future__ import annotations import argparse, json, os, secrets, time from flask import Flask, request, redirect, send_from_directory, session, abort, jsonify, Response HTML = """{org} — Enterprise Portal

{org}


{body}""" def make_app(workspace: str) -> Flask: cfg = json.load(open(os.path.join(workspace, "portal", "portal.json"), encoding="utf-8")) app = Flask(__name__); app.secret_key = secrets.token_hex(16) inputs = os.path.join(workspace, "inputs"); out_dir = os.path.join(workspace, "out"); os.makedirs(out_dir, exist_ok=True) user = cfg.get("user", {"username": "analyst", "password": "analyst"}) records = cfg.get("records", {}); forms = {f["id"]: f for f in cfg.get("forms", [])} docs = cfg.get("documents", []) nav = "".join(f'{k.title()}' for k in records) def page(body): return HTML.format(org=cfg.get("org", "Portal"), nav=nav, body=body) def authed(): return session.get("u") == user["username"] @app.before_request def _gate(): if request.path.startswith(("/login", "/static", "/health")): return None if not authed(): return redirect("/login") @app.route("/health") def health(): return jsonify({"ok": True, "org": cfg.get("org"), "documents": len(docs), "records": {k: len(v) for k, v in records.items()}, "forms": list(forms)}) @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": if request.form.get("username") == user["username"] and request.form.get("password") == user["password"]: session["u"] = user["username"]; return redirect("/") return page("

Invalid credentials.

" + LOGIN), 401 return page(LOGIN) @app.route("/logout") def logout(): session.clear(); return redirect("/login") @app.route("/") def home(): return page(f"

Welcome, {user['username']}. {cfg.get('welcome', '')}

  • Document library ({len(docs)} documents)
  • " + "".join(f"
  • {k} ({len(v)} records)
  • " for k, v in records.items()) + f"
  • Forms ({len(forms)})
") @app.route("/documents") def documents(): rows = "".join(f"{d['id']}{d['title']}{d.get('category', '')}" for d in docs) return page(f"

Document library

{rows}
IDTitleCategory
") @app.route("/documents//download") def download(doc_id): d = next((x for x in docs if x["id"] == doc_id), None) if not d: abort(404) rel = d["path"]; full = os.path.normpath(os.path.join(inputs, rel)) if not full.startswith(os.path.normpath(inputs)): abort(403) return send_from_directory(os.path.dirname(full), os.path.basename(full), as_attachment=True) @app.route("/api/documents") def api_docs(): return jsonify(docs) @app.route("/records/") def rec_html(entity): rows = records.get(entity) if rows is None: abort(404) cols = list(rows[0].keys()) if rows else [] body = "".join("" + "".join(f"{r.get(c, '')}" for c in cols) + "" for r in rows[:2000]) return page(f"

{entity}

JSON: /api/{entity}

" + "".join(f"" for c in cols) + f"{body}
{c}
") @app.route("/api/") def rec_json(entity): if entity not in records: abort(404) return jsonify(records[entity]) @app.route("/forms") def forms_index(): return page("

Forms

") @app.route("/forms/", methods=["GET", "POST"]) def form(form_id): f = forms.get(form_id) if not f: abort(404) if request.method == "POST": data = request.get_json(silent=True) or {k: v for k, v in request.form.items()} rec = {"form_id": form_id, "submitted_utc": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), "data": data} p = os.path.join(out_dir, "portal_submissions.json") cur = json.load(open(p)) if os.path.exists(p) else [] cur.append(rec); json.dump(cur, open(p, "w"), indent=1) if request.is_json: return jsonify({"ok": True, "submission": rec}) return page(f"

{f['title']}

Submission recorded.

{json.dumps(rec, indent=1)}
") fields = "".join(f"

" for x in f["fields"]) return page(f"

{f['title']}

{fields}

API: POST JSON to this URL.

") return app LOGIN = "

Sign in

" def main(): ap = argparse.ArgumentParser(); ap.add_argument("--workspace", required=True); ap.add_argument("--port", type=int, required=True) a = ap.parse_args() app = make_app(a.workspace) app.run(host="127.0.0.1", port=a.port, debug=False, use_reloader=False, threaded=True) if __name__ == "__main__": main()