diff --git a/ai_aside/__init__.py b/ai_aside/__init__.py index 1ccfe5a..12c11ae 100644 --- a/ai_aside/__init__.py +++ b/ai_aside/__init__.py @@ -2,6 +2,6 @@ A plugin containing xblocks and apps supporting GPT and other LLM use on edX. """ -__version__ = '3.6.2' +__version__ = '3.7.0' default_app_config = "ai_aside.apps.AiAsideConfig" diff --git a/ai_aside/config_api/view_utils.py b/ai_aside/config_api/view_utils.py index a972478..643db45 100644 --- a/ai_aside/config_api/view_utils.py +++ b/ai_aside/config_api/view_utils.py @@ -11,15 +11,6 @@ from ai_aside.config_api.permissions import HasStudioWriteAccess -def handle_ai_aside_exception(exc): - """ - Converts ai_aside exceptions into restframework responses - """ - if isinstance(exc, AiAsideException): - return APIResponse(http_status=exc.http_status, data={'message': str(exc)}) - return None - - class APIResponse(Response): """API Response""" def __init__(self, data=None, http_status=None, content_type=None, success=False): @@ -38,11 +29,19 @@ class AiAsideAPIView(APIView): authentication_classes = (JwtAuthentication, SessionAuthentication,) permission_classes = (HasStudioWriteAccess,) - def handle_exception(self, exc): - """ - Converts ai-aside exceptions into standard restframework responses - """ - resp = handle_ai_aside_exception(exc) - if not resp: - resp = super().handle_exception(exc) - return resp + +def handle_errors(view_func): + """ + Wrapper which handles our standard exception. + + We cannot do this by overriding handle_exception as you might expect, + because the newrelic wrapper sits between the view function and the + handle_exception and logs it, which makes our expected exceptions seem + harmful. So we'll handle those before newrelic can see them. + """ + def wrapped_viewfunc(self_, request, **kwargs): + try: + return view_func(self_, request, **kwargs) + except AiAsideException as exc: + return APIResponse(http_status=exc.http_status, data={'message': str(exc)}) + return wrapped_viewfunc diff --git a/ai_aside/config_api/views.py b/ai_aside/config_api/views.py index 8b9c413..ad304cb 100644 --- a/ai_aside/config_api/views.py +++ b/ai_aside/config_api/views.py @@ -27,13 +27,14 @@ ) from ai_aside.config_api.exceptions import AiAsideException, AiAsideNotFoundException from ai_aside.config_api.validators import validate_course_key, validate_unit_key -from ai_aside.config_api.view_utils import AiAsideAPIView, APIResponse +from ai_aside.config_api.view_utils import AiAsideAPIView, APIResponse, handle_errors class CourseSummaryConfigEnabledAPIView(AiAsideAPIView): """ Simple GET endpoint to expose whether the course may use summary config. """ + @handle_errors def get(self, request, course_id=None): """Expose whether the course may use summary config""" if course_id is None: @@ -46,6 +47,7 @@ def get(self, request, course_id=None): class CourseEnabledAPIView(AiAsideAPIView): """Handlers for course level settings""" + @handle_errors def get(self, request, course_id=None): """Gets the enabled state for a course""" if course_id is None: @@ -55,6 +57,7 @@ def get(self, request, course_id=None): settings = get_course_settings(course_key) return APIResponse(success=True, data=settings) + @handle_errors def post(self, request, course_id=None): """Update the course and reset if its necessary""" @@ -74,6 +77,7 @@ def post(self, request, course_id=None): return APIResponse(success=True) + @handle_errors def delete(self, request, course_id=None): """Deletes the settings for a module""" @@ -87,6 +91,7 @@ def delete(self, request, course_id=None): class UnitEnabledAPIView(AiAsideAPIView): """Handlers for module level settings""" + @handle_errors def get(self, request, course_id=None, unit_id=None): """Gets the enabled state for a unit""" if course_id is None or unit_id is None: @@ -97,6 +102,7 @@ def get(self, request, course_id=None, unit_id=None): settings = get_unit_settings(course_key, unit_key) return APIResponse(success=True, data=settings) + @handle_errors def post(self, request, course_id=None, unit_id=None): """Sets the enabled state for a unit""" @@ -111,6 +117,7 @@ def post(self, request, course_id=None, unit_id=None): return APIResponse(success=True) + @handle_errors def delete(self, request, course_id=None, unit_id=None): """Deletes the settings for a unit"""