diff --git a/scripts/lab/app.py b/scripts/lab/app.py index 0207113..6f2d4a3 100644 --- a/scripts/lab/app.py +++ b/scripts/lab/app.py @@ -25,8 +25,13 @@ def show_response(response: requests.Response) -> None: st.text(response.text) -def json_input(label: str, value: dict[str, Any]) -> dict[str, Any] | None: - raw = st.text_area(label, json.dumps(value, indent=2), height=180) +def request(method: str, path: str, **kwargs: Any) -> requests.Response: + kwargs.setdefault("timeout", 10) + return requests.request(method, api_url(path), **kwargs) + + +def json_input(label: str, value: dict[str, Any], height: int = 180) -> dict[str, Any] | None: + raw = st.text_area(label, json.dumps(value, indent=2), height=height) try: return json.loads(raw) except json.JSONDecodeError as error: @@ -34,13 +39,32 @@ def json_input(label: str, value: dict[str, Any]) -> dict[str, Any] | None: return None +def pagination(prefix: str) -> dict[str, int]: + col1, col2 = st.columns(2) + with col1: + page = st.number_input(f"{prefix} page", min_value=1, value=1, step=1) + with col2: + per_page = st.number_input( + f"{prefix} per_page", min_value=1, max_value=100, value=20, step=1 + ) + return {"page": page, "per_page": per_page} + + +def response_json(response: requests.Response) -> dict[str, Any]: + try: + data = response.json() + except ValueError: + return {} + return data if isinstance(data, dict) else {} + + if "base_url" not in st.session_state: st.session_state.base_url = "http://127.0.0.1:5555/api/v1" st.title("Visione API Lab") -auth_tab, reports_tab, admin_tab, docs_tab = st.tabs( - ["Auth", "Reports", "Admin", "Docs"] +auth_tab, reports_tab, operator_tab, user_tab, admin_tab, public_tab, docs_tab = st.tabs( + ["Auth", "Reports", "Operator", "User", "Admin", "Public", "Docs"] ) with auth_tab: @@ -50,13 +74,12 @@ with auth_tab: email = st.text_input("Email", "admin@visione.local") password = st.text_input("Password", "ChangeMe123!", type="password") if st.button("Login"): - response = requests.post( - api_url("/auth/login/password"), + response = request( + "POST", + "/auth/login/password", json={"email": email, "password": password}, - timeout=10, ) - data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {} - token = data.get("token") + token = response_json(response).get("token") if token: st.session_state.token = token show_response(response) @@ -64,22 +87,15 @@ with auth_tab: st.subheader("OTP") otp_email = st.text_input("OTP email", "citizen@example.com") if st.button("Request OTP"): - show_response( - requests.post( - api_url("/auth/otp/request"), - json={"email": otp_email}, - timeout=10, - ) - ) + show_response(request("POST", "/auth/otp/request", json={"email": otp_email})) otp_code = st.text_input("OTP code") if st.button("Verify OTP"): - response = requests.post( - api_url("/auth/otp/verify"), + response = request( + "POST", + "/auth/otp/verify", json={"email": otp_email, "code": otp_code}, - timeout=10, ) - data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {} - token = data.get("token") + token = response_json(response).get("token") if token: st.session_state.token = token show_response(response) @@ -98,11 +114,29 @@ with auth_tab: }, ) if st.button("Register") and payload: - show_response(requests.post(api_url("/auth/register"), json=payload, timeout=10)) + show_response(request("POST", "/auth/register", json=payload)) st.subheader("Me") if st.button("GET /me"): - show_response(requests.get(api_url("/me"), headers=headers(), timeout=10)) + show_response(request("GET", "/me", headers=headers())) + + st.subheader("Change password") + current_password = st.text_input( + "Current password", "ChangeMe123!", type="password" + ) + new_password = st.text_input("New password", "ChangeMe123!!", type="password") + if st.button("Change password"): + show_response( + request( + "POST", + "/auth/change-password", + json={ + "current_password": current_password, + "new_password": new_password, + }, + headers=headers(), + ) + ) with reports_tab: col1, col2 = st.columns(2) @@ -119,38 +153,51 @@ with reports_tab: }, ) if st.button("Create report") and report_payload: - show_response( - requests.post( - api_url("/reports"), - json=report_payload, - headers=headers(), - timeout=10, - ) - ) + show_response(request("POST", "/reports", json=report_payload, headers=headers())) st.subheader("List reports") - status = st.text_input("Status filter") - params = {"status": status} if status else {} + list_col1, list_col2, list_col3 = st.columns(3) + with list_col1: + status = st.text_input("Status filter") + with list_col2: + category_id = st.text_input("Category id filter") + with list_col3: + area_id = st.text_input("Area id filter") + params = { + key: value + for key, value in { + "status": status, + "category_id": category_id, + "area_id": area_id, + }.items() + if value + } if st.button("GET /reports"): - show_response( - requests.get( - api_url("/reports"), - params=params, - headers=headers(), - timeout=10, - ) - ) + show_response(request("GET", "/reports", params=params, headers=headers())) with col2: report_id = st.number_input("Report id", min_value=1, step=1) if st.button("Detail"): - show_response( - requests.get( - api_url(f"/reports/{report_id}"), - headers=headers(), - timeout=10, + show_response(request("GET", f"/reports/{report_id}", headers=headers())) + + st.subheader("Messages") + message_payload = json_input("Message payload", {"body": "Messaggio dal lab"}, 120) + msg_col1, msg_col2 = st.columns(2) + with msg_col1: + if st.button("Add message") and message_payload: + show_response( + request( + "POST", + f"/reports/{report_id}/messages", + json=message_payload, + headers=headers(), + ) + ) + with msg_col2: + if st.button("List messages"): + show_response( + request("GET", f"/reports/{report_id}/messages", headers=headers()) ) - ) st.subheader("Upload media") files = st.file_uploader( @@ -164,8 +211,9 @@ with reports_tab: for file in files ] show_response( - requests.post( - api_url(f"/reports/{report_id}/media"), + request( + "POST", + f"/reports/{report_id}/media", headers=headers(), files=multipart, timeout=60, @@ -179,29 +227,245 @@ with reports_tab: ) if st.button("Update status"): show_response( - requests.patch( - api_url(f"/reports/{report_id}/status"), + request( + "PATCH", + f"/reports/{report_id}/status", json={"status": new_status, "note": "Updated from Visione Lab"}, headers=headers(), - timeout=10, + ) + ) + if st.button("Take report"): + show_response(request("POST", f"/reports/{report_id}/take", headers=headers())) + + st.subheader("Assignment and feedback") + team_id = st.number_input("Team id", min_value=1, step=1) + assign_col, feedback_col = st.columns(2) + with assign_col: + if st.button("Assign team"): + show_response( + request( + "POST", + f"/reports/{report_id}/assignments", + json={"team_id": team_id}, + headers=headers(), + ) + ) + with feedback_col: + feedback_payload = json_input( + "Feedback payload", {"rating": 5, "comment": "Intervento risolto"}, 120 + ) + if st.button("Add feedback") and feedback_payload: + show_response( + request( + "POST", + f"/reports/{report_id}/feedback", + json=feedback_payload, + headers=headers(), + ) + ) + +with operator_tab: + col1, col2 = st.columns(2) + with col1: + st.subheader("Operator queues") + queue_params = pagination("Queue") + queue_endpoint = st.selectbox( + "Queue", + [ + "/operator/reports/assigned", + "/operator/reports/open", + "/operator/reports/others", + ], + ) + if st.button("GET operator queue"): + show_response( + request("GET", queue_endpoint, params=queue_params, headers=headers()) + ) + + st.subheader("Intervention summary") + summary_report_id = st.number_input( + "Summary report id", min_value=1, value=1, step=1 + ) + if st.button("GET intervention summary"): + show_response( + request( + "GET", + f"/reports/{summary_report_id}/intervention-summary", + headers=headers(), ) ) + with col2: + st.subheader("Flag content") + flag_report_id = st.number_input("Flag report id", min_value=1, value=1, step=1) + flag_payload = json_input( + "Flag payload", + {"reason": "abusive_content", "details": "Created from Visione Lab"}, + 140, + ) + if st.button("Flag report") and flag_payload: + show_response( + request( + "POST", + f"/reports/{flag_report_id}/flags", + json=flag_payload, + headers=headers(), + ) + ) + message_id = st.number_input("Flag message id", min_value=1, value=1, step=1) + if st.button("Flag message") and flag_payload: + show_response( + request( + "POST", + f"/reports/{flag_report_id}/messages/{message_id}/flags", + json=flag_payload, + headers=headers(), + ) + ) + +with user_tab: + col1, col2 = st.columns(2) + with col1: + st.subheader("Notifications") + notification_params = pagination("Notifications") + if st.button("List notifications"): + show_response( + request( + "GET", + "/notifications", + params=notification_params, + headers=headers(), + ) + ) + notification_id = st.number_input("Notification id", min_value=1, step=1) + if st.button("Mark notification read"): + show_response( + request( + "PATCH", + f"/notifications/{notification_id}/read", + headers=headers(), + ) + ) + + with col2: + st.subheader("Rewards") + rewards_params = pagination("Rewards") + if st.button("GET /me/rewards"): + show_response( + request("GET", "/me/rewards", params=rewards_params, headers=headers()) + ) + with admin_tab: - st.subheader("Reference data") - endpoint = st.selectbox("Endpoint", ["/admin/categories", "/admin/areas", "/admin/teams", "/admin/stats/overview", "/admin/users"]) - if st.button("GET admin endpoint"): - show_response(requests.get(api_url(endpoint), headers=headers(), timeout=10)) + col1, col2 = st.columns(2) + with col1: + st.subheader("Reference data and stats") + endpoint = st.selectbox( + "Endpoint", + [ + "/admin/categories", + "/admin/areas", + "/admin/teams", + "/admin/stats/overview", + "/admin/users", + ], + ) + if st.button("GET admin endpoint"): + show_response(request("GET", endpoint, headers=headers())) + + st.subheader("Create reference data") + create_endpoint = st.selectbox( + "Create endpoint", ["/admin/categories", "/admin/areas", "/admin/teams"] + ) + create_payload = json_input( + "Create payload", + {"name": "Nuova categoria", "description": "Created from Visione Lab"}, + ) + if st.button("POST admin endpoint") and create_payload: + show_response( + request( + "POST", + create_endpoint, + json=create_payload, + headers=headers(), + ) + ) + + with col2: + st.subheader("User administration") + admin_user_id = st.number_input("Admin target user id", min_value=1, step=1) + roles_payload = json_input("Roles payload", {"roles": ["operator"]}, 100) + if st.button("Update roles") and roles_payload: + show_response( + request( + "PATCH", + f"/admin/users/{admin_user_id}/roles", + json=roles_payload, + headers=headers(), + ) + ) + banned = st.checkbox("Banned") + if st.button("Update ban"): + show_response( + request( + "PATCH", + f"/admin/users/{admin_user_id}/ban", + json={"banned": banned}, + headers=headers(), + ) + ) + + st.subheader("Moderation") + moderation_params = pagination("Moderation") + moderation_status = st.selectbox( + "Moderation status", ["", "OPEN", "RESOLVED", "DISMISSED"] + ) + if moderation_status: + moderation_params["status"] = moderation_status + if st.button("List moderation flags"): + show_response( + request( + "GET", + "/admin/moderation", + params=moderation_params, + headers=headers(), + ) + ) + flag_id = st.number_input("Moderation flag id", min_value=1, step=1) + moderation_payload = json_input( + "Moderation update payload", + { + "status": "RESOLVED", + "resolution_note": "Reviewed from Visione Lab", + "reject_report": False, + }, + 140, + ) + if st.button("Update moderation flag") and moderation_payload: + show_response( + request( + "PATCH", + f"/admin/moderation/{flag_id}", + json=moderation_payload, + headers=headers(), + ) + ) + +with public_tab: + st.subheader("Open data") + open_data_params = pagination("Open data") + if st.button("GET /open-data/reports"): + show_response( + request("GET", "/open-data/reports", params=open_data_params) + ) with docs_tab: st.link_button("Swagger UI", api_url("/docs")) if st.button("Fetch OpenAPI"): - show_response(requests.get(api_url("/openapi.json"), timeout=10)) + show_response(request("GET", "/openapi.json")) with st.sidebar: st.text_input("Backend API", key="base_url") st.text_input("Bearer token", key="token", type="password") st.link_button("MailHog", "http://127.0.0.1:8025") if st.button("Health check"): - show_response(requests.get(api_url("/health"), timeout=5)) - + show_response(request("GET", "/health", timeout=5))