diff --git a/NIPTool/API/external/api/api_v1/endpoints/login.py b/NIPTool/API/external/api/api_v1/endpoints/login.py index 29083892..83c538ed 100644 --- a/NIPTool/API/external/api/api_v1/endpoints/login.py +++ b/NIPTool/API/external/api/api_v1/endpoints/login.py @@ -42,7 +42,6 @@ def login(token: Token = Depends(login_for_access_token)): "Authorization": f"{token.get('token_type')} {token.get('access_token')}", "accept": "application/json", } - print(headers) return RedirectResponse("../batches", headers=headers) diff --git a/NIPTool/API/external/api/api_v1/endpoints/sample.py b/NIPTool/API/external/api/api_v1/endpoints/sample.py index e4b9123b..bfddfd60 100644 --- a/NIPTool/API/external/api/api_v1/endpoints/sample.py +++ b/NIPTool/API/external/api/api_v1/endpoints/sample.py @@ -14,8 +14,30 @@ @router.get("/samples/{sample_id}/") def sample(request: Request, sample_id: str, adapter: NiptAdapter = Depends(get_nipt_adapter)): """Sample view with sample information.""" + sample: dict = find.sample(sample_id=sample_id, adapter=adapter).dict() - batch = find.batch(batch_id=sample.get("batch_id"), adapter=adapter) + batch: Batch = find.batch(batch_id=sample.get("batch_id"), adapter=adapter) + + return templates.TemplateResponse( + "sample/sample.html", + context=dict( + request=request, + current_user=User(username="mayapapaya", email="mayabrandi@123.com", role="RW"), + chrom_abnorm=CHROM_ABNORM, + sample=sample, + status_classes=STATUS_CLASSES, + batch=batch, + page_id="sample", + ), + ) + + +@router.post("/samples/{sample_id}/") +def sample(request: Request, sample_id: str, adapter: NiptAdapter = Depends(get_nipt_adapter)): + """Sample view with sample information.""" + + sample: dict = find.sample(sample_id=sample_id, adapter=adapter).dict() + batch: Batch = find.batch(batch_id=sample.get("batch_id"), adapter=adapter) return templates.TemplateResponse( "sample/sample.html", diff --git a/NIPTool/API/external/api/api_v1/endpoints/update.py b/NIPTool/API/external/api/api_v1/endpoints/update.py index 5ce39505..220b84e6 100644 --- a/NIPTool/API/external/api/api_v1/endpoints/update.py +++ b/NIPTool/API/external/api/api_v1/endpoints/update.py @@ -1,11 +1,12 @@ import logging from typing import Iterable -from typing import Optional from fastapi import APIRouter, Depends, Request from fastapi.responses import RedirectResponse +from starlette.datastructures import FormData + from NIPTool.adapter.plugin import NiptAdapter -from NIPTool.crud import find, update +from NIPTool.crud import update from NIPTool.models.database import User from NIPTool.API.external.utils import * @@ -16,89 +17,105 @@ LOG = logging.getLogger(__name__) -from pydantic import BaseModel +USER = User(username="mayapapaya", email="mayapapaya@mail.com", role="RW") + + +@router.post("/set_sample_status") +async def set_sample_status(request: Request, adapter: NiptAdapter = Depends(get_nipt_adapter)): + """Update the manualy interpreted chromosome abnormality status for a sample.""" + + form = await request.form() + + if USER.role != "RW": + return RedirectResponse(request.headers.get("referer")) + + sample_id: str = form["sample_id"] + sample: dict = find.sample(sample_id=sample_id, adapter=adapter).dict() + + for abnormality in CHROM_ABNORM: + new_abnormality_status: str = form[abnormality] + abnormality_key: str = f"status_{abnormality}" + if sample.get(abnormality_key) == new_abnormality_status: + continue + + LOG.debug( + "Updating %s to %s for sample %s", + abnormality_key, + new_abnormality_status, + sample_id, + ) + time_stamp: str = datetime.now().strftime("%Y/%m/%d %H:%M:%S") + sample[abnormality_key] = new_abnormality_status + sample[f"status_change_{abnormality}"] = f"{USER.username} {time_stamp}" + + update.sample(adapter=adapter, sample=Sample(**sample)) + return RedirectResponse(request.headers.get("referer")) + +@router.post("/sample_comment") +async def sample_comment(request: Request, adapter: NiptAdapter = Depends(get_nipt_adapter)): + """Update sample comment""" -class Item(BaseModel): - form_id: str - sample_id: Optional[str] + form = await request.form() + if USER.role != "RW": + return RedirectResponse(request.headers.get("referer")) -@router.post("/update_debugging") -def update_debugging( - request: Request, item: Item, adapter: NiptAdapter = Depends(get_nipt_adapter) -): - """Update the database""" - print(item) - print("hej") - time_stamp = datetime.now().strftime("%Y/%m/%d %H:%M:%S") - user = User(username="mayapapaya", email="mayabrandi@123.com", role="RW") - if user.role != "RW": - return "", 201 + sample_id: str = form["sample_id"] + sample: Sample = find.sample(sample_id=sample_id, adapter=adapter) + comment: str = form.get("comment") + if comment != sample.comment: + sample.comment = comment + update.sample(adapter=adapter, sample=sample) - return RedirectResponse("batches/342712/") + return RedirectResponse(request.headers.get("referer")) -@router.post("/update") -def update(request: Request, adapter: NiptAdapter = Depends(get_nipt_adapter)): - """Update the database""" +@router.post("/include_samples") +async def include_samples(request: Request, adapter: NiptAdapter = Depends(get_nipt_adapter)): + """Update include status and comment for samples in batch""" + + form = await request.form() + + if USER.role != "RW": + return RedirectResponse(request.headers.get("referer")) + + button_id = form.get("button_id") + samples: Iterable[str] = form.getlist("samples") + if button_id == "include all samples": + include_all_samples(samples=samples, adapter=adapter) + elif button_id == "Save": + save_samples(samples=samples, form=form, adapter=adapter) + + return RedirectResponse(request.headers.get("referer")) + + +def save_samples(samples: Iterable[str], form: FormData, adapter: NiptAdapter): + """Function to update sample.comment and sample.include.""" time_stamp: str = datetime.now().strftime("%Y/%m/%d %H:%M:%S") - user = User(username="mayapapaya", email="mayapapaya@mail.com", role="RW") - - if user.role != "RW": - return "", 201 - - if request.form.get("form_id") == "set_sample_status": - sample_id: str = request.form["sample_id"] - sample: Sample = find.sample(sample_id=sample_id) - # Convert to dict to fetch statuses - sample_dict: dict = sample.dict() - for abnormality in CHROM_ABNORM: - new_abnormality_status: str = request.form[abnormality] - abnormality_key: str = "_".join(["status", abnormality]) - if sample_dict.get(abnormality_key) != new_abnormality_status: - LOG.debug( - "Updating %s to %s for sample %s", - abnormality_key, - new_abnormality_status, - sample_id, - ) - sample[abnormality_key] = new_abnormality_status - sample["status_change_abnormality"] = " ".join([user.name, time_stamp]) - update.sample(adapter=adapter, sample_object=Sample(**sample_dict)) - - if request.form.get("form_id") == "set_sample_comment" and request.form.get("comment"): - sample_id: str = request.form["sample_id"] - sample: Sample = find.sample(sample_id=sample_id) - comment: str = request.form.get("comment") + for sample_id in samples: + sample: Sample = find.sample(sample_id=sample_id, adapter=adapter) + comment: str = form.get(f"comment_{sample_id}") + include: bool = form.get(f"include_{sample_id}") if comment != sample.comment: sample.comment = comment - update.sample(adapter=adapter, sample_object=sample) - - if request.form.get("button_id") == "Save": - samples: Iterable[str] = request.form.getlist("samples") - for sample_id in samples: - sample: Sample = find.sample(sample_id=sample_id) - comment: str = request.form.get(f"comment_{sample_id}") - include: bool = request.form.get(f"include_{sample_id}") - if comment != sample.comment: - sample.comment = comment - if include and not sample.include: - sample.include = True - sample.change_include_date = " ".join([user.name, time_stamp]) - elif not include and sample.include: - sample.include = False - update.sample(adapter=adapter, sample_object=sample) - - if request.form.get("button_id") == "include all samples": - samples: Iterable[str] = request.form.getlist("samples") - for sample_id in samples: - sample: Sample = find.sample(sample_id=sample_id) - if sample.include: - continue + if include and not sample.include: sample.include = True - sample.change_include_date = " ".join([user.name, time_stamp]) - update.sample(adapter=adapter, sample_object=sample) + sample.change_include_date = f"{USER.username} {time_stamp}" + elif not include and sample.include: + sample.include = False + update.sample(adapter=adapter, sample=sample) + - return RedirectResponse(request.url) +def include_all_samples(samples: Iterable[str], adapter: NiptAdapter): + """Function to set sample.include=True for all samples.""" + + time_stamp: str = datetime.now().strftime("%Y/%m/%d %H:%M:%S") + for sample_id in samples: + sample: Sample = find.sample(sample_id=sample_id, adapter=adapter) + if sample.include: + continue + sample.include = True + sample.change_include_date = f"{USER.username} {time_stamp}" + update.sample(adapter=adapter, sample=sample) diff --git a/NIPTool/API/external/api/api_v1/templates/batch/tabs/table.html b/NIPTool/API/external/api/api_v1/templates/batch/tabs/table.html index ef74e73a..1cd7ccf4 100644 --- a/NIPTool/API/external/api/api_v1/templates/batch/tabs/table.html +++ b/NIPTool/API/external/api/api_v1/templates/batch/tabs/table.html @@ -11,7 +11,7 @@
-
+ diff --git a/NIPTool/API/external/api/api_v1/templates/sample/header.html b/NIPTool/API/external/api/api_v1/templates/sample/header.html index f8ea63f7..ae1b0ccd 100644 --- a/NIPTool/API/external/api/api_v1/templates/sample/header.html +++ b/NIPTool/API/external/api/api_v1/templates/sample/header.html @@ -1,6 +1,6 @@ {% block content %} - +
diff --git a/NIPTool/API/external/api/api_v1/templates/sample/sample.html b/NIPTool/API/external/api/api_v1/templates/sample/sample.html index 19e64b81..18ba2a8a 100644 --- a/NIPTool/API/external/api/api_v1/templates/sample/sample.html +++ b/NIPTool/API/external/api/api_v1/templates/sample/sample.html @@ -16,7 +16,7 @@
- +
diff --git a/NIPTool/API/external/constants.py b/NIPTool/API/external/constants.py index c281bbb8..3203fa86 100644 --- a/NIPTool/API/external/constants.py +++ b/NIPTool/API/external/constants.py @@ -7,8 +7,8 @@ "Other": "warning", "Failed": "danger", } -CHROM_ABNORM = ["T13", "T18", "T21", "X0", "XXX", "XXY", "XYY"] -TRIS_CHROM_ABNORM = ["T13", "T18", "T21"] +CHROM_ABNORM = ["13", "18", "21", "X0", "XXX", "XXY", "XYY"] +TRIS_CHROM_ABNORM = ["13", "18", "21"] SEX_CHROM_ABNORM = ["X0", "XXX", "XXY", "XYY"] STATUS_COLORS = { "Suspected": "#DBA901", diff --git a/NIPTool/crud/update.py b/NIPTool/crud/update.py index 46b67283..bf75e433 100644 --- a/NIPTool/crud/update.py +++ b/NIPTool/crud/update.py @@ -12,5 +12,5 @@ def sample(adapter: NiptAdapter, sample: Sample) -> dict: sample_dict: dict = sample.dict(exclude_none=True) sample_id = sample.sample_id LOG.info("Updating sample %s", sample_id) - adapter.sample_collection.update_one({"sample_id": sample_id}, sample_dict) + adapter.sample_collection.update_one({"sample_id": sample_id}, {"$set": sample_dict}) return sample_dict diff --git a/NIPTool/models/database/sample.py b/NIPTool/models/database/sample.py index c312df20..5cffeb7a 100644 --- a/NIPTool/models/database/sample.py +++ b/NIPTool/models/database/sample.py @@ -77,8 +77,8 @@ class Sample(BaseModel): CNVSegment: Optional[str] segmental_calls: Optional[str] include: Optional[bool] - change_include_date: Optional[str] - comment: Optional[str] + change_include_date: Optional[str] = "" + comment: Optional[str] = "" status_13: Optional[str] status_18: Optional[str] status_21: Optional[str] @@ -86,13 +86,13 @@ class Sample(BaseModel): status_XXX: Optional[str] status_XXY: Optional[str] status_XYY: Optional[str] - status_change_T13: Optional[str] - status_change_T18: Optional[str] - status_change_T21: Optional[str] - status_change_TX0: Optional[str] - status_change_TXXX: Optional[str] - status_change_TXXY: Optional[str] - status_change_TXYY: Optional[str] + status_change_13: Optional[str] = "" + status_change_18: Optional[str] = "" + status_change_21: Optional[str] = "" + status_change_X0: Optional[str] = "" + status_change_XXX: Optional[str] = "" + status_change_XXY: Optional[str] = "" + status_change_XYY: Optional[str] = "" class Config: allow_population_by_field_name = True