Skip to content

Commit

Permalink
Merge pull request #1310 from ScilifelabDataCentre/DDS-1190-projectin…
Browse files Browse the repository at this point in the history
…fo_endpoint

Add endpoint for project info
  • Loading branch information
i-oden authored Oct 27, 2022
2 parents d3047f0 + ddc35a8 commit f02f1bb
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,4 @@ Please add a _short_ line describing the PR you make, if the PR implements a spe
- Add link to the dds instance to the end of all emails ([#1305](https://github.com/ScilifelabDataCentre/dds_web/pull/1305))
- Troubleshooting steps added to web page ([#1309](https://github.com/ScilifelabDataCentre/dds_web/pull/1309))
- Bug: Return instead of project creator if user has been deleted ([#1311](https://github.com/ScilifelabDataCentre/dds_web/pull/1311))
- New endpoint: ProjectInfo - display project information ([#1310](https://github.com/ScilifelabDataCentre/dds_web/pull/1310))
1 change: 1 addition & 0 deletions dds_web/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def output_json(data, code, headers=None):
api.add_resource(project.ProjectStatus, "/proj/status", endpoint="project_status")
api.add_resource(project.ProjectAccess, "/proj/access", endpoint="project_access")
api.add_resource(project.ProjectBusy, "/proj/busy", endpoint="project_busy")
api.add_resource(project.ProjectInfo, "/proj/info", endpoint="project_info")

# User management ################################################################ User management #
api.add_resource(user.RetrieveUserInfo, "/user/info", endpoint="user_info")
Expand Down
28 changes: 28 additions & 0 deletions dds_web/api/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
dbsession,
json_required,
handle_validation_errors,
handle_db_error,
)
from dds_web.errors import (
AccessDeniedError,
Expand Down Expand Up @@ -949,3 +950,30 @@ def put(self):
"ok": True,
"message": f"Project {project_id} was set to {'busy' if set_to_busy else 'not busy'}.",
}


class ProjectInfo(flask_restful.Resource):
"""Get information for a specific project."""

@auth.login_required
@logging_bind_request
@handle_db_error
def get(self):
# Get project ID, project and verify access
project_id = dds_web.utils.get_required_item(obj=flask.request.args, req="project")
project = dds_web.utils.collect_project(project_id=project_id)
dds_web.utils.verify_project_access(project=project)

# Construct a dict with info items
project_info = {
"Project ID": project.public_id,
"Created by": project.creator.name if project.creator else "Former User",
"Status": project.current_status,
"Last updated": project.date_updated,
"Size": project.size,
"Title": project.title,
"Description": project.description,
}

return_info = {"project_info": project_info}
return return_info
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ class DDSEndpoint:
PROJECT_ACCESS = BASE_ENDPOINT + "/proj/access"
PROJECT_BUSY = BASE_ENDPOINT + "/proj/busy"
PROJECT_BUSY_ANY = BASE_ENDPOINT + "/proj/busy/any"
PROJECT_INFO = BASE_ENDPOINT + "/proj/info"

# Listing urls
LIST_PROJ = BASE_ENDPOINT + "/proj/list"
Expand Down
109 changes: 109 additions & 0 deletions tests/test_project_info_listing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# IMPORTS ################################################################################ IMPORTS #

# Standard library
import http
import unittest

# Own
import tests


# CONFIG ################################################################################## CONFIG #

proj_info_items = [
"Project ID",
"Created by",
"Status",
"Last updated",
"Size",
"Title",
"Description",
]
proj_query = {"project": "public_project_id"}
proj_query_restricted = {"project": "restricted_project_id"}

# TESTS #################################################################################### TESTS #


def test_list_proj_info_no_token(client):
"""Token required to list project information"""

response = client.get(tests.DDSEndpoint.PROJECT_INFO, headers=tests.DEFAULT_HEADER)
assert response.status_code == http.HTTPStatus.UNAUTHORIZED
response_json = response.json
assert response_json.get("message")
assert "No token" in response_json.get("message")


def test_list_proj_info_without_project(client):
"""Attempting to get the project information without specifying a project"""

token = tests.UserAuth(tests.USER_CREDENTIALS["unituser"]).token(client)
response = client.get(tests.DDSEndpoint.PROJECT_INFO, headers=token)
response_json = response.json
assert "Missing required information: 'project'" in response_json.get("message")


def test_list_proj_info_access_granted(client):
"""Researcher should be able to list project information"""

token = tests.UserAuth(tests.USER_CREDENTIALS["researchuser"]).token(client)
response = client.get(tests.DDSEndpoint.PROJECT_INFO, headers=token, query_string=proj_query)
assert response.status_code == http.HTTPStatus.OK
response_json = response.json
project_info = response_json.get("project_info")

assert "public_project_id" == project_info.get("Project ID")
# check that endpoint returns dictionary and not a list
assert isinstance(project_info, dict)


def test_list_proj_info_unit_user(client):
"""Unit user should be able to list project information"""

token = tests.UserAuth(tests.USER_CREDENTIALS["unitadmin"]).token(client)
response = client.get(tests.DDSEndpoint.PROJECT_INFO, headers=token, query_string=proj_query)
assert response.status_code == http.HTTPStatus.OK
response_json = response.json
project_info = response_json.get("project_info")

assert "public_project_id" == project_info.get("Project ID")
assert (
"This is a test project. You will be able to upload to but NOT download"
in project_info.get("Description")
)
assert "Size" in project_info.keys() and project_info["Size"] is not None


def test_list_proj_info_returned_items(client):
"""Returned project information should contain certain items"""

token = tests.UserAuth(tests.USER_CREDENTIALS["unitadmin"]).token(client)
response = client.get(tests.DDSEndpoint.PROJECT_INFO, headers=token, query_string=proj_query)
assert response.status_code == http.HTTPStatus.OK
response_json = response.json
project_info = response_json.get("project_info")

assert all(item in project_info for item in proj_info_items)


def test_list_project_info_by_researchuser_not_in_project(client):
"""Researchuser not in project should not be able to list project info"""

token = tests.UserAuth(tests.USER_CREDENTIALS["researchuser2"]).token(client)
response = client.get(tests.DDSEndpoint.PROJECT_INFO, query_string=proj_query, headers=token)
assert response.status_code == http.HTTPStatus.FORBIDDEN
response_json = response.json
assert "Project access denied" in response_json.get("message")


def test_list_proj_info_public_insufficient_credentials(client):
"""If the project access has not been granted, the project info should not be provided."""

token = tests.UserAuth(tests.USER_CREDENTIALS["researchuser"]).token(client)
response = client.get(
tests.DDSEndpoint.PROJECT_INFO, query_string=proj_query_restricted, headers=token
)
assert response.status_code == http.HTTPStatus.FORBIDDEN
response_json = response.json
assert "Project access denied" in response_json.get("message")

0 comments on commit f02f1bb

Please sign in to comment.