Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update raise errors. #282

Merged
merged 2 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 24 additions & 24 deletions src/handlers/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from controller.exceptions import ControllerError, NotFoundError
from pipeline import MetaKGQueryPipeline
from utils.downloader import DownloadError, download_async
from utils.http_error import SmartAPIHTTPError
from utils.metakg.export import edges2graphml
from utils.metakg.path_finder import MetaKGPathFinder
from utils.metakg.cytoscape_formatter import CytoscapeDataFormatter
Expand Down Expand Up @@ -67,7 +68,7 @@ def get(self):
# raising HTTPError will cause headers to be emptied
self.finish()
else:
raise HTTPError(403)
raise HTTPError(status_code=403)


class LoginHandler(AuthHandler):
Expand Down Expand Up @@ -112,7 +113,7 @@ class ValidateHandler(BaseHandler):

async def get(self):
if self.request.body:
raise HTTPError(400, reason="GET takes no request body.")
raise HTTPError(status_code=400, reason="GET takes no request body.")

raw = await self.download(self.args.url)
self.validate(raw)
Expand All @@ -138,9 +139,8 @@ def validate(self, raw):
smartapi = SmartAPI(SmartAPI.VALIDATION_ONLY)
smartapi.raw = raw
smartapi.validate()

except (ControllerError, AssertionError) as err:
raise HTTPError(400, reason=str(err))
raise SmartAPIHTTPError(400, reason=str(err))
else:
self.finish({"success": True, "details": f"valid SmartAPI ({smartapi.version}) metadata."})

Expand All @@ -164,19 +164,19 @@ async def post(self):
"""

if SmartAPI.find(self.args.url, "url"):
raise HTTPError(409)
raise HTTPError(status_code=409)

try:
file = await download_async(self.args.url)
except DownloadError as err:
raise HTTPError(400, reason=str(err)) from err
raise HTTPError(status_code=400, reason=str(err)) from err

try:
smartapi = SmartAPI(self.args.url)
smartapi.raw = file.raw
smartapi.validate()
except (ControllerError, AssertionError) as err:
raise HTTPError(400, reason=str(err)) from err
raise HTTPError(status_code=400, reason=str(err)) from err

if self.args.dryrun:
raise Finish({"success": True, "details": f"[Dryrun] Valid {smartapi.version} Metadata"})
Expand All @@ -186,7 +186,7 @@ async def post(self):
smartapi.refresh(file) # populate webdoc meta
_id = smartapi.save()
except ControllerError as err:
raise HTTPError(400, reason=str(err)) from err
raise HTTPError(status_code=400, reason=str(err)) from err
else:
self.finish({"success": True, "_id": _id})
await self._notify(smartapi)
Expand Down Expand Up @@ -251,21 +251,21 @@ async def put(self, _id):
try:
smartapi = SmartAPI.get(_id)
except NotFoundError:
raise HTTPError(404)
raise HTTPError(status_code=404)

if smartapi.username != self.current_user["login"]:
raise HTTPError(403)
raise HTTPError(status_code=403)

if self.args.slug is not None:
if self.args.slug in {"api"}: # reserved
raise HTTPError(400, reason="slug is reserved")
raise HTTPError(status_code=400, reason="slug is reserved")

try: # update slug
smartapi.slug = self.args.slug or None
smartapi.save()

except (ControllerError, ValueError) as err:
raise HTTPError(400, reason=str(err)) from err
raise HTTPError(status_code=400, reason=str(err)) from err

self.finish({"success": True})

Expand All @@ -291,15 +291,15 @@ def delete(self, _id):
try:
smartapi = SmartAPI.get(_id)
except NotFoundError:
raise HTTPError(404)
raise HTTPError(status_code=404)

if smartapi.username != self.current_user["login"]:
raise HTTPError(403)
raise HTTPError(status_code=403)

try:
_id = smartapi.delete()
except ControllerError as err:
raise HTTPError(400, reason=str(err)) from err
raise HTTPError(status_code=400, reason=str(err)) from err

self.finish({"success": True, "_id": _id})

Expand Down Expand Up @@ -345,41 +345,41 @@ class UptimeHandler(BaseHandler):
@github_authenticated
def get(self):
if self.request.body:
raise HTTPError(400, reason="GET takes no request body.")
raise HTTPError(status_code=400, reason="GET takes no request body.")

if self.args.id:
try:
smartapi = SmartAPI.get(self.args.id)
if smartapi.username != self.current_user["login"]:
raise HTTPError(403)
raise HTTPError(status_code=403)
status = smartapi.check()
smartapi.save()
except NotFoundError:
raise HTTPError(404)
raise HTTPError(status_code=404)
except (ControllerError, AssertionError) as err:
raise HTTPError(400, reason=str(err))
raise HTTPError(status_code=400, reason=str(err))
else:
self.finish({"success": True, "details": status})
else:
raise HTTPError(400, reason="Missing required parameter: id")
raise HTTPError(status_code=400, reason="Missing required parameter: id")

@github_authenticated
def post(self):
if self.args.id:
try:
smartapi = SmartAPI.get(self.args.id)
if smartapi.username != self.current_user["login"]:
raise HTTPError(403)
raise HTTPError(status_code=403)
status = smartapi.check()
smartapi.save()
except NotFoundError:
raise HTTPError(404)
raise HTTPError(status_code=404)
except (ControllerError, AssertionError) as err:
raise HTTPError(400, reason=str(err))
raise HTTPError(status_code=400, reason=str(err))
else:
self.finish({"success": True, "details": status})
else:
raise HTTPError(400, reason="Missing required form field: id")
raise HTTPError(status_code=400, reason="Missing required form field: id")


class MetaKGQueryHandler(QueryHandler):
Expand Down
39 changes: 39 additions & 0 deletions src/utils/http_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import Optional, Any
from tornado.web import HTTPError
import re


class SmartAPIHTTPError(HTTPError):
"""An extended HTTPError class with additional details and message sanitization.

Adds the following enhancements:
- A `details` parameter for including extra context about the error.
- A `clean_error_message` method for sanitizing log messages and details.

:arg str details: Additional information about the error.
"""

def __init__(
self,
status_code: int = 500,
log_message: Optional[str] = None,
*args: Any,
**kwargs: Any,
) -> None:
super().__init__(status_code, log_message, *args, **kwargs)
if self.reason:
self.reason = self.clean_error_message(self.reason)
if self.log_message:
self.log_message = self.clean_error_message(self.log_message)

@staticmethod
def clean_error_message(message: str) -> str:
"""
Sanitizes an error message by replacing newlines, tabs, and reducing multiple spaces.

:param message: The error message to sanitize.
:return: A cleaned and sanitized version of the message.
"""
message = message.replace("\n", " ") # Replace actual newlines with spaces
message = re.sub(r'\s+', ' ', message) # Normalize spaces
return message.strip()
Loading