Skip to content

Commit

Permalink
Merge pull request #123 from CSCfi/develop
Browse files Browse the repository at this point in the history
Release 0.5.1
  • Loading branch information
blankdots authored Aug 14, 2020
2 parents e252222 + 495e1fd commit 6897809
Show file tree
Hide file tree
Showing 27 changed files with 874 additions and 526 deletions.
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
author = "CSC Developers"

# The full version, including alpha/beta/rc tags
release = "0.5.0"
release = "0.5.1"


# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion metadata_backend/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Backend for submitting and validating XML Files containing ENA metadata."""

__title__ = "metadata_backend"
__version__ = VERSION = "0.5.0"
__version__ = VERSION = "0.5.1"
__author__ = "CSC Developers"
76 changes: 64 additions & 12 deletions metadata_backend/api/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from ..helpers.parser import XMLToJSONParser
from ..helpers.schema_loader import JSONSchemaLoader, SchemaNotFoundException, XMLSchemaLoader
from ..helpers.validator import JSONValidator, XMLValidator
from .operators import FolderOperator, Operator, XMLOperator
from .operators import FolderOperator, Operator, XMLOperator, UserOperator


class RESTApiHandler:
Expand Down Expand Up @@ -100,7 +100,7 @@ def get_page_param(param_name: str, default: int) -> int:
link_headers = self._header_links(url, page_num, per_page, total_objects)
LOG.debug(f"Pagination header links: {link_headers}")
LOG.info(f"Querying for objects in {collection} " f"resulted in {total_objects} objects ")
return web.Response(body=result, status=200, headers=link_headers, content_type="application/json")
return web.Response(body=result, status=200, headers=link_headers, content_type="application/json",)

async def _get_data(self, req: Request) -> Dict:
"""Get the data content from a request.
Expand Down Expand Up @@ -199,7 +199,7 @@ async def post_object(self, req: Request) -> Response:
url = f"{req.scheme}://{req.host}{req.path}"
location_headers = {"Location": f"{url}{accession_id}"}
LOG.info(f"POST object with accesssion ID {accession_id} " f"in schema {collection} was successful.")
return web.Response(body=body, status=201, headers=location_headers, content_type="application/json")
return web.Response(body=body, status=201, headers=location_headers, content_type="application/json",)

async def query_objects(self, req: Request) -> Response:
"""Query metadata objects from database.
Expand All @@ -223,8 +223,8 @@ async def delete_object(self, req: Request) -> Response:

accession_id = req.match_info["accessionId"]
db_client = req.app["db_client"]
await Operator(db_client).delete_metadata_object(collection, accession_id)
LOG.info(f"DELETE object with accesssion ID {accession_id} " f"in schema {collection} was successful.")
accession_id = await Operator(db_client).delete_metadata_object(collection, accession_id)
LOG.info(f"DELETE object with accession ID {accession_id} " f"in schema {collection} was successful.")
return web.Response(status=204)

async def put_object(self, req: Request) -> Response:
Expand Down Expand Up @@ -252,9 +252,9 @@ async def put_object(self, req: Request) -> Response:
content = await self._get_data(req)
JSONValidator(content, schema_type).validate
operator = Operator(db_client)
await operator.replace_metadata_object(collection, accession_id, content)
accession_id = await operator.replace_metadata_object(collection, accession_id, content)
body = json.dumps({"accessionId": accession_id})
LOG.info(f"PUT object with accesssion ID {accession_id} " f"in schema {collection} was successful.")
LOG.info(f"PUT object with accession ID {accession_id} " f"in schema {collection} was successful.")
return web.Response(body=body, status=200, content_type="application/json")

async def patch_object(self, req: Request) -> Response:
Expand All @@ -278,9 +278,9 @@ async def patch_object(self, req: Request) -> Response:
else:
content = await self._get_data(req)
operator = Operator(db_client)
await operator.update_metadata_object(collection, accession_id, content)
accession_id = await operator.update_metadata_object(collection, accession_id, content)
body = json.dumps({"accessionId": accession_id})
LOG.info(f"PATCH object with accesssion ID {accession_id} " f"in schema {collection} was successful.")
LOG.info(f"PATCH object with accession ID {accession_id} " f"in schema {collection} was successful.")
return web.Response(body=body, status=200, content_type="application/json")

async def get_folders(self, req: Request) -> Response:
Expand All @@ -304,6 +304,7 @@ async def post_folder(self, req: Request) -> Response:
"""
db_client = req.app["db_client"]
content = await self._get_data(req)
JSONValidator(content, "folders").validate
operator = FolderOperator(db_client)
folder = await operator.create_folder(content)
body = json.dumps({"folderId": folder})
Expand All @@ -323,7 +324,7 @@ async def get_folder(self, req: Request) -> Response:
db_client = req.app["db_client"]
operator = FolderOperator(db_client)
folder = await operator.read_folder(folder_id)
LOG.info(f"GET folder with folder ID {folder_id} was successful.")
LOG.info(f"GET folder with ID {folder_id} was successful.")
return web.Response(body=json.dumps(folder), status=200, content_type="application/json")

async def patch_folder(self, req: Request) -> Response:
Expand All @@ -340,8 +341,8 @@ async def patch_folder(self, req: Request) -> Response:
patch_ops = await self._get_data(req)
allowed_paths = ["/name", "/description", "/metadataObjects"]
for op in patch_ops:
if not any([i in op["path"] for i in allowed_paths]):
reason = f"Request contains '{op['path']}' key that cannot be" " updated to folders."
if all(i not in op["path"] for i in allowed_paths):
reason = f"Request contains '{op['path']}' key that cannot be updated to folders."
LOG.error(reason)
raise web.HTTPBadRequest(reason=reason)
patch = JsonPatch(patch_ops)
Expand All @@ -365,6 +366,57 @@ async def delete_folder(self, req: Request) -> Response:
LOG.info(f"DELETE folder with ID {folder} was successful.")
return web.Response(status=204)

async def get_user(self, req: Request) -> Response:
"""Get one user by its user ID.
:param req: GET request
:returns: JSON response containing user object
"""
user_id = req.match_info["userId"]
db_client = req.app["db_client"]
operator = UserOperator(db_client)
user = await operator.read_user(user_id)
LOG.info(f"GET user with ID {user_id} was successful.")
return web.Response(body=json.dumps(user), status=200, content_type="application/json")

async def patch_user(self, req: Request) -> Response:
"""Update user object with a specific user ID.
:param req: PATCH request
:returns: JSON response containing user ID for updated user object
"""
user_id = req.match_info["userId"]
db_client = req.app["db_client"]

# Check patch operations in request are valid
patch_ops = await self._get_data(req)
allowed_paths = ["/drafts", "/folders"]
for op in patch_ops:
if all(i not in op["path"] for i in allowed_paths):
reason = f"Request contains '{op['path']}' key that cannot be updated to user object."
LOG.error(reason)
raise web.HTTPBadRequest(reason=reason)
patch = JsonPatch(patch_ops)

operator = UserOperator(db_client)
user = await operator.update_user(user_id, patch)
body = json.dumps({"userId": user})
LOG.info(f"PATCH user with ID {user} was successful.")
return web.Response(body=body, status=200, content_type="application/json")

async def delete_user(self, req: Request) -> Response:
"""Delete user from database.
:param req: DELETE request
:returns: HTTP No Content response
"""
user_id = req.match_info["userId"]
db_client = req.app["db_client"]
operator = UserOperator(db_client)
user = await operator.delete_user(user_id)
LOG.info(f"DELETE user with ID {user} was successful.")
return web.Response(status=204)


class SubmissionAPIHandler:
"""Handler for non-rest API methods."""
Expand Down
5 changes: 4 additions & 1 deletion metadata_backend/api/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ async def jwt_authentication(req: Request, handler: Callable) -> Response:

# Include claims that are required to be present
# in the payload of the token
claims_options = {"iss": {"essential": True, "values": ["haka_iss", "elixir_iss"]}, "exp": {"essential": True}}
claims_options = {
"iss": {"essential": True, "values": ["haka_iss", "elixir_iss"]},
"exp": {"essential": True},
}

# Decode and validate token
try:
Expand Down
Loading

0 comments on commit 6897809

Please sign in to comment.