diff --git a/poetry.lock b/poetry.lock index c11fdb7..094ed37 100644 --- a/poetry.lock +++ b/poetry.lock @@ -514,13 +514,13 @@ requests = ">=2.31.0,<3.0.0" [[package]] name = "geneweaver-db" -version = "0.3.3" +version = "0.3.4" description = "Database Interaction Services for GeneWeaver" optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "geneweaver_db-0.3.3-py3-none-any.whl", hash = "sha256:1feaa0c9e56f142c78a4f26f97e5f44e55dd13598a2f19f8c582ff9641032711"}, - {file = "geneweaver_db-0.3.3.tar.gz", hash = "sha256:9dbcdcd4961a5f2837d4a8d5da77cf20717bee19a3c1a1a58003c5a43d3092ce"}, + {file = "geneweaver_db-0.3.4-py3-none-any.whl", hash = "sha256:af53696ec40e7761e52127adf9b04a68503b38a9d1101d2815e4476b62b458b3"}, + {file = "geneweaver_db-0.3.4.tar.gz", hash = "sha256:a268b406a714604f3404e06215bfc5d98fd3e9ba0f05a0dbf2bdaeeb5e4a20bd"}, ] [package.dependencies] @@ -1953,4 +1953,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "0bcc0704a65ea586114e87edfffde4c31be5f45fb8c3b0d588c409dd40f7c33f" +content-hash = "49af25b58075f34f2d3521b4148dce3d670a26a257cb3f2874e1293408f8385d" diff --git a/pyproject.toml b/pyproject.toml index d526495..9c0d01e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "geneweaver-api" -version = "0.5.0a0" +version = "0.5.0a1" description = "The Geneweaver API" authors = [ "Alexander Berger ", @@ -17,11 +17,10 @@ packages = [ [tool.poetry.dependencies] python = "^3.9" - geneweaver-core = "^0.9.1" fastapi = {extras = ["all"], version = "^0.99.1"} uvicorn = {extras = ["standard"], version = "^0.24.0"} -geneweaver-db = "^0.3.3" +geneweaver-db = "^0.3.4" psycopg-pool = "^3.1.7" requests = "^2.31.0" python-jose = {extras = ["cryptography"], version = "^3.3.0"} diff --git a/src/geneweaver/api/controller/genesets.py b/src/geneweaver/api/controller/genesets.py index 558e998..5cd04c2 100644 --- a/src/geneweaver/api/controller/genesets.py +++ b/src/geneweaver/api/controller/genesets.py @@ -14,6 +14,7 @@ from geneweaver.api.services import geneset as genset_service from geneweaver.api.services import publications as publication_service from geneweaver.core.enum import GeneIdentifier, GenesetTier, Species +from geneweaver.core.schema.score import GenesetScoreType from typing_extensions import Annotated from . import message as api_message @@ -264,3 +265,24 @@ def get_publication_for_geneset( raise HTTPException(status_code=404, detail=api_message.RECORD_NOT_FOUND_ERROR) return pub_resp + + +@router.put("/{geneset_id}/threshold") +def put_geneset_threshold( + geneset_id: Annotated[ + int, Path(format="int64", minimum=0, maxiumum=9223372036854775807) + ], + gene_score_type: GenesetScoreType, + user: UserInternal = Security(deps.full_user), + cursor: Optional[deps.Cursor] = Depends(deps.cursor), +) -> dict: + """Set geneset threshold for geneset owner.""" + response = genset_service.update_geneset_threshold( + cursor, geneset_id, gene_score_type, user + ) + + if "error" in response: + if response.get("message") == api_message.ACCESS_FORBIDDEN: + raise HTTPException(status_code=403, detail=api_message.ACCESS_FORBIDDEN) + + return response diff --git a/src/geneweaver/api/services/geneset.py b/src/geneweaver/api/services/geneset.py index f4775c1..ba4ccf1 100644 --- a/src/geneweaver/api/services/geneset.py +++ b/src/geneweaver/api/services/geneset.py @@ -6,9 +6,11 @@ from geneweaver.api.controller import message from geneweaver.api.schemas.auth import User from geneweaver.core.enum import GeneIdentifier, GenesetTier, Species +from geneweaver.core.schema.score import GenesetScoreType from geneweaver.db import gene as db_gene from geneweaver.db import geneset as db_geneset from geneweaver.db import geneset_value as db_geneset_value +from geneweaver.db import threshold as db_threshold from psycopg import Cursor @@ -243,3 +245,26 @@ def map_geneset_homology( except Exception as err: logger.error(err) raise err + + +def update_geneset_threshold( + cursor: Cursor, geneset_id: int, geneset_score: GenesetScoreType, user: User +) -> dict: + """Set geneset threshold if user is the owner.""" + try: + if user is None or user.id is None: + return {"error": True, "message": message.ACCESS_FORBIDDEN} + + if not db_geneset.user_is_owner( + cursor=cursor, user_id=user.id, geneset_id=geneset_id + ): + return {"error": True, "message": message.ACCESS_FORBIDDEN} + + db_threshold.set_geneset_threshold( + cursor=cursor, geneset_id=geneset_id, geneset_score_type=geneset_score + ) + return {} + + except Exception as err: + logger.error(err) + raise err diff --git a/tests/controllers/test_genesets.py b/tests/controllers/test_genesets.py index d65af59..971520d 100644 --- a/tests/controllers/test_genesets.py +++ b/tests/controllers/test_genesets.py @@ -1,5 +1,6 @@ """Tests for geneset API.""" +import json from unittest.mock import patch from geneweaver.api.controller import message @@ -11,6 +12,7 @@ geneset_metadata_w_pub_info = test_geneset_data.get("geneset_metadata_w_pub_info") publication_by_id_resp = test_publication_data.get("publication_by_id") geneset_genes_values_resp = test_geneset_data.get("geneset_genes_values_resp_1") +geneset_threshold_update_req = test_geneset_data.get("geneset_threshold_update_req") @patch("geneweaver.api.services.geneset.get_geneset") @@ -228,3 +230,29 @@ def test_get_geneset_gene_values_errors(mock_get_geneset_gene_values, client): mock_get_geneset_gene_values.return_value = {"data": None} response = client.get("/api/genesets/1234/values") assert response.status_code == 404 + + +@patch("geneweaver.api.services.geneset.update_geneset_threshold") +def test_set_geneset_endpoint_response(mock_update_geneset_threshold, client): + """Test set geneset threshold endpoint.""" + mock_update_geneset_threshold.return_value = {} + + response = client.put( + "/api/genesets/1234/threshold", data=json.dumps(geneset_threshold_update_req) + ) + assert response.status_code == 200 + assert response.json() == {} + + +@patch("geneweaver.api.services.geneset.update_geneset_threshold") +def test_set_geneset_endpoint_response_errors(mock_update_geneset_threshold, client): + """Test set geneset threshold endpoint errors.""" + mock_update_geneset_threshold.return_value = { + "error": True, + "message": message.ACCESS_FORBIDDEN, + } + + response = client.put( + "/api/genesets/1234/threshold", data=json.dumps(geneset_threshold_update_req) + ) + assert response.status_code == 403 diff --git a/tests/data/__init__.py b/tests/data/__init__.py index 252d1ba..285088b 100644 --- a/tests/data/__init__.py +++ b/tests/data/__init__.py @@ -47,6 +47,9 @@ "geneset_genes_values_resp_1": json.loads(geneset_list_response_json).get( "geneset_genes_values_resp_1" ), + "geneset_threshold_update_req": json.loads(geneset_list_response_json).get( + "geneset_threshold_update_req" + ), } # Gene homolog ids test data diff --git a/tests/data/geneset.json b/tests/data/geneset.json index c42ff67..dd93c9d 100644 --- a/tests/data/geneset.json +++ b/tests/data/geneset.json @@ -296,5 +296,10 @@ "value": 1.0 } ] + }, + "geneset_threshold_update_req": { + "score_type": "p-value", + "threshold_low": 0, + "threshold": 0.05 } } \ No newline at end of file diff --git a/tests/services/test_genset.py b/tests/services/test_genset.py index effa950..07a33df 100644 --- a/tests/services/test_genset.py +++ b/tests/services/test_genset.py @@ -7,6 +7,7 @@ from geneweaver.api.schemas.auth import User from geneweaver.api.services import geneset from geneweaver.core.enum import GeneIdentifier, GenesetTier, Species +from geneweaver.core.schema.score import GenesetScoreType from tests.data import test_geneset_data @@ -15,6 +16,7 @@ geneset_w_gene_id_type_resp = test_geneset_data.get("geneset_w_gene_id_type_resp") geneset_metadata_w_pub_info = test_geneset_data.get("geneset_metadata_w_pub_info") geneset_genes_values_resp = test_geneset_data.get("geneset_genes_values_resp_1") +geneset_threshold_update_req = test_geneset_data.get("geneset_threshold_update_req") mock_user = User() mock_user.id = 1 @@ -278,3 +280,51 @@ def test_get_geneset_gene_values_invalid_user(mock_db_geneset_value): response = geneset.get_geneset_gene_values(None, user=None, geneset_id=1234) assert response.get("error") is True assert response.get("message") == message.ACCESS_FORBIDDEN + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.db_threshold") +def test_geneset_thershold_update(mock_db_threshold, mock_db_geneset): + """Test geneset gene value data response.""" + mock_db_threshold.set_geneset_threshold.return_value = None + mock_db_geneset.user_is_owner.return_value = True + geneset_threshold = GenesetScoreType(**geneset_threshold_update_req) + + response = geneset.update_geneset_threshold( + cursor=None, user=mock_user, geneset_id=1234, geneset_score=geneset_threshold + ) + assert response == {} + + +@patch("geneweaver.api.services.geneset.db_geneset") +@patch("geneweaver.api.services.geneset.db_threshold") +def test_geneset_thershold_update_errors(mock_db_threshold, mock_db_geneset): + """Test geneset gene value data response.""" + mock_db_threshold.set_geneset_threshold.return_value = None + mock_db_geneset.user_is_owner.return_value = False + geneset_threshold = GenesetScoreType(**geneset_threshold_update_req) + + # user is not the geneset owner + response = geneset.update_geneset_threshold( + cursor=None, user=mock_user, geneset_id=1234, geneset_score=geneset_threshold + ) + assert response.get("error") is True + assert response.get("message") == message.ACCESS_FORBIDDEN + + # user is not logged-in + response = geneset.update_geneset_threshold( + cursor=None, user=None, geneset_id=1234, geneset_score=geneset_threshold + ) + assert response.get("error") is True + assert response.get("message") == message.ACCESS_FORBIDDEN + + # db error + mock_db_geneset.user_is_owner.return_value = True + mock_db_threshold.set_geneset_threshold.side_effect = Exception("ERROR") + with pytest.raises(expected_exception=Exception): + geneset.update_geneset_threshold( + cursor=None, + user=mock_user, + geneset_id=1234, + geneset_score=geneset_threshold, + )