Skip to content

Commit fc2523f

Browse files
authored
Merge pull request #5 from aplmicrons/custom_err
Custom error handler
2 parents 1ad7b10 + 867bcb2 commit fc2523f

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

django/bosscore/error.py

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ErrorCodes(IntEnum):
4646
MISSING_PERMISSION = 3001
4747
UNRECOGNIZED_PERMISSION = 3002
4848
INGEST_NOT_CREATOR = 3003
49+
ACCESS_DENIED_UNKNOWN = 3004 # User may not even be logged in.
4950

5051
# Database errors
5152
RESOURCE_NOT_FOUND = 4000

django/bosscore/renderer_helper.py

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright 2016 The Johns Hopkins University Applied Physics Laboratory
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from bosscore.error import ErrorCodes
16+
from rest_framework.renderers import JSONRenderer
17+
18+
def check_for_403(fcn):
19+
"""Decorator to check renderer_context for a 403 response.
20+
21+
Args:
22+
fcn (function): A custom BaseRenderer.render() implementation..
23+
24+
Returns:
25+
(function): Wraps given function with one that checks for a 403 status.
26+
"""
27+
28+
def wrapper(*args, **kwargs):
29+
"""Return a JSON response if a 403 found.
30+
31+
Executes the custom renderer if no 403 status code found.
32+
33+
Args:
34+
35+
Returns:
36+
(BaseRenderer)
37+
"""
38+
39+
# renderer_context is the 4th argument if not specified by keyword.
40+
if len(args) < 4 and kwargs is None:
41+
return fcn(*args, **kwargs)
42+
43+
renderer_context = None
44+
if len(args) >= 4:
45+
renderer_context = args[3]
46+
elif kwargs is not None and 'renderer_context' in kwargs:
47+
renderer_context = kwargs['renderer_context']
48+
49+
if renderer_context is None:
50+
return fcn(*args, **kwargs)
51+
52+
# Check for presense of a Response object.
53+
if 'response' not in renderer_context:
54+
return fcn(*args, **kwargs)
55+
56+
# Have a response, check for 403.
57+
if renderer_context['response'].status_code == 403:
58+
renderer_context['response']['Content-Type'] = 'application/json'
59+
obj = args[0]
60+
obj.media_type = 'application/json'
61+
obj.format = 'json'
62+
err_msg = {"status": 403, "message": "Access denied, are you logged in?",
63+
"code": ErrorCodes.ACCESS_DENIED_UNKNOWN}
64+
jr = JSONRenderer()
65+
return jr.render(err_msg, 'application/json', renderer_context)
66+
67+
return fcn(*args, **kwargs)
68+
69+
return wrapper
70+

django/bossspatialdb/renderers.py

+16
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io
2121
from PIL import Image
2222

23+
from bosscore.renderer_helper import check_for_403
2324

2425
class BloscPythonRenderer(renderers.BaseRenderer):
2526
""" A DRF renderer for a blosc encoded cube of data using the numpy interface
@@ -31,6 +32,7 @@ class BloscPythonRenderer(renderers.BaseRenderer):
3132
charset = None
3233
render_style = 'binary'
3334

35+
@check_for_403
3436
def render(self, data, media_type=None, renderer_context=None):
3537

3638
if not data["data"].data.flags['C_CONTIGUOUS']:
@@ -52,8 +54,18 @@ class BloscRenderer(renderers.BaseRenderer):
5254
charset = None
5355
render_style = 'binary'
5456

57+
@check_for_403
5558
def render(self, data, media_type=None, renderer_context=None):
5659

60+
if renderer_context['response'].status_code == 403:
61+
renderer_context["accepted_media_type"] = 'application/json'
62+
self.media_type = 'application/json'
63+
self.format = 'json'
64+
err_msg = {"status": 403, "message": "Access denied, are you logged in?",
65+
"code": 2005}
66+
jr = JSONRenderer()
67+
return jr.render(err_msg, 'application/json', renderer_context)
68+
5769
if not data["data"].data.flags['C_CONTIGUOUS']:
5870
data["data"].data = np.ascontiguousarray(data["data"].data, dtype=data["data"].data.dtype)
5971

@@ -75,6 +87,7 @@ class NpygzRenderer(renderers.BaseRenderer):
7587
charset = None
7688
render_style = 'binary'
7789

90+
@check_for_403
7891
def render(self, data, media_type=None, renderer_context=None):
7992

8093
if not data["data"].data.flags['C_CONTIGUOUS']:
@@ -106,6 +119,7 @@ class JpegRenderer(renderers.BaseRenderer):
106119
charset = None
107120
render_style = 'binary'
108121

122+
@check_for_403
109123
def render(self, data, media_type=None, renderer_context=None):
110124

111125
# Return data, squeezing time dimension as this only works with 3D data
@@ -115,6 +129,7 @@ def render(self, data, media_type=None, renderer_context=None):
115129
else:
116130
# This appears to contain time data. Error out
117131
renderer_context["response"].status_code = 400
132+
renderer_context['response']['Content-Type'] = 'application/json'
118133
renderer_context["accepted_media_type"] = 'application/json'
119134
self.media_type = 'application/json'
120135
self.format = 'json'
@@ -126,6 +141,7 @@ def render(self, data, media_type=None, renderer_context=None):
126141
if renderer_context['view'].bit_depth != 8:
127142
# This renderer only works on uint8 data
128143
renderer_context["response"].status_code = 400
144+
renderer_context['response']['Content-Type'] = 'application/json'
129145
renderer_context["accepted_media_type"] = 'application/json'
130146
self.media_type = 'application/json'
131147
self.format = 'json'

django/bosstiles/renderers.py

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# limitations under the License.
1414
import io
1515
from rest_framework import renderers
16+
from rest_framework.renderers import JSONRenderer
17+
from bosscore.renderer_helper import check_for_403
1618

1719

1820
class PNGRenderer(renderers.BaseRenderer):
@@ -23,6 +25,7 @@ class PNGRenderer(renderers.BaseRenderer):
2325
charset = None
2426
render_style = 'binary'
2527

28+
@check_for_403
2629
def render(self, data, media_type=None, renderer_context=None):
2730
file_obj = io.BytesIO()
2831
data.save(file_obj, "PNG")
@@ -38,6 +41,7 @@ class JPEGRenderer(renderers.BaseRenderer):
3841
charset = None
3942
render_style = 'binary'
4043

44+
@check_for_403
4145
def render(self, data, media_type=None, renderer_context=None):
4246
file_obj = io.BytesIO()
4347
data.save(file_obj, "JPEG")

0 commit comments

Comments
 (0)