Initial
This commit is contained in:
21
.env
Normal file
21
.env
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Flask
|
||||||
|
FLASK_SECRET_KEY=replace-with-long-random-string
|
||||||
|
|
||||||
|
# Firebase Admin (choose ONE of these approaches)
|
||||||
|
# 1) Path to JSON creds file
|
||||||
|
GOOGLE_APPLICATION_CREDENTIALS=./rothbard-service-account.json
|
||||||
|
# 2) Or inline JSON (escaped as single line)
|
||||||
|
# FIREBASE_SERVICE_ACCOUNT_JSON={"type":"service_account",...}
|
||||||
|
|
||||||
|
# Filevine auth
|
||||||
|
FILEVINE_CLIENT_ID=4F18738C-107A-4B82-BFAC-308F1B6A626A
|
||||||
|
FILEVINE_CLIENT_SECRET=*2{aXWvYN(9!BiYUXC_tXj^n8
|
||||||
|
FILEVINE_PERSONAL_ACCESS_TOKEN=B87C144C35A570077F9D7D70CDC2280DD023142D1BFCE2C45B6CE8934600EA6F
|
||||||
|
FILEVINE_ORG_ID=9227
|
||||||
|
FILEVINE_USER_ID=100510
|
||||||
|
|
||||||
|
# Front-end Firebase (public — safe to expose)
|
||||||
|
FIREBASE_API_KEY=AIzaSyC7t2D0uSuc1hm6ZEkfUMVPtkaE2TXF1a0
|
||||||
|
FIREBASE_AUTH_DOMAIN=rothbard-3f496.firebaseapp.com
|
||||||
|
FIREBASE_PROJECT_ID=rothbard-3f496
|
||||||
|
FIREBASE_APP_ID=1:90016977941:web:da38d57849021115e52a1c
|
||||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.venv/**
|
||||||
|
.lsp/**
|
||||||
|
.clj-kondo/**
|
||||||
|
|
||||||
|
|
||||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
Rothbard Client Portal
|
||||||
|
|
||||||
|
This is a server-side rendered client portal for rothbard law group. Users can log in, and once they've been configured, can see a list of cases from the filevine API.
|
||||||
|
|
||||||
|
Todo list
|
||||||
|
* Lock down firebase
|
||||||
|
* Set firebase up with terraform
|
||||||
|
* Allow users to store their preferences on which columns they see
|
||||||
|
* Styling
|
||||||
|
* New user sign up
|
||||||
|
* Set up users
|
||||||
|
|
||||||
|
|
||||||
|
Project Structure:
|
||||||
|
* static/ - static assets, html, javascript etc
|
||||||
|
* templates/ jinja templates
|
||||||
|
* app.py - core login
|
||||||
|
* examples/ sample filevine api requests/responses for digging into
|
||||||
|
* generate_sample.py - generates the examples
|
||||||
270
app.py
Normal file
270
app.py
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
from functools import wraps
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from flask import Flask, render_template, request, redirect, url_for, session, abort, jsonify
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import firebase_admin
|
||||||
|
from firebase_admin import credentials, auth as fb_auth, firestore
|
||||||
|
import requests
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.secret_key = os.environ.get("FLASK_SECRET_KEY", os.urandom(32))
|
||||||
|
|
||||||
|
# --- Firebase Admin init ---
|
||||||
|
_creds = None
|
||||||
|
json_inline = os.environ.get("FIREBASE_SERVICE_ACCOUNT_JSON")
|
||||||
|
file_path = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
|
||||||
|
if json_inline:
|
||||||
|
_creds = credentials.Certificate(json.loads(json_inline))
|
||||||
|
elif file_path and os.path.exists(file_path):
|
||||||
|
_creds = credentials.Certificate(file_path)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Firebase credentials not configured. Set GOOGLE_APPLICATION_CREDENTIALS or FIREBASE_SERVICE_ACCOUNT_JSON.")
|
||||||
|
|
||||||
|
firebase_admin.initialize_app(_creds)
|
||||||
|
db = firestore.client()
|
||||||
|
|
||||||
|
# --- Filevine env ---
|
||||||
|
FV_CLIENT_ID = os.environ.get("FILEVINE_CLIENT_ID")
|
||||||
|
FV_CLIENT_SECRET = os.environ.get("FILEVINE_CLIENT_SECRET")
|
||||||
|
FV_PAT = os.environ.get("FILEVINE_PERSONAL_ACCESS_TOKEN")
|
||||||
|
FV_ORG_ID = os.environ.get("FILEVINE_ORG_ID")
|
||||||
|
FV_USER_ID = os.environ.get("FILEVINE_USER_ID")
|
||||||
|
|
||||||
|
if not all([FV_CLIENT_ID, FV_CLIENT_SECRET, FV_PAT, FV_ORG_ID, FV_USER_ID]):
|
||||||
|
print("[WARN] Missing one or more Filevine env vars — dashboard will fail until set.")
|
||||||
|
|
||||||
|
# --- Helpers ---
|
||||||
|
|
||||||
|
def login_required(view):
|
||||||
|
@wraps(view)
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
uid = session.get("uid")
|
||||||
|
if not uid:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
return view(*args, **kwargs)
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_profile(uid: str):
|
||||||
|
"""Fetch user's Firestore profile: users/{uid} => { enabled, caseEmail }"""
|
||||||
|
doc_ref = db.collection("users").document(uid)
|
||||||
|
snap = doc_ref.get()
|
||||||
|
if not snap.exists:
|
||||||
|
# bootstrap a placeholder doc so admins can fill it in
|
||||||
|
doc_ref.set({"enabled": False}, merge=True)
|
||||||
|
return {"enabled": False, "caseEmail": None}
|
||||||
|
data = snap.to_dict() or {}
|
||||||
|
return {"enabled": bool(data.get("enabled", False)), "caseEmail": data.get("caseEmail")}
|
||||||
|
|
||||||
|
|
||||||
|
# --- Routes ---
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
uid = session.get("uid")
|
||||||
|
if not uid:
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
profile = get_user_profile(uid)
|
||||||
|
if profile.get("enabled") and profile.get("caseEmail"):
|
||||||
|
return redirect(url_for("dashboard"))
|
||||||
|
return redirect(url_for("welcome"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/login")
|
||||||
|
def login():
|
||||||
|
# Pass public Firebase config to template
|
||||||
|
fb_public = {
|
||||||
|
"apiKey": os.environ.get("FIREBASE_API_KEY", ""),
|
||||||
|
"authDomain": os.environ.get("FIREBASE_AUTH_DOMAIN", ""),
|
||||||
|
"projectId": os.environ.get("FIREBASE_PROJECT_ID", ""),
|
||||||
|
"appId": os.environ.get("FIREBASE_APP_ID", ""),
|
||||||
|
}
|
||||||
|
return render_template("login.html", firebase_config=fb_public)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/session_login", methods=["POST"])
|
||||||
|
def session_login():
|
||||||
|
"""Exchanges Firebase ID token for a server session."""
|
||||||
|
id_token = request.json.get("idToken") if request.is_json else request.form.get("idToken")
|
||||||
|
if not id_token:
|
||||||
|
abort(400, "Missing idToken")
|
||||||
|
try:
|
||||||
|
decoded = fb_auth.verify_id_token(id_token)
|
||||||
|
uid = decoded["uid"]
|
||||||
|
session.clear()
|
||||||
|
session["uid"] = uid
|
||||||
|
# Optional: short session
|
||||||
|
session["expires_at"] = (datetime.utcnow() + timedelta(hours=8)).isoformat()
|
||||||
|
return jsonify({"ok": True})
|
||||||
|
except Exception as e:
|
||||||
|
print("[ERR] session_login:", e)
|
||||||
|
abort(401, "Invalid ID token")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/logout")
|
||||||
|
def logout():
|
||||||
|
session.clear()
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/welcome")
|
||||||
|
@login_required
|
||||||
|
def welcome():
|
||||||
|
uid = session.get("uid")
|
||||||
|
profile = get_user_profile(uid)
|
||||||
|
return render_template("welcome.html", profile=profile)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Filevine API ---
|
||||||
|
|
||||||
|
def get_filevine_bearer():
|
||||||
|
url = "https://identity.filevine.com/connect/token"
|
||||||
|
data = {
|
||||||
|
"client_id": FV_CLIENT_ID,
|
||||||
|
"client_secret": FV_CLIENT_SECRET,
|
||||||
|
"grant_type": "personal_access_token",
|
||||||
|
"scope": "fv.api.gateway.access tenant filevine.v2.api.* email openid fv.auth.tenant.read",
|
||||||
|
"token": FV_PAT,
|
||||||
|
}
|
||||||
|
headers = {"Accept": "application/json"}
|
||||||
|
resp = requests.post(url, data=data, headers=headers, timeout=30)
|
||||||
|
resp.raise_for_status()
|
||||||
|
js = resp.json()
|
||||||
|
print(js)
|
||||||
|
return js.get("access_token")
|
||||||
|
|
||||||
|
|
||||||
|
def list_all_projects(bearer: str):
|
||||||
|
base = "https://api.filevineapp.com/fv-app/v2/Projects"
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {bearer}",
|
||||||
|
"x-fv-orgid": str(FV_ORG_ID),
|
||||||
|
"x-fv-userid": str(FV_USER_ID),
|
||||||
|
}
|
||||||
|
print(headers)
|
||||||
|
results = []
|
||||||
|
last_id = None
|
||||||
|
tries = 0
|
||||||
|
while True:
|
||||||
|
tries += 1
|
||||||
|
url = base
|
||||||
|
params = {}
|
||||||
|
if last_id is not None:
|
||||||
|
# Some deployments use LastID/Offset pagination; adapt if needed
|
||||||
|
params["lastID"] = last_id
|
||||||
|
r = requests.get(url, headers=headers, params=params, timeout=30)
|
||||||
|
print(r.content)
|
||||||
|
r.raise_for_status()
|
||||||
|
page = r.json()
|
||||||
|
items = page.get("items", [])
|
||||||
|
results.extend(items)
|
||||||
|
has_more = page.get("hasMore")
|
||||||
|
last_id = page.get("lastID")
|
||||||
|
if not has_more:
|
||||||
|
break
|
||||||
|
# Safety valve
|
||||||
|
if tries > 200:
|
||||||
|
break
|
||||||
|
print("RESULTS", results)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_project_detail(bearer: str, project_id_native: int):
|
||||||
|
url = f"https://api.filevineapp.com/fv-app/v2/Projects/{project_id_native}"
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {bearer}",
|
||||||
|
"x-fv-orgid": str(FV_ORG_ID),
|
||||||
|
"x-fv-userid": str(FV_USER_ID),
|
||||||
|
}
|
||||||
|
r = requests.get(url, headers=headers, timeout=30)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def fetch_client(bearer: str, client_id_native: int):
|
||||||
|
url = f"https://api.filevineapp.com/fv-app/v2/contacts/{client_id_native}"
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {bearer}",
|
||||||
|
"x-fv-orgid": str(FV_ORG_ID),
|
||||||
|
"x-fv-userid": str(FV_USER_ID),
|
||||||
|
}
|
||||||
|
r = requests.get(url, headers=headers, timeout=30)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
def fetch_contacts(bearer: str, project_id_native: int):
|
||||||
|
url = f"https://api.filevineapp.com/fv-app/v2/projects/{project_id_native}/contacts"
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {bearer}",
|
||||||
|
"x-fv-orgid": str(FV_ORG_ID),
|
||||||
|
"x-fv-userid": str(FV_USER_ID),
|
||||||
|
}
|
||||||
|
r = requests.get(url, headers=headers, timeout=30)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json().get("items")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/dashboard")
|
||||||
|
@login_required
|
||||||
|
def dashboard():
|
||||||
|
uid = session.get("uid")
|
||||||
|
profile = get_user_profile(uid)
|
||||||
|
if not profile.get("enabled"):
|
||||||
|
return redirect(url_for("welcome"))
|
||||||
|
case_email = profile.get("caseEmail")
|
||||||
|
if not case_email:
|
||||||
|
return redirect(url_for("welcome"))
|
||||||
|
|
||||||
|
# 1) Bearer token
|
||||||
|
bearer = get_filevine_bearer()
|
||||||
|
|
||||||
|
# 2) List projects (all pages)
|
||||||
|
projects = list_all_projects(bearer)
|
||||||
|
|
||||||
|
# 3) Filter to ProjectEmailAddress == caseEmail
|
||||||
|
#filtered = [p for p in projects if str(p.get("ProjectEmailAddress", "")).lower() == str(case_email).lower()]
|
||||||
|
|
||||||
|
filtered = projects
|
||||||
|
# 4) Fetch details for each
|
||||||
|
detailed_rows = []
|
||||||
|
for p in filtered:
|
||||||
|
pid = (p.get("projectId") or {}).get("native")
|
||||||
|
c = fetch_client(bearer, (p.get("clientId") or {}).get("native"))
|
||||||
|
cs = fetch_contacts(bearer, pid)
|
||||||
|
print("CS IS", cs)
|
||||||
|
|
||||||
|
if pid is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
detail = fetch_project_detail(bearer, pid)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[WARN] detail fetch failed for {pid}: {e}")
|
||||||
|
detail = {}
|
||||||
|
row = {
|
||||||
|
"client": c.get("firstName"),
|
||||||
|
"matter_description": p.get("projectName"),
|
||||||
|
"contacts": cs,
|
||||||
|
"ProjectEmailAddress": p.get("projectEmailAddress"),
|
||||||
|
"Number": p.get("number"),
|
||||||
|
"IncidentDate": (p.get("incidentDate") or detail.get("incidentDate")),
|
||||||
|
"ProjectId": pid,
|
||||||
|
"ProjectName": p.get("projectName") or detail.get("projectName"),
|
||||||
|
"ProjectUrl": p.get("projectUrl") or detail.get("projectUrl"),
|
||||||
|
}
|
||||||
|
detailed_rows.append(row)
|
||||||
|
|
||||||
|
# 5) Render table
|
||||||
|
return render_template("dashboard.html", rows=detailed_rows, case_email=case_email)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=True, host="0.0.0.0", port=5000)
|
||||||
85
examples/client.json
Normal file
85
examples/client.json
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"sample_request": {
|
||||||
|
"url": "https://api.filevineapp.com/fv-app/v2/contacts/43125866",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": "Bearer eyJhbGciOiJSUzUxMiIsImtpZCI6Ijg2NjRFMkY0MDNCQjIxMzk2MzQ4NUFDOEI0MzVGMEJBOTgxNTBFN0RSUzUxMiIsInR5cCI6ImF0K2p3dCIsIng1dCI6ImhtVGk5QU83SVRsalNGckl0RFh3dXBnVkRuMCJ9.eyJuYmYiOjE3NjExNzg4NzUsImV4cCI6MTc2MTE4MDY3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS5maWxldmluZS5jb20iLCJhdWQiOlsiZmlsZXZpbmUudjIuYXBpIiwiZnYuYXBpLmdhdGV3YXkiLCJmdi5hdXRoIl0sImNsaWVudF9pZCI6IjRGMTg3MzhDLTEwN0EtNEI4Mi1CRkFDLTMwOEYxQjZBNjI2QSIsInN1YiI6ImY3MDQ4NGZmLTQ5MjItNDliMy05MWFkLTE2YjA5Mjk5MGIzMCIsImF1dGhfdGltZSI6MTc2MTE3ODg3NSwiaWRwIjoibG9jYWwiLCJwYXRfaWQiOiJmUkEwbHRoSnp5aTBBWU9ZS1F4WGVlckczUHc1MXEyMmh4cTlzbk4zL2V3PSIsInBhdF9uYW1lIjoiQnJ5Y2UgQ292ZXJ0IiwicGF0X3ZlcnNpb24iOiIxIiwidGVuYW50X2ZybiI6ImZybjpmaWxldmluZTp1cy1wcm9kOmZpbGV2aW5lLWFwcDo6OnRlbmFudFxcMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwidGVuYW50X2lkIjoiMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwianRpIjoiMkNENzYzNUFGNkU5RjQ0RjY2NzI1RTkyREY3RUI2NDciLCJpYXQiOjE3NjExNzg4NzUsInNjb3BlIjpbImVtYWlsIiwiZmlsZXZpbmUudjIuYXBpLioiLCJmdi5hcGkuZ2F0ZXdheS5hY2Nlc3MiLCJmdi5hdXRoLnRlbmFudC5yZWFkIiwib3BlbmlkIiwidGVuYW50Il0sImFtciI6WyJwZXJzb25hbF9hY2Nlc3NfdG9rZW4iXX0.E-TzpOEg6TO0ab65oq_rIambdugvK435q-yR1miardzwt5mP1Bz4aiLCurnx3FmkxhMSTnIOC8jzX73mG_lZL22FFctsB5EWt7WrUScqVAmTtG4hfPQOp4BM007nbXiKWwEXejBhyV8bsxkRkjv1gj6OlaCnvLkiDCgiD93RWpo6LSMi7nry1bNUXI2eN-0yXXrvDEiwvfY2meO1lvVwEUktLPy45_ehZ6IOc6ZIDw3zMLkqZjj046JRCsT9L8w-oNHq5xerRC4RcssIklsn9KH7M_oDrDtW20gLcTJ0mubk_HcTc1oQh-loe89UHFg-tiB63LHng9Vj3JnyZPvEjg",
|
||||||
|
"x-fv-orgid": "9227",
|
||||||
|
"x-fv-userid": "100510"
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
"sample_response": {
|
||||||
|
"status_code": 200,
|
||||||
|
"json": {
|
||||||
|
"personId": {
|
||||||
|
"native": 43125866,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"firstName": "Twin Pines Apartments (Twin Pine LLC)",
|
||||||
|
"middleName": "",
|
||||||
|
"lastName": "",
|
||||||
|
"isSingleName": true,
|
||||||
|
"fullName": "Twin Pines Apartments (Twin Pine LLC)",
|
||||||
|
"pictureUrl": "/images/Default6eba3d0d-6227-44c3-b907-8311c3d4da82.png",
|
||||||
|
"pictureKey": "Default6eba3d0d-6227-44c3-b907-8311c3d4da82.png",
|
||||||
|
"fromCompany": "",
|
||||||
|
"personTypes": [
|
||||||
|
"Client/ Property"
|
||||||
|
],
|
||||||
|
"uniqueId": "65333863-f119-4e10-9473-992b99fbac16",
|
||||||
|
"searchNames": [
|
||||||
|
"twin",
|
||||||
|
"pines",
|
||||||
|
"apartments",
|
||||||
|
"(twin",
|
||||||
|
"pine",
|
||||||
|
"llc)",
|
||||||
|
"twin pines apartments (twin pine llc)"
|
||||||
|
],
|
||||||
|
"phones": [],
|
||||||
|
"emails": [],
|
||||||
|
"addresses": [],
|
||||||
|
"prefix": "",
|
||||||
|
"hashtags": [],
|
||||||
|
"suffix": "",
|
||||||
|
"jobTitle": "",
|
||||||
|
"department": "",
|
||||||
|
"modifiedDate": "2025-10-22T15:06:31.993Z",
|
||||||
|
"links": {
|
||||||
|
"self": "/contacts/43125866",
|
||||||
|
"projects": "/contacts/43125866/projects",
|
||||||
|
"phones": "/contacts/43125866/phones",
|
||||||
|
"emailAddresses": "/contacts/43125866/emailAddresses",
|
||||||
|
"addresses": "/contacts/43125866/addresses"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Date": "Thu, 23 Oct 2025 00:21:16 GMT",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
"Transfer-Encoding": "chunked",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Server": "cloudflare",
|
||||||
|
"access-control-allow-headers": "Content-Type, x-fv-orgid, x-fv-clientip, x-fv-userid, authorization, x-fv-application",
|
||||||
|
"access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS, LOCK, UNLOCK, PROPPATCH, PROPFIND",
|
||||||
|
"access-control-allow-origin": "*",
|
||||||
|
"Cache-Control": "no-store, must-revalidate, no-cache, max-age=0, private",
|
||||||
|
"ratelimit-limit": "10;r=3300;w=60;c=Customer Temp",
|
||||||
|
"ratelimit-remaining": "9;r=3300;w=60;c=Customer Temp",
|
||||||
|
"content-security-policy": "default-src 'self';child-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://app.vinesign.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com https://app.pendo.io https://feedback.us.pendo.io docs.google.com https://feedback.filevine.com *.newrelic.com *.filev.io *.flvn.io filev.io flvn.io 'self';connect-src *.filevinedev.com *.filevineapp.com *.filevine.ca *.filevine.com *.filevinegov.com *.fvauth.com https://app.vinesign.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com *.nr-data.net *.pendo.io *.pdftron.com *.typeform.com *.newrelic.com https://app.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://localhost:8080 *.filev.io *.flvn.io filev.io flvn.io 'self' blob: wss:;font-src *.bootstrapcdn.com fonts.gstatic.com *.typekit.net *.typeform.com 'self' data: blob:;frame-src *;frame-ancestors https://*.filevineapp.com https://app.pendo.io 'self';img-src *.typekit.net *.typeform.com https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-globalproducts-prod-us-logos.s3.us-west-2.amazonaws.com https://us.fv-globalproducts-logos.prod.filevine.com https://fv-prod-us-shard-h-fv-internal-image.s3.amazonaws.com https://fv-prod-us-shard-h-fv-internal-image.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io *.kaywa.com www.googletagmanager.com 'self' data: blob: cid:;manifest-src 'self';media-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com https://us-shard-h-discussions.filevineapp.com *.filev.io *.flvn.io filev.io flvn.io 'self';object-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io 'self';script-src *.bootstrapcdn.com *.typekit.net *.typeform.com *.newrelic.com *.nr-data.net https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://code.jquery.com https://localhost:8080 https://www.googletagmanager.com 'unsafe-inline' 'unsafe-eval' 'self' blob:;style-src *.bootstrapcdn.com fonts.googleapis.com *.typekit.net *.typeform.com https://app.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://cdn.pendo.io https://data.pendo.io 'unsafe-inline' 'self';worker-src 'self' blob: 'unsafe-inline'",
|
||||||
|
"x-filevine-api-version": "3.3426.3.0",
|
||||||
|
"x-fv-correlation-id": "0a3acd7278c6486796d853ddf232e48f",
|
||||||
|
"x-aspnet-version": "4.0.30319",
|
||||||
|
"x-powered-by": "ASP.NET",
|
||||||
|
"x-content-type-options": "nosniff",
|
||||||
|
"x-frame-option": "SAMEORIGIN",
|
||||||
|
"x-xss-protection": "1; mode=block",
|
||||||
|
"x-fv-gateway-correlation-id": "0a3acd7278c6486796d853ddf232e48f",
|
||||||
|
"cf-cache-status": "DYNAMIC",
|
||||||
|
"Content-Encoding": "gzip",
|
||||||
|
"CF-RAY": "992d12c6c95790db-SEA",
|
||||||
|
"alt-svc": "h3=\":443\"; ma=86400"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
246
examples/project_contacts.json
Normal file
246
examples/project_contacts.json
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
{
|
||||||
|
"sample_request": {
|
||||||
|
"url": "https://api.filevineapp.com/fv-app/v2/Projects/15905506/contacts",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": "Bearer eyJhbGciOiJSUzUxMiIsImtpZCI6Ijg2NjRFMkY0MDNCQjIxMzk2MzQ4NUFDOEI0MzVGMEJBOTgxNTBFN0RSUzUxMiIsInR5cCI6ImF0K2p3dCIsIng1dCI6ImhtVGk5QU83SVRsalNGckl0RFh3dXBnVkRuMCJ9.eyJuYmYiOjE3NjExNzg4NzUsImV4cCI6MTc2MTE4MDY3NSwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS5maWxldmluZS5jb20iLCJhdWQiOlsiZmlsZXZpbmUudjIuYXBpIiwiZnYuYXBpLmdhdGV3YXkiLCJmdi5hdXRoIl0sImNsaWVudF9pZCI6IjRGMTg3MzhDLTEwN0EtNEI4Mi1CRkFDLTMwOEYxQjZBNjI2QSIsInN1YiI6ImY3MDQ4NGZmLTQ5MjItNDliMy05MWFkLTE2YjA5Mjk5MGIzMCIsImF1dGhfdGltZSI6MTc2MTE3ODg3NSwiaWRwIjoibG9jYWwiLCJwYXRfaWQiOiJmUkEwbHRoSnp5aTBBWU9ZS1F4WGVlckczUHc1MXEyMmh4cTlzbk4zL2V3PSIsInBhdF9uYW1lIjoiQnJ5Y2UgQ292ZXJ0IiwicGF0X3ZlcnNpb24iOiIxIiwidGVuYW50X2ZybiI6ImZybjpmaWxldmluZTp1cy1wcm9kOmZpbGV2aW5lLWFwcDo6OnRlbmFudFxcMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwidGVuYW50X2lkIjoiMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwianRpIjoiRTg1ODdBNDY3NkI1OTg2M0U0OTAxNkNFRTYxNDNFNjciLCJpYXQiOjE3NjExNzg4NzUsInNjb3BlIjpbImVtYWlsIiwiZmlsZXZpbmUudjIuYXBpLioiLCJmdi5hcGkuZ2F0ZXdheS5hY2Nlc3MiLCJmdi5hdXRoLnRlbmFudC5yZWFkIiwib3BlbmlkIiwidGVuYW50Il0sImFtciI6WyJwZXJzb25hbF9hY2Nlc3NfdG9rZW4iXX0.mjeEZUAE466DLME0jmRu_znERUH6_85AitHzgDrQlWPpeIy_18-B5x9hG2-wAp2s_WGdjn2eRc8qmy5wD9vbw4k1-L3HNhfI_9s24MGbanXWeu9eGHenY092D12W4eoJYlYCCpbGhqPNbql021hbU6TZTTGs2IMfwBy9k5H2HVCkPd2NbswuEsTt_M1XUUe-6duqEIGWdYQ097xGcVl3tGYgAxR6nyICyiovxVRZXsuKGK0a5r_7KKSZwM6v1brB9V08oBBsGoTRaLe_uxG-YHrMSPZ0JXvLxvzT8XXLh5RMXd2ijekHQ9nMKehmxojiQKg20r8_4kUtzZlkyeL_WQ",
|
||||||
|
"x-fv-orgid": "9227",
|
||||||
|
"x-fv-userid": "100510"
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
"sample_response": {
|
||||||
|
"status_code": 200,
|
||||||
|
"json": {
|
||||||
|
"count": 3,
|
||||||
|
"offset": 0,
|
||||||
|
"limit": 50,
|
||||||
|
"hasMore": false,
|
||||||
|
"requestedFields": "*",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"projectId": {
|
||||||
|
"native": 15905506,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"orgContactId": {
|
||||||
|
"native": 43125848,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"roles": [
|
||||||
|
"Property Contacts: Property Manager 1"
|
||||||
|
],
|
||||||
|
"orgContact": {
|
||||||
|
"personId": {
|
||||||
|
"native": 43125848,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"firstName": "Brian",
|
||||||
|
"middleName": "Robert",
|
||||||
|
"lastName": "Testy",
|
||||||
|
"isSingleName": false,
|
||||||
|
"fullName": "Brian Robert Testy",
|
||||||
|
"primaryEmail": "brianskarbek@gmail.com",
|
||||||
|
"pictureUrl": "/images/Default64896de9-7ee8-47a4-bcd2-1df186e6230a.png",
|
||||||
|
"pictureKey": "Default64896de9-7ee8-47a4-bcd2-1df186e6230a.png",
|
||||||
|
"personTypes": [
|
||||||
|
"Property Manager"
|
||||||
|
],
|
||||||
|
"uniqueId": "4daf252f-db81-4ca7-b7e4-0a5fd801170c",
|
||||||
|
"searchNames": [
|
||||||
|
"brian",
|
||||||
|
"robert",
|
||||||
|
"testy",
|
||||||
|
"brian robert testy",
|
||||||
|
"brian testy"
|
||||||
|
],
|
||||||
|
"phones": [
|
||||||
|
{
|
||||||
|
"phoneId": {
|
||||||
|
"native": 74619813,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"number": "4084821733",
|
||||||
|
"rawNumber": "4084821733",
|
||||||
|
"isSmsable": false,
|
||||||
|
"isFaxable": false,
|
||||||
|
"links": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"emails": [
|
||||||
|
{
|
||||||
|
"emailId": {
|
||||||
|
"native": 19265473,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"address": "brianskarbek@gmail.com",
|
||||||
|
"links": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"addresses": [
|
||||||
|
{
|
||||||
|
"addressId": {
|
||||||
|
"native": 56313190,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"line1": "2926 Neal Ave",
|
||||||
|
"line2": "",
|
||||||
|
"city": "San Jose",
|
||||||
|
"state": "CA",
|
||||||
|
"postalCode": "95128",
|
||||||
|
"fullAddress": "2926 Neal Ave, San Jose, CA 95128",
|
||||||
|
"links": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hashtags": [],
|
||||||
|
"modifiedDate": "2025-10-18T14:24:54.16Z",
|
||||||
|
"links": {
|
||||||
|
"self": "/contacts/43125848",
|
||||||
|
"projects": "/contacts/43125848/projects",
|
||||||
|
"phones": "/contacts/43125848/phones",
|
||||||
|
"emailAddresses": "/contacts/43125848/emailAddresses",
|
||||||
|
"addresses": "/contacts/43125848/addresses"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"links": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": {
|
||||||
|
"native": 15905506,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"orgContactId": {
|
||||||
|
"native": 43193362,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"roles": [
|
||||||
|
"Defendants: Defendant Contact"
|
||||||
|
],
|
||||||
|
"orgContact": {
|
||||||
|
"personId": {
|
||||||
|
"native": 43193362,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"firstName": "Bad",
|
||||||
|
"lastName": "Guy",
|
||||||
|
"isSingleName": false,
|
||||||
|
"fullName": "Bad Guy",
|
||||||
|
"pictureUrl": "/images/Defaultf6812c31-f9e7-4961-b7da-89adcd48dbac.png",
|
||||||
|
"pictureKey": "Defaultf6812c31-f9e7-4961-b7da-89adcd48dbac.png",
|
||||||
|
"personTypes": [
|
||||||
|
"Defendant"
|
||||||
|
],
|
||||||
|
"uniqueId": "3368bc70-4aed-4349-9fd6-0cd2dca654ae",
|
||||||
|
"searchNames": [
|
||||||
|
"bad",
|
||||||
|
"guy",
|
||||||
|
"bad guy"
|
||||||
|
],
|
||||||
|
"phones": [],
|
||||||
|
"emails": [],
|
||||||
|
"addresses": [],
|
||||||
|
"hashtags": [],
|
||||||
|
"modifiedDate": "2025-10-22T15:29:38.463Z",
|
||||||
|
"links": {
|
||||||
|
"self": "/contacts/43193362",
|
||||||
|
"projects": "/contacts/43193362/projects",
|
||||||
|
"phones": "/contacts/43193362/phones",
|
||||||
|
"emailAddresses": "/contacts/43193362/emailAddresses",
|
||||||
|
"addresses": "/contacts/43193362/addresses"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"links": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectId": {
|
||||||
|
"native": 15905506,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"orgContactId": {
|
||||||
|
"native": 43182533,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"roles": [
|
||||||
|
"Matter Overview: Signing Attorney"
|
||||||
|
],
|
||||||
|
"orgContact": {
|
||||||
|
"personId": {
|
||||||
|
"native": 43182533,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"firstName": "Brian",
|
||||||
|
"lastName": "Skarbek",
|
||||||
|
"isSingleName": false,
|
||||||
|
"fullName": "Brian Skarbek",
|
||||||
|
"primaryEmail": "Brian@ToddRothbardLaw.com",
|
||||||
|
"pictureUrl": "/images/Default96eecdd8-0702-4099-9ef2-254bb3a788fa.png",
|
||||||
|
"pictureKey": "Default96eecdd8-0702-4099-9ef2-254bb3a788fa.png",
|
||||||
|
"personTypes": [
|
||||||
|
"Attorney"
|
||||||
|
],
|
||||||
|
"uniqueId": "f0cab457-e837-4341-843d-a8afb4265beb",
|
||||||
|
"searchNames": [
|
||||||
|
"brian",
|
||||||
|
"skarbek",
|
||||||
|
"brian skarbek"
|
||||||
|
],
|
||||||
|
"phones": [],
|
||||||
|
"emails": [
|
||||||
|
{
|
||||||
|
"emailId": {
|
||||||
|
"native": 19294763,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"address": "Brian@ToddRothbardLaw.com",
|
||||||
|
"links": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"addresses": [],
|
||||||
|
"hashtags": [],
|
||||||
|
"modifiedDate": "2025-10-20T23:47:10.213Z",
|
||||||
|
"links": {
|
||||||
|
"self": "/contacts/43182533",
|
||||||
|
"projects": "/contacts/43182533/projects",
|
||||||
|
"phones": "/contacts/43182533/phones",
|
||||||
|
"emailAddresses": "/contacts/43182533/emailAddresses",
|
||||||
|
"addresses": "/contacts/43182533/addresses"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"links": {}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"self": "/contacts?firstName=&lastName=&fullName=&nickName=&personType=&phone=&email=&searchTerm=&offset=0&limit=50&requestedFields=*",
|
||||||
|
"prev": null,
|
||||||
|
"next": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Date": "Thu, 23 Oct 2025 00:21:15 GMT",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
"Transfer-Encoding": "chunked",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Server": "cloudflare",
|
||||||
|
"access-control-allow-headers": "Content-Type, x-fv-orgid, x-fv-clientip, x-fv-userid, authorization, x-fv-application",
|
||||||
|
"access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS, LOCK, UNLOCK, PROPPATCH, PROPFIND",
|
||||||
|
"access-control-allow-origin": "*",
|
||||||
|
"Cache-Control": "no-store, must-revalidate, no-cache, max-age=0, private",
|
||||||
|
"ratelimit-limit": "10;r=3300;w=60;c=Customer Temp",
|
||||||
|
"ratelimit-remaining": "9;r=3300;w=60;c=Customer Temp",
|
||||||
|
"content-security-policy": "default-src 'self';child-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://app.vinesign.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com https://app.pendo.io https://feedback.us.pendo.io docs.google.com https://feedback.filevine.com *.newrelic.com *.filev.io *.flvn.io filev.io flvn.io 'self';connect-src *.filevinedev.com *.filevineapp.com *.filevine.ca *.filevine.com *.filevinegov.com *.fvauth.com https://app.vinesign.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com *.nr-data.net *.pendo.io *.pdftron.com *.typeform.com *.newrelic.com https://app.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://localhost:8080 *.filev.io *.flvn.io filev.io flvn.io 'self' blob: wss:;font-src *.bootstrapcdn.com fonts.gstatic.com *.typekit.net *.typeform.com 'self' data: blob:;frame-src *;frame-ancestors https://*.filevineapp.com https://app.pendo.io 'self';img-src *.typekit.net *.typeform.com https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-globalproducts-prod-us-logos.s3.us-west-2.amazonaws.com https://us.fv-globalproducts-logos.prod.filevine.com https://fv-prod-us-shard-h-fv-internal-image.s3.amazonaws.com https://fv-prod-us-shard-h-fv-internal-image.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io *.kaywa.com www.googletagmanager.com 'self' data: blob: cid:;manifest-src 'self';media-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com https://us-shard-h-discussions.filevineapp.com *.filev.io *.flvn.io filev.io flvn.io 'self';object-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io 'self';script-src *.bootstrapcdn.com *.typekit.net *.typeform.com *.newrelic.com *.nr-data.net https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://code.jquery.com https://localhost:8080 https://www.googletagmanager.com 'unsafe-inline' 'unsafe-eval' 'self' blob:;style-src *.bootstrapcdn.com fonts.googleapis.com *.typekit.net *.typeform.com https://app.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://cdn.pendo.io https://data.pendo.io 'unsafe-inline' 'self';worker-src 'self' blob: 'unsafe-inline'",
|
||||||
|
"x-filevine-api-version": "3.3426.3.0",
|
||||||
|
"x-fv-correlation-id": "51ff3a6e96c24996b386a4177bef952a",
|
||||||
|
"x-aspnet-version": "4.0.30319",
|
||||||
|
"x-powered-by": "ASP.NET",
|
||||||
|
"x-content-type-options": "nosniff",
|
||||||
|
"x-frame-option": "SAMEORIGIN",
|
||||||
|
"x-xss-protection": "1; mode=block",
|
||||||
|
"x-fv-gateway-correlation-id": "51ff3a6e96c24996b386a4177bef952a",
|
||||||
|
"cf-cache-status": "DYNAMIC",
|
||||||
|
"Content-Encoding": "gzip",
|
||||||
|
"CF-RAY": "992d12c2ec4131ba-SEA",
|
||||||
|
"alt-svc": "h3=\":443\"; ma=86400"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
442
examples/project_list.json
Normal file
442
examples/project_list.json
Normal file
@@ -0,0 +1,442 @@
|
|||||||
|
{
|
||||||
|
"sample_request": {
|
||||||
|
"url": "https://api.filevineapp.com/fv-app/v2/projects",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": "Bearer eyJhbGciOiJSUzUxMiIsImtpZCI6Ijg2NjRFMkY0MDNCQjIxMzk2MzQ4NUFDOEI0MzVGMEJBOTgxNTBFN0RSUzUxMiIsInR5cCI6ImF0K2p3dCIsIng1dCI6ImhtVGk5QU83SVRsalNGckl0RFh3dXBnVkRuMCJ9.eyJuYmYiOjE3NjExNzg4NzQsImV4cCI6MTc2MTE4MDY3NCwiaXNzIjoiaHR0cHM6Ly9pZGVudGl0eS5maWxldmluZS5jb20iLCJhdWQiOlsiZmlsZXZpbmUudjIuYXBpIiwiZnYuYXBpLmdhdGV3YXkiLCJmdi5hdXRoIl0sImNsaWVudF9pZCI6IjRGMTg3MzhDLTEwN0EtNEI4Mi1CRkFDLTMwOEYxQjZBNjI2QSIsInN1YiI6ImY3MDQ4NGZmLTQ5MjItNDliMy05MWFkLTE2YjA5Mjk5MGIzMCIsImF1dGhfdGltZSI6MTc2MTE3ODg3NCwiaWRwIjoibG9jYWwiLCJwYXRfaWQiOiJmUkEwbHRoSnp5aTBBWU9ZS1F4WGVlckczUHc1MXEyMmh4cTlzbk4zL2V3PSIsInBhdF9uYW1lIjoiQnJ5Y2UgQ292ZXJ0IiwicGF0X3ZlcnNpb24iOiIxIiwidGVuYW50X2ZybiI6ImZybjpmaWxldmluZTp1cy1wcm9kOmZpbGV2aW5lLWFwcDo6OnRlbmFudFxcMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwidGVuYW50X2lkIjoiMGJlOGFhOGItZmEyOS00MjQ0LWI1YzItMDE5NzIzMWExNWY5IiwianRpIjoiODlCRTQzRDlDRTYwQkNFNzg4Mzc5OEE1M0VBQkYwQTAiLCJpYXQiOjE3NjExNzg4NzQsInNjb3BlIjpbImVtYWlsIiwiZmlsZXZpbmUudjIuYXBpLioiLCJmdi5hcGkuZ2F0ZXdheS5hY2Nlc3MiLCJmdi5hdXRoLnRlbmFudC5yZWFkIiwib3BlbmlkIiwidGVuYW50Il0sImFtciI6WyJwZXJzb25hbF9hY2Nlc3NfdG9rZW4iXX0.P5rPsrBwt0MQ7SmR9l0K0WXgTkqStXXbyYRYCmjPaBnJZjLljMLkpqZsFYDf3pyg6t9oZK_oa86sGa7H13SBIocWqV70hloqAVn1uinwzKxS1gv0xvUdTkd_uPgJZPvQwsu_Py4RrXcHkhtH8dqOGO_VFBFyYvt5RSNUpVtS6ofP0srbxoAOUEsYW-VhmKV8ugcdFzATgTx6k6gXyy1fTKoa_s7tVSFcOe-yPD7xpnixY3aqnYFaCSf5PYzd9l7iBPzfgjn0cFWnOjtxKSl_fxzQacJqOonrSPYdTlNf-F6h5E-yT-CQuVVWRplcbadEDvgMptTQjbprZHTMLfdn-w",
|
||||||
|
"x-fv-orgid": "9227",
|
||||||
|
"x-fv-userid": "100510"
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
},
|
||||||
|
"sample_response": {
|
||||||
|
"status_code": 200,
|
||||||
|
"json": {
|
||||||
|
"count": 8,
|
||||||
|
"offset": 0,
|
||||||
|
"limit": 50,
|
||||||
|
"hasMore": false,
|
||||||
|
"requestedFields": "*",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 138236604,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Nonpayment File Review",
|
||||||
|
"phaseDate": "2025-10-22T15:23:59.89Z",
|
||||||
|
"clientName": "Twin Pines Apartments (Twin Pine LLC)",
|
||||||
|
"clientPictureURL": "/images/Default6eba3d0d-6227-44c3-b907-8311c3d4da82.png",
|
||||||
|
"clientPictureKey": "Default6eba3d0d-6227-44c3-b907-8311c3d4da82.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Lani",
|
||||||
|
"firstPrimaryUsername": "lani2",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-22T15:27:44.177Z",
|
||||||
|
"uniqueKey": "TwinPinesApartmentsZ15905506",
|
||||||
|
"projectOrClientName": "Twin Pines Apartments (Twin Pine LLC) v. Guy, #12, NP",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "TwinPinesApartmentsZ15905506@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-10-22T15:03:48.41Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/15905506",
|
||||||
|
"projectId": {
|
||||||
|
"native": 15905506,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 43125866,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "Twin Pines Apartments (Twin Pine LLC) v. Guy, #12, NP",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 209436,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/15905506",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/138236604",
|
||||||
|
"client": "/contacts/43125866",
|
||||||
|
"contacts": "/projects/15905506/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 138206532,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Nonpayment File Review",
|
||||||
|
"phaseDate": "2025-10-21T14:42:31.18Z",
|
||||||
|
"clientName": "3900 Adeline",
|
||||||
|
"clientPictureURL": "/images/avatar-user-placeholder.png",
|
||||||
|
"clientPictureKey": "avatar-user-placeholder.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Rebecca Hartzler",
|
||||||
|
"firstPrimaryUsername": "rebecca63",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-21T15:29:19.773Z",
|
||||||
|
"uniqueKey": "AdelineZ15902340",
|
||||||
|
"projectOrClientName": "3900 Adeline (3900 Adeline, LLC) v. Patten, #323, NP",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "AdelineZ15902340@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-10-21T14:38:26.957Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/15902340",
|
||||||
|
"projectId": {
|
||||||
|
"native": 15902340,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 43183162,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "3900 Adeline (3900 Adeline, LLC) v. Patten, #323, NP",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 209436,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/15902340",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/138206532",
|
||||||
|
"client": "/contacts/43183162",
|
||||||
|
"contacts": "/projects/15902340/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 138179643,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Nonpayment File Review",
|
||||||
|
"phaseDate": "2025-10-20T15:07:56.023Z",
|
||||||
|
"clientName": "Bates Motel (Bates Motel Group, LLC)",
|
||||||
|
"clientPictureURL": "/images/Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureKey": "Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Stephanie Gonzalez",
|
||||||
|
"firstPrimaryUsername": "stephanie148",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-21T00:07:51.847Z",
|
||||||
|
"uniqueKey": "vFakeDefendantNPZ15901312",
|
||||||
|
"projectOrClientName": "v. Fake Defendant, #50, NP",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "vFakeDefendantNPZ15901312@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-10-20T14:31:07.29Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/15901312",
|
||||||
|
"projectId": {
|
||||||
|
"native": 15901312,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 40576359,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "v. Fake Defendant, #50, NP",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 209436,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/15901312",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/138179643",
|
||||||
|
"client": "/contacts/40576359",
|
||||||
|
"contacts": "/projects/15901312/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 138011554,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Migrated",
|
||||||
|
"phaseDate": "2025-10-16T20:33:18.8Z",
|
||||||
|
"clientName": "ABC Property Management",
|
||||||
|
"clientPictureURL": "/images/Default5888c798-e92d-4c2e-82e9-737a564b5317.png",
|
||||||
|
"clientPictureKey": "Default5888c798-e92d-4c2e-82e9-737a564b5317.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Brian Skarbek",
|
||||||
|
"firstPrimaryUsername": "brianskarbek",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-16T20:33:18.803Z",
|
||||||
|
"uniqueKey": "TBDZ15896299",
|
||||||
|
"projectOrClientName": "TBD",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "TBDZ15896299@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-10-16T20:33:18.8Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/15896299",
|
||||||
|
"projectId": {
|
||||||
|
"native": 15896299,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 43122010,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "TBD",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 211957,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/15896299",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/138011554",
|
||||||
|
"client": "/contacts/43122010",
|
||||||
|
"contacts": "/projects/15896299/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 137923183,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Default",
|
||||||
|
"phaseDate": "2025-10-22T18:03:38.6Z",
|
||||||
|
"clientName": "Bates Motel (Bates Motel Group, LLC)",
|
||||||
|
"clientPictureURL": "/images/Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureKey": "Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Sarra McDonald",
|
||||||
|
"firstPrimaryUsername": "sarra",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-22T22:14:58.907Z",
|
||||||
|
"uniqueKey": "BatesMotelZ15892080",
|
||||||
|
"projectOrClientName": "Bates Motel (Bates Motel Group, LLC)",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "BatesMotelZ15892080@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-10-13T21:54:29.187Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/15892080",
|
||||||
|
"projectId": {
|
||||||
|
"native": 15892080,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 40576359,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "Bates Motel (Bates Motel Group, LLC)",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 211435,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/15892080",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/137923183",
|
||||||
|
"client": "/contacts/40576359",
|
||||||
|
"contacts": "/projects/15892080/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 128719223,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Trial Prep and Trial",
|
||||||
|
"phaseDate": "2025-10-22T21:40:11.117Z",
|
||||||
|
"clientName": "1234 Main Street Apartments (Main Street Property Holding LLC)",
|
||||||
|
"clientPictureURL": "/images/avatar-user-placeholder.png",
|
||||||
|
"clientPictureKey": "avatar-user-placeholder.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Sarra McDonald",
|
||||||
|
"firstPrimaryUsername": "sarra",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-22T22:14:26.443Z",
|
||||||
|
"uniqueKey": "MainStreetApartmentsvSmithNTTZ12685677",
|
||||||
|
"projectOrClientName": "1234 Main Street Apartments v Smith, #24, NTT",
|
||||||
|
"hashtags": [
|
||||||
|
"#Attorney-to-accept-service"
|
||||||
|
],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "MainStreetApartmentsvSmithNTTZ12685677@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-06-17T01:07:55.873Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/12685677",
|
||||||
|
"projectId": {
|
||||||
|
"native": 12685677,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 40637221,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "1234 Main Street Apartments v Smith, #24, NTT",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 211438,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/12685677",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/128719223",
|
||||||
|
"client": "/contacts/40637221",
|
||||||
|
"contacts": "/projects/12685677/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "EVICT",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 128547693,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "Notice Pending",
|
||||||
|
"phaseDate": "2025-10-21T00:21:07.603Z",
|
||||||
|
"clientName": "Bates Motel (Bates Motel Group, LLC)",
|
||||||
|
"clientPictureURL": "/images/Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureKey": "Defaultf3f74f0b-0eee-4a40-98f1-57960d87f12a.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Jen Rhodes",
|
||||||
|
"firstPrimaryUsername": "jen60",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-10-21T00:07:49.373Z",
|
||||||
|
"uniqueKey": "BatesMotelVsTenantNameZ12662539",
|
||||||
|
"projectOrClientName": "Bates Motel Vs. Tenant Name 25CV123456",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "BatesMotelVsTenantNameZ12662539@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-06-06T02:48:45.96Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/12662539",
|
||||||
|
"projectId": {
|
||||||
|
"native": 12662539,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34111,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 40576359,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "Bates Motel Vs. Tenant Name 25CV123456",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 209439,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/12662539",
|
||||||
|
"projectType": "/projecttypes/34111",
|
||||||
|
"rootFolder": "/folders/128547693",
|
||||||
|
"client": "/contacts/40576359",
|
||||||
|
"contacts": "/projects/12662539/contacts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"projectTypeCode": "ADMIN",
|
||||||
|
"rootDocFolderId": {
|
||||||
|
"native": 128547692,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"phaseName": "ADMIN",
|
||||||
|
"phaseDate": "2025-06-06T02:47:33.87Z",
|
||||||
|
"clientName": "Admin",
|
||||||
|
"clientPictureURL": "/images/c8711333-fad7-40f3-81fb-2853b8a7e082.png",
|
||||||
|
"clientPictureKey": "c8711333-fad7-40f3-81fb-2853b8a7e082.png",
|
||||||
|
"clientPictureS3Url": "",
|
||||||
|
"firstPrimaryName": "Jen Rhodes",
|
||||||
|
"firstPrimaryUsername": "jen60",
|
||||||
|
"isArchived": false,
|
||||||
|
"lastActivity": "2025-06-06T02:47:33.873Z",
|
||||||
|
"uniqueKey": "VineskillsTrainingandResourcesProjectZ12662538",
|
||||||
|
"projectOrClientName": "Vineskills | Training and Resources Project",
|
||||||
|
"hashtags": [],
|
||||||
|
"orgId": 9227,
|
||||||
|
"projectEmailAddress": "VineskillsTrainingandResourcesProjectZ12662538@rothbardlawgroup.filevineapp.com",
|
||||||
|
"createdDate": "2025-06-06T02:47:33.87Z",
|
||||||
|
"projectUrl": "https://rothbardlawgroup.filevineapp.com/#/project/12662538",
|
||||||
|
"projectId": {
|
||||||
|
"native": 12662538,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectTypeId": {
|
||||||
|
"native": 34112,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"clientId": {
|
||||||
|
"native": 40576358,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"projectName": "Vineskills | Training and Resources Project",
|
||||||
|
"phaseId": {
|
||||||
|
"native": 209445,
|
||||||
|
"partner": null
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"self": "/projects/12662538",
|
||||||
|
"projectType": "/projecttypes/34112",
|
||||||
|
"rootFolder": "/folders/128547692",
|
||||||
|
"client": "/contacts/40576358",
|
||||||
|
"contacts": "/projects/12662538/contacts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": {
|
||||||
|
"self": "/projects?name=&number=&createdSince=&searchterm=&projectId=&incidentDate=&hashtags=&offset=0&limit=50&requestedFields=*",
|
||||||
|
"prev": null,
|
||||||
|
"next": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Date": "Thu, 23 Oct 2025 00:21:15 GMT",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
"Transfer-Encoding": "chunked",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Server": "cloudflare",
|
||||||
|
"access-control-allow-headers": "Content-Type, x-fv-orgid, x-fv-clientip, x-fv-userid, authorization, x-fv-application",
|
||||||
|
"access-control-allow-methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS, LOCK, UNLOCK, PROPPATCH, PROPFIND",
|
||||||
|
"access-control-allow-origin": "*",
|
||||||
|
"Cache-Control": "no-store, must-revalidate, no-cache, max-age=0, private",
|
||||||
|
"ratelimit-limit": "10;r=3300;w=60;c=Customer Temp",
|
||||||
|
"ratelimit-remaining": "9;r=3300;w=60;c=Customer Temp",
|
||||||
|
"content-security-policy": "default-src 'self';child-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://app.vinesign.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com https://app.pendo.io https://feedback.us.pendo.io docs.google.com https://feedback.filevine.com *.newrelic.com *.filev.io *.flvn.io filev.io flvn.io 'self';connect-src *.filevinedev.com *.filevineapp.com *.filevine.ca *.filevine.com *.filevinegov.com *.fvauth.com https://app.vinesign.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.amazonaws.com *.nr-data.net *.pendo.io *.pdftron.com *.typeform.com *.newrelic.com https://app.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://localhost:8080 *.filev.io *.flvn.io filev.io flvn.io 'self' blob: wss:;font-src *.bootstrapcdn.com fonts.gstatic.com *.typekit.net *.typeform.com 'self' data: blob:;frame-src *;frame-ancestors https://*.filevineapp.com https://app.pendo.io 'self';img-src *.typekit.net *.typeform.com https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-globalproducts-prod-us-logos.s3.us-west-2.amazonaws.com https://us.fv-globalproducts-logos.prod.filevine.com https://fv-prod-us-shard-h-fv-internal-image.s3.amazonaws.com https://fv-prod-us-shard-h-fv-internal-image.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io *.kaywa.com www.googletagmanager.com 'self' data: blob: cid:;manifest-src 'self';media-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com https://us-shard-h-discussions.filevineapp.com *.filev.io *.flvn.io filev.io flvn.io 'self';object-src https://fv-prod-us-shard-h-images.s3.amazonaws.com https://fv-prod-us-shard-h-images.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-docs.s3.amazonaws.com https://fv-prod-us-shard-h-docs.s3.us-west-2.amazonaws.com https://fv-prod-us-shard-h-report-export.s3.us-west-2.amazonaws.com *.filev.io *.flvn.io filev.io flvn.io 'self';script-src *.bootstrapcdn.com *.typekit.net *.typeform.com *.newrelic.com *.nr-data.net https://app.pendo.io https://cdn.pendo.io https://data.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://code.jquery.com https://localhost:8080 https://www.googletagmanager.com 'unsafe-inline' 'unsafe-eval' 'self' blob:;style-src *.bootstrapcdn.com fonts.googleapis.com *.typekit.net *.typeform.com https://app.pendo.io https://pendo-static-5683967597215744.storage.googleapis.com https://pendo-io-static.storage.googleapis.com https://duuxdetkhlwyv.cloudfront.net https://cdn.pendo.io https://data.pendo.io 'unsafe-inline' 'self';worker-src 'self' blob: 'unsafe-inline'",
|
||||||
|
"x-filevine-api-version": "3.3426.3.0",
|
||||||
|
"x-fv-correlation-id": "4562cb54a936470cb3fb463db5837dab",
|
||||||
|
"x-aspnet-version": "4.0.30319",
|
||||||
|
"x-powered-by": "ASP.NET",
|
||||||
|
"x-content-type-options": "nosniff",
|
||||||
|
"x-frame-option": "SAMEORIGIN",
|
||||||
|
"x-xss-protection": "1; mode=block",
|
||||||
|
"x-fv-gateway-correlation-id": "4562cb54a936470cb3fb463db5837dab",
|
||||||
|
"cf-cache-status": "DYNAMIC",
|
||||||
|
"Content-Encoding": "gzip",
|
||||||
|
"CF-RAY": "992d12bd2939decc-SEA",
|
||||||
|
"alt-svc": "h3=\":443\"; ma=86400"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
generate_sample.py
Normal file
111
generate_sample.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import os
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables from .env file
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
def get_bearer_token():
|
||||||
|
"""Request a bearer token using credentials from environment variables."""
|
||||||
|
url = "https://identity.filevine.com/connect/token"
|
||||||
|
data = {
|
||||||
|
"client_id": os.environ.get("FILEVINE_CLIENT_ID"),
|
||||||
|
"client_secret": os.environ.get("FILEVINE_CLIENT_SECRET"),
|
||||||
|
"grant_type": "personal_access_token",
|
||||||
|
"scope": "fv.api.gateway.access tenant filevine.v2.api.* email openid fv.auth.tenant.read",
|
||||||
|
"token": os.environ.get("FILEVINE_PERSONAL_ACCESS_TOKEN"),
|
||||||
|
}
|
||||||
|
headers = {"Accept": "application/json"}
|
||||||
|
response = requests.post(url, data=data, headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json().get("access_token")
|
||||||
|
|
||||||
|
# Define the collection of request/response pairs
|
||||||
|
# User can add more tuples following the same pattern
|
||||||
|
SAMPLE_PROJECT_ID = 15905506
|
||||||
|
REQUESTS = [
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"url": "https://api.filevineapp.com/fv-app/v2/projects",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {get_bearer_token()}",
|
||||||
|
"x-fv-orgid": os.environ.get("FILEVINE_ORG_ID"),
|
||||||
|
"x-fv-userid": os.environ.get("FILEVINE_USER_ID"),
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
|
||||||
|
},
|
||||||
|
"examples/project_list.json"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"url": f"https://api.filevineapp.com/fv-app/v2/Projects/{SAMPLE_PROJECT_ID}/contacts",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {get_bearer_token()}",
|
||||||
|
"x-fv-orgid": os.environ.get("FILEVINE_ORG_ID"),
|
||||||
|
"x-fv-userid": os.environ.get("FILEVINE_USER_ID"),
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
|
||||||
|
},
|
||||||
|
"examples/project_contacts.json"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"url": f"https://api.filevineapp.com/fv-app/v2/contacts/43125866",
|
||||||
|
"headers": {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": f"Bearer {get_bearer_token()}",
|
||||||
|
"x-fv-orgid": os.environ.get("FILEVINE_ORG_ID"),
|
||||||
|
"x-fv-userid": os.environ.get("FILEVINE_USER_ID"),
|
||||||
|
},
|
||||||
|
"params": {},
|
||||||
|
"method": "GET"
|
||||||
|
|
||||||
|
},
|
||||||
|
"examples/client.json"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
def generate_sample_request_response(request_config):
|
||||||
|
"""Generate a sample request/response pair using the provided request configuration."""
|
||||||
|
# Make the request
|
||||||
|
response = requests.request(**request_config)
|
||||||
|
|
||||||
|
# Create structured output
|
||||||
|
result = {
|
||||||
|
"sample_request": request_config,
|
||||||
|
"sample_response": {
|
||||||
|
"status_code": response.status_code,
|
||||||
|
"json": response.json() if response.content else None,
|
||||||
|
"headers": dict(response.headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
# Ensure examples directory exists
|
||||||
|
os.makedirs("examples", exist_ok=True)
|
||||||
|
|
||||||
|
# Process each request/response pair
|
||||||
|
for request_config, output_path in REQUESTS:
|
||||||
|
# Regenerate bearer token for each request (tokens may expire)
|
||||||
|
request_config["headers"]["Authorization"] = f"Bearer {get_bearer_token()}"
|
||||||
|
|
||||||
|
result = generate_sample_request_response(request_config)
|
||||||
|
|
||||||
|
# Save pretty printed JSON to file
|
||||||
|
with open(output_path, 'w') as f:
|
||||||
|
json.dump(result, f, indent=2)
|
||||||
|
|
||||||
|
print(f"Generated {len(REQUESTS)} sample request/response pairs")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Flask==3.0.3
|
||||||
|
firebase-admin==6.6.0
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
requests==2.32.3
|
||||||
|
itsdangerous==2.2.0
|
||||||
13
rothbard-service-account.json
Executable file
13
rothbard-service-account.json
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"type": "service_account",
|
||||||
|
"project_id": "rothbard-3f496",
|
||||||
|
"private_key_id": "58d242c0d372e3ae4821e1b32e2d4be8ca718fde",
|
||||||
|
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5OuQyds3Gdvsw\n44ZJLekGrqt0ktj5YjSvfEjzk7jZuMJITy+mCpohfm6JUv6IRl1MHY+P8sxM9xiT\nkLF3EXeAyyWXVWx4KjpGX0KeG4IfSZhnMKljDBtZIyxJhOvy54+QBFcRqjIeeB5s\n5EHG2jJySOzDUA7JMzP/Oo0MmU332ylLU3NIutolccs1XC/ymi2ocHpgcGhENl40\nDLvn6ZMS3hEulkaUDfMBovJrvvjWWxbK4HLb+04m2+XD98uOmD3x3/nUWuiLNMH+\n1mJNzVRgiNFCDyqg3brUWP6eEWeF0W66QWPk7SV72lPsf8Ldq7BicS5p5k4gMxO2\ng+eaAkZxAgMBAAECggEAL+GOTZEyXiQxiJC4DMCmZQjP32F6XvTI47f/7573AKjm\n5+Q4T/abox7YmfzvOPDfeyaFDtPXhem126diiIHmX0+kFvuI/4MC71/+i3pW55mR\noNMOZkEh7KfP8e0/RNog3TyR+UoCjKfGTaWvbyTGN46sTUyrlcz7mvVasrAKXJBE\nLtyvz5BpXpikybC70MDY/bDKUxrl45AaRR/FuBTqDj7wK56O1TMaviRZUks6GHUM\nYphoammseQi1X/OjxwjtUHgclKcZN3r1F+tYdbBMGLbKGu8rRjEr8y8vLJAVxK0M\nSVsNzjlsUFGF/RVljb38tlqKXchZ+DJ3FZ3fyU4YFQKBgQD2FucwWnoQi0E0d9kX\nJWgmoH9fYwDr6NpD7k9bLW4ktrWTEENAzfV9/cfFRlFbHA5Zk35a4xKYY3ZXiO76\n0Xk5nkhWrymNd46yT094SInEugaKfBAw6Xo243Jq6/eR7GD1KSL+9z+4oCtQ+JHv\nepAiTBDGNOUuXQT06ONJrEUXPwKBgQDAsIx/rJdcaH0XZH+0TeNY0fe5U9LAdNZm\nkNeVSaMBY+UuRvZt0Y0C3F54ngXfEtmAwvQ4LVgBmJVv4JAkETRowAJeD2RflhYl\n4s7aaPyh0GJJ4/j8/XP0TZN5gv7D3MNJAh2bJLluONjZmWgckaRlU8E2za2EZSqY\nW2bmoFNmTwKBgAZLF6Z46d46cXRyDC83Wa6DND6wPXnK/qn2Ejl2s/ZkZchZBh9G\nJR0PvGgjIDmAQi2wQ+73F6amBITAj7wCV2NN1PPCjwF7KT8OIC4nTL6nMzufaJqX\nnfSBZI+vcSleLiyW3LpAgHSsQ+9SLAk/zSfTYipvd9zzrAjHW+iqaynpAoGAMjZP\nhn29O7Fm14+yz5N0aRLeEQdM5iYMMNIRu69isNwNPs/zK47txg8S9y+GrCjHUQx8\ng58dTd0rI+pK5XsuQxW2CDjOmTINN3YxHS06mBgrZMHpglOxwbntcj62kOeYZBAP\nEvyw7Y4WxC17ueYiBt2afeN/Ef8i6Gz5FaQ113UCgYBr39cTINpIuwDyfDAqu032\n0zP/8GFE5zb4VlGoKC2Ma/9x+nkOf05eXqv1jOpq+hsYlBe9mrufeF0gcKAycHWn\nW1QgkepPXlrvFXws928TQUGv+Jp63UMdNWXbfh4ZIp3vhAAdh+h8TcvRyVrADZgB\nqZXfdtkfYTQewM7p8vno3Q==\n-----END PRIVATE KEY-----\n",
|
||||||
|
"client_email": "firebase-adminsdk-fbsvc@rothbard-3f496.iam.gserviceaccount.com",
|
||||||
|
"client_id": "112093576377036658724",
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token",
|
||||||
|
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40rothbard-3f496.iam.gserviceaccount.com",
|
||||||
|
"universe_domain": "googleapis.com"
|
||||||
|
}
|
||||||
2
static/auth.js
Normal file
2
static/auth.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
(function(){
|
||||||
|
})();
|
||||||
28
templates/base.html
Normal file
28
templates/base.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>{{ title or 'App' }}</title>
|
||||||
|
<!-- Tailwind (CDN for demo; consider self-hosting for prod) -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
</head>
|
||||||
|
<body class="min-h-screen bg-slate-50 text-slate-900">
|
||||||
|
<header class="border-b bg-white">
|
||||||
|
<div class="max-w-5xl mx-auto p-4 flex items-center justify-between">
|
||||||
|
<a href="/" class="font-semibold">Filevine Demo</a>
|
||||||
|
<nav class="space-x-4">
|
||||||
|
{% if session.uid %}
|
||||||
|
<a href="/dashboard" class="text-sm text-slate-600 hover:text-slate-900">Dashboard</a>
|
||||||
|
<a href="/logout" class="text-sm text-slate-600 hover:text-slate-900">Logout</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/login" class="text-sm text-slate-600 hover:text-slate-900">Login</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="max-w-5xl mx-auto p-6">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
45
templates/dashboard.html
Normal file
45
templates/dashboard.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<h1 class="text-xl font-semibold mb-4">Projects for {{ case_email }}</h1>
|
||||||
|
<div class="bg-white shadow rounded-2xl overflow-hidden">
|
||||||
|
<table class="min-w-full">
|
||||||
|
<thead class="bg-slate-100 text-left text-sm">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-3">Project Email</th>
|
||||||
|
<th class="px-4 py-3">Matter Description</th>
|
||||||
|
<th class="px-4 py-3">Number</th>
|
||||||
|
<th class="px-4 py-3">Incident Date</th>
|
||||||
|
<th class="px-4 py-3">Name</th>
|
||||||
|
<th class="px-4 py-3">Link</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y">
|
||||||
|
{% for r in rows %}
|
||||||
|
<tr class="hover:bg-slate-50">
|
||||||
|
<td class="px-4 py-3 text-sm">{{ r.client or '—' }}</td>
|
||||||
|
<td class="px-4 py-3 text-sm">{{ r.matter_description or '—' }}</td>
|
||||||
|
<td class="px-4 py-3 text-sm">
|
||||||
|
<ul>
|
||||||
|
{% for c in r.contacts %}
|
||||||
|
<li>{{ c.orgContact.firstName }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td class="px-4 py-3 text-sm">{{ r.Number or '—' }}</td>
|
||||||
|
<td class="px-4 py-3 text-sm">{{ (r.IncidentDate or '')[:10] }}</td>
|
||||||
|
<td class="px-4 py-3 text-sm">{{ r.ProjectName or '—' }}</td>
|
||||||
|
<td class="px-4 py-3 text-sm">
|
||||||
|
{% if r.projectUrl %}
|
||||||
|
<a class="text-blue-600 hover:underline" href="{{ r.projectUrl }}" target="_blank">Open</a>
|
||||||
|
{% else %}—{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="px-4 py-6 text-center text-slate-500">No matching projects found.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
69
templates/login.html
Normal file
69
templates/login.html
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="max-w-md mx-auto bg-white shadow rounded-2xl p-6">
|
||||||
|
<h1 class="text-xl font-semibold mb-4">Sign in</h1>
|
||||||
|
<form id="login-form" class="space-y-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-1">Email</label>
|
||||||
|
<input id="email" type="email" required class="w-full border rounded-lg p-2" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-1">Password</label>
|
||||||
|
<input id="password" type="password" required class="w-full border rounded-lg p-2" />
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="w-full py-2 rounded-lg bg-slate-900 text-white">Sign in</button>
|
||||||
|
<p id="error" class="text-sm text-red-600 mt-2 hidden"></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Firebase App (the core Firebase SDK) -->
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/12.4.0/firebase-app-compat.js"></script>
|
||||||
|
|
||||||
|
<!-- Firebase Auth -->
|
||||||
|
<script src="https://www.gstatic.com/firebasejs/12.4.0/firebase-auth-compat.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.FIREBASE_CONFIG = {{ firebase_config|tojson }};
|
||||||
|
// import { initializeApp } from 'https://www.gstatic.com/firebasejs/12.4.0/firebase-app.js'
|
||||||
|
|
||||||
|
// // If you enabled Analytics in your project, add the Firebase SDK for Google Analytics
|
||||||
|
// import { getAnalytics } from 'https://www.gstatic.com/firebasejs/12.4.0/firebase-analytics.js'
|
||||||
|
|
||||||
|
// // Add Firebase products that you want to use
|
||||||
|
// import { getAuth } from 'https://www.gstatic.com/firebasejs/12.4.0/firebase-auth.js'
|
||||||
|
// import { getFirestore } from 'https://www.gstatic.com/firebasejs/12.4.0/firebase-firestore.js'
|
||||||
|
|
||||||
|
const app = firebase.initializeApp(window.FIREBASE_CONFIG || {});
|
||||||
|
const auth = firebase.auth()
|
||||||
|
console.log(app)
|
||||||
|
console.log(auth)
|
||||||
|
console.log(auth.signInWithEmailAndPassword)
|
||||||
|
|
||||||
|
const form = document.getElementById('login-form');
|
||||||
|
const email = document.getElementById('email');
|
||||||
|
const password = document.getElementById('password');
|
||||||
|
const err = document.getElementById('error');
|
||||||
|
|
||||||
|
form.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
err.classList.add('hidden');
|
||||||
|
try {
|
||||||
|
const cred = await auth.signInWithEmailAndPassword(email.value, password.value);
|
||||||
|
const idToken = await cred.user.getIdToken();
|
||||||
|
const res = await fetch('/session_login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ idToken })
|
||||||
|
});
|
||||||
|
if(!res.ok){
|
||||||
|
throw new Error('Session exchange failed');
|
||||||
|
}
|
||||||
|
window.location.href = '/';
|
||||||
|
} catch (e) {
|
||||||
|
err.textContent = e.message || 'Login failed';
|
||||||
|
err.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
11
templates/welcome.html
Normal file
11
templates/welcome.html
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block content %}
|
||||||
|
<div class="bg-white shadow rounded-2xl p-6">
|
||||||
|
<h1 class="text-xl font-semibold mb-2">Welcome!</h1>
|
||||||
|
<p class="text-slate-700">Your account is almost ready. An administrator will finish setup soon.</p>
|
||||||
|
<ul class="mt-4 list-disc pl-6 text-sm text-slate-700">
|
||||||
|
<li><strong>enabled</strong>: {{ 'true' if profile.enabled else 'false' }}</li>
|
||||||
|
<li><strong>caseEmail</strong>: {{ profile.caseEmail or '—' }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user