From 13cb1b94cbee9f5b3a5dc1b58f7e9c389cff4d2f Mon Sep 17 00:00:00 2001 From: Jakub Kadlcik Date: Wed, 28 Aug 2024 15:10:27 +0200 Subject: [PATCH] backend, frontend: put result ID into review URL Fix #155 --- backend/src/api.py | 39 ++++++++++++++++++++++++------- backend/src/exceptions.py | 8 +++---- backend/src/store.py | 11 +++++++++ frontend/src/app/review/core.cljs | 12 ++++++---- 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/backend/src/api.py b/backend/src/api.py index ee3c683..266db6d 100644 --- a/backend/src/api.py +++ b/backend/src/api.py @@ -9,7 +9,12 @@ from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError -from fastapi.responses import HTMLResponse, JSONResponse, FileResponse +from fastapi.responses import ( + HTMLResponse, + JSONResponse, + FileResponse, + RedirectResponse, +) from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from pydantic import BaseModel @@ -41,6 +46,7 @@ ) from src.spells import make_tar, find_file_by_name from src.store import Storator3000 +from src.exceptions import NoDataFound logger = logging.getLogger(__name__) @@ -106,7 +112,16 @@ def documentation(request: Request): return template_response("documentation.html", {"request": request}) -@app.get("/review", response_class=HTMLResponse) +@app.get("/review", response_class=RedirectResponse) +def review_redirect(): + """ + Redirect to a review URL that contains some result ID + """ + result = Storator3000.get_random() + return f"/review/{result.stem}" + + +@app.get("/review/{result_id}", response_class=HTMLResponse) def review(request: Request): return template_response("review.html", {"request": request}) @@ -261,12 +276,20 @@ def contribute_review_container_logs( return _store_data_for_providers(feedback_input, ProvidersEnum.container, url) -@app.get("/frontend/review/random") -def frontend_review_random(): - random_feedback_file = Storator3000.get_random() - with open(random_feedback_file) as random_file: - content = json.loads(random_file.read()) - return FeedbackSchema(**content).dict() | {"id": random_feedback_file.name.rstrip(".json")} +@app.get("/frontend/review/{result_id}") +def frontend_review_random(result_id): + if result_id == "random": + feedback_file = Storator3000.get_random() + else: + feedback_file = Storator3000.get_by_id(result_id) + + if not feedback_file: + raise NoDataFound(f"No result with ID {result_id}") + + with open(feedback_file) as fp: + content = json.loads(fp.read()) + return FeedbackSchema(**content).dict() \ + | {"id": feedback_file.name.rstrip(".json")} def _get_text_from_feedback(item: dict) -> str: diff --git a/backend/src/exceptions.py b/backend/src/exceptions.py index 2518291..9d173f5 100644 --- a/backend/src/exceptions.py +++ b/backend/src/exceptions.py @@ -3,10 +3,6 @@ from fastapi import HTTPException -class NoDataFound(Exception): - pass - - class FetchError(HTTPException): """ Unable to fetch the logs from the outside world for any reason. @@ -14,3 +10,7 @@ class FetchError(HTTPException): def __init__(self, detail=None) -> None: super().__init__(status_code=HTTPStatus.NOT_FOUND, detail=detail) + + +class NoDataFound(FetchError): + pass diff --git a/backend/src/store.py b/backend/src/store.py index 546dcb2..55cccff 100644 --- a/backend/src/store.py +++ b/backend/src/store.py @@ -57,6 +57,17 @@ def get_random(cls) -> Path: return Path(random.choice(files)) + @classmethod + def get_by_id(cls, result_id: str) -> Path | None: + """ + Return a result based on its ID + """ + files = cls.get_logs() + for path in files: + if os.path.basename(path).split(".")[0] == result_id: + return Path(path) + return None + @classmethod def get_stats(cls) -> dict: """Retrieve basic statistics about submitted reports. diff --git a/frontend/src/app/review/core.cljs b/frontend/src/app/review/core.cljs index 4ea6fd5..74fd0da 100644 --- a/frontend/src/app/review/core.cljs +++ b/frontend/src/app/review/core.cljs @@ -2,11 +2,10 @@ (:require [clojure.set :refer [rename-keys]] [ajax.core :refer [GET POST]] + [clojure.string :as str] [malli.core :as m] [app.helpers :refer - [current-path - remove-trailing-slash - safe + [safe fontawesome-icon]] [app.editor.core :refer [editor active-file]] [app.components.accordion :refer [accordion]] @@ -116,8 +115,13 @@ (reset! error-title title) (reset! error-description description)) +(defn result-id-from-url [] + (let [split (-> js/window .-location .-href (str/split "/review/"))] + (when (> (count split) 1) + (last split)))) + (defn init-data-review [] - (GET (str "/frontend" (remove-trailing-slash (current-path)) "/random") + (GET (str "/frontend/review/" (or (result-id-from-url) "random")) :response-format :json :keywords? true