зеркало из https://github.com/mozilla/treeherder.git
Remove unsafe methods form swagger ui
Also add custom exception handling to the api, uniforming how failures are reported to the consumer
This commit is contained in:
Родитель
25e57fd3ba
Коммит
52700b1a90
|
@ -56,5 +56,5 @@ def test_artifact_detail_bad_project(webapp, jm):
|
|||
expect_errors=True
|
||||
)
|
||||
assert resp.status_int == 404
|
||||
assert resp.json == {"message": "No project with name foo"}
|
||||
assert resp.json == {"detail": "No project with name foo"}
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ def test_note_detail_bad_project(webapp, jm):
|
|||
expect_errors=True
|
||||
)
|
||||
assert resp.status_int == 404
|
||||
assert resp.json == {"message": "No project with name foo"}
|
||||
assert resp.json == {"detail": "No project with name foo"}
|
||||
|
||||
|
||||
def test_create_note(webapp, eleven_jobs_processed, mock_message_broker, jm):
|
||||
|
|
|
@ -98,7 +98,7 @@ def test_resultset_list_bad_project(webapp, jm):
|
|||
)
|
||||
|
||||
assert resp.status_int == 404
|
||||
assert resp.json == {"message": "No project with name foo"}
|
||||
assert resp.json == {"detail": "No project with name foo"}
|
||||
|
||||
|
||||
def test_resultset_list_empty_rs_still_show(webapp, initial_data,
|
||||
|
@ -250,7 +250,7 @@ def test_result_set_detail_bad_project(webapp, jm):
|
|||
expect_errors=True
|
||||
)
|
||||
assert resp.status_int == 404
|
||||
assert resp.json == {"message": "No project with name foo"}
|
||||
assert resp.json == {"detail": "No project with name foo"}
|
||||
|
||||
|
||||
def test_resultset_create(sample_resultset, jm, initial_data):
|
||||
|
|
|
@ -100,10 +100,7 @@ class TreeherderModelBase(object):
|
|||
candidate_sources.append(source)
|
||||
|
||||
if not candidate_sources:
|
||||
raise DatasetNotFoundError(
|
||||
"No dataset found for project %r, contenttype %r."
|
||||
% (self.project, contenttype)
|
||||
)
|
||||
raise DatasetNotFoundError(self.project, contenttype)
|
||||
|
||||
candidate_sources.sort(key=lambda s: s.dataset, reverse=True)
|
||||
|
||||
|
@ -111,7 +108,16 @@ class TreeherderModelBase(object):
|
|||
|
||||
|
||||
class DatasetNotFoundError(ValueError):
|
||||
pass
|
||||
def __init__(self, project, contenttype, *args, **kwargs):
|
||||
super(DatasetNotFoundError, self).__init__(*args, **kwargs)
|
||||
self.project = project
|
||||
self.contenttype = contenttype
|
||||
|
||||
def __unicode__(self):
|
||||
return u"No dataset found for project {0} and contenttype '{1}'".format(
|
||||
self.project,
|
||||
self.contenttype,
|
||||
)
|
||||
|
||||
|
||||
class ObjectNotFoundException(Exception):
|
||||
|
|
|
@ -209,7 +209,8 @@ REST_FRAMEWORK = {
|
|||
),
|
||||
'DEFAULT_RENDERER_CLASSES': (
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
)
|
||||
),
|
||||
'EXCEPTION_HANDLER': 'treeherder.webapp.api.exceptions.exception_handler'
|
||||
}
|
||||
|
||||
SITE_URL = "http://local.treeherder.mozilla.org"
|
||||
|
@ -281,3 +282,5 @@ def obtain_username(email):
|
|||
return email
|
||||
|
||||
BROWSERID_USERNAME_ALGO = obtain_username
|
||||
|
||||
SWAGGER_SETTINGS = {"enabled_methods": ['get',]}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
from rest_framework import exceptions
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import exception_handler as drf_exc_handler
|
||||
from django.conf import settings
|
||||
|
||||
from treeherder.model.derived import DatasetNotFoundError, ObjectNotFoundException
|
||||
|
||||
|
||||
class ResourceNotFoundException(exceptions.APIException):
|
||||
status_code = 404
|
||||
default_detail = "Resource not found"
|
||||
|
||||
|
||||
def exception_handler(exc):
|
||||
"""
|
||||
Add treeherder-specific exception handling to the rest framework
|
||||
Mostly a conversion of treeherders ORM exceptions to drf APIExceptions
|
||||
"""
|
||||
if isinstance(exc, DatasetNotFoundError):
|
||||
exc = ResourceNotFoundException(
|
||||
"No project with name {0}".format(exc.project)
|
||||
)
|
||||
if isinstance(exc, ObjectNotFoundException):
|
||||
exc = ResourceNotFoundException(
|
||||
"{0} object not found using: {1}".format(
|
||||
exc.table, unicode(exc.extra_info)))
|
||||
|
||||
response = drf_exc_handler(exc)
|
||||
if response is None:
|
||||
msg = {"detail": unicode(exc)}
|
||||
if settings.DEBUG:
|
||||
import traceback
|
||||
msg["traceback"] = traceback.format_exc()
|
||||
response = Response(msg, status=500)
|
||||
return response
|
|
@ -1,6 +1,7 @@
|
|||
from django.conf import settings
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.exceptions import ParseError
|
||||
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from treeherder.webapp.api.permissions import IsStaffOrReadOnly
|
||||
|
@ -32,11 +33,19 @@ class NoteViewSet(viewsets.ViewSet):
|
|||
def list(self, request, project, jm):
|
||||
"""
|
||||
GET method implementation for list view
|
||||
job_id -- Mandatory filter indicating which job these notes belong to.
|
||||
"""
|
||||
job_id = request.QUERY_PARAMS.get('job_id')
|
||||
|
||||
objs = jm.get_job_note_list(job_id=job_id)
|
||||
return Response(objs)
|
||||
job_id = request.QUERY_PARAMS.get('job_id')
|
||||
if not job_id:
|
||||
raise ParseError(detail="The job_id parameter is mandatory for this endpoint")
|
||||
try:
|
||||
job_id = int(job_id)
|
||||
except:
|
||||
raise ParseError(detail="The job_id parameter must be an integer")
|
||||
|
||||
job_note_list = jm.get_job_note_list(job_id=job_id)
|
||||
return Response(job_note_list)
|
||||
|
||||
@with_jobs
|
||||
def create(self, request, project, jm):
|
||||
|
@ -80,4 +89,3 @@ class NoteViewSet(viewsets.ViewSet):
|
|||
|
||||
else:
|
||||
return Response("No note with id: {0}".format(pk), 404)
|
||||
|
||||
|
|
|
@ -7,8 +7,7 @@ import oauth2 as oauth
|
|||
from django.conf import settings
|
||||
from rest_framework.response import Response
|
||||
|
||||
from treeherder.model.derived import (JobsModel, DatasetNotFoundError,
|
||||
ObjectNotFoundException)
|
||||
from treeherder.model.derived import JobsModel
|
||||
from treeherder.etl.oauth_utils import OAuthCredentials
|
||||
|
||||
|
||||
|
@ -185,28 +184,13 @@ def with_jobs(model_func):
|
|||
|
||||
``func`` must take a jobsmodel object and return a response object
|
||||
|
||||
Catches exceptions
|
||||
"""
|
||||
def use_jobs_model(*args, **kwargs):
|
||||
|
||||
project = kwargs["project"]
|
||||
jm = JobsModel(project)
|
||||
try:
|
||||
jm = JobsModel(project)
|
||||
return model_func(*args, jm=jm, **kwargs)
|
||||
|
||||
except DatasetNotFoundError as e:
|
||||
return Response(
|
||||
{"message": "No project with name {0}".format(project)},
|
||||
status=404,
|
||||
)
|
||||
except ObjectNotFoundException as e:
|
||||
return Response({"message": unicode(e)}, status=404)
|
||||
except Exception as e: # pragma nocover
|
||||
msg = {"message": unicode(e)}
|
||||
if settings.DEBUG:
|
||||
import traceback
|
||||
msg["traceback"] = traceback.format_exc()
|
||||
|
||||
return Response(msg, status=500)
|
||||
finally:
|
||||
jm.disconnect()
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче