Improve forum error handling
CommentClientError now has sane subclasses that are meaningfully distinct, and each subclass is handled appropriately. Errors raised by the requests library are no longer handled by turning them into CommentClientErrors, since there is no meaningful handling we can do, and this way we will get more visibility into why errors are occurring. Also, HTTP status codes from the comments service indicating client error are correctly passed through to the client.
This commit is contained in:
@@ -1,2 +1,5 @@
|
||||
from .comment_client import *
|
||||
from .utils import CommentClientError, CommentClientUnknownError
|
||||
from .utils import (
|
||||
CommentClientError, CommentClientRequestError,
|
||||
CommentClient500Error, CommentClientMaintenanceError
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .utils import CommentClientError, perform_request
|
||||
from .utils import CommentClientRequestError, perform_request
|
||||
|
||||
from .thread import Thread, _url_for_flag_abuse_thread, _url_for_unflag_abuse_thread
|
||||
import models
|
||||
@@ -48,7 +48,7 @@ class Comment(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_flag_abuse_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can only flag/unflag threads or comments")
|
||||
raise CommentClientRequestError("Can only flag/unflag threads or comments")
|
||||
params = {'user_id': user.id}
|
||||
request = perform_request('put', url, params)
|
||||
voteable.update_attributes(request)
|
||||
@@ -59,7 +59,7 @@ class Comment(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_unflag_abuse_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can flag/unflag for threads or comments")
|
||||
raise CommentClientRequestError("Can flag/unflag for threads or comments")
|
||||
params = {'user_id': user.id}
|
||||
|
||||
if removeAll:
|
||||
|
||||
@@ -119,13 +119,13 @@ class Model(object):
|
||||
@classmethod
|
||||
def url(cls, action, params={}):
|
||||
if cls.base_url is None:
|
||||
raise CommentClientError("Must provide base_url when using default url function")
|
||||
raise CommentClientRequestError("Must provide base_url when using default url function")
|
||||
if action not in cls.DEFAULT_ACTIONS:
|
||||
raise ValueError("Invalid action {0}. The supported action must be in {1}".format(action, str(cls.DEFAULT_ACTIONS)))
|
||||
elif action in cls.DEFAULT_ACTIONS_WITH_ID:
|
||||
try:
|
||||
return cls.url_with_id(params)
|
||||
except KeyError:
|
||||
raise CommentClientError("Cannot perform action {0} without id".format(action))
|
||||
raise CommentClientRequestError("Cannot perform action {0} without id".format(action))
|
||||
else: # action must be in DEFAULT_ACTIONS_WITHOUT_ID now
|
||||
return cls.url_without_id()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from .utils import merge_dict, strip_blank, strip_none, extract, perform_request
|
||||
from .utils import CommentClientError
|
||||
from .utils import CommentClientRequestError
|
||||
import models
|
||||
import settings
|
||||
|
||||
@@ -88,7 +88,7 @@ class Thread(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_flag_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can only flag/unflag threads or comments")
|
||||
raise CommentClientRequestError("Can only flag/unflag threads or comments")
|
||||
params = {'user_id': user.id}
|
||||
request = perform_request('put', url, params)
|
||||
voteable.update_attributes(request)
|
||||
@@ -99,7 +99,7 @@ class Thread(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_unflag_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can only flag/unflag for threads or comments")
|
||||
raise CommentClientRequestError("Can only flag/unflag for threads or comments")
|
||||
params = {'user_id': user.id}
|
||||
#if you're an admin, when you unflag, remove ALL flags
|
||||
if removeAll:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from .utils import merge_dict, perform_request, CommentClientError
|
||||
from .utils import merge_dict, perform_request, CommentClientRequestError
|
||||
|
||||
import models
|
||||
import settings
|
||||
@@ -41,7 +41,7 @@ class User(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_vote_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can only vote / unvote for threads or comments")
|
||||
raise CommentClientRequestError("Can only vote / unvote for threads or comments")
|
||||
params = {'user_id': self.id, 'value': value}
|
||||
request = perform_request('put', url, params)
|
||||
voteable.update_attributes(request)
|
||||
@@ -52,14 +52,14 @@ class User(models.Model):
|
||||
elif voteable.type == 'comment':
|
||||
url = _url_for_vote_comment(voteable.id)
|
||||
else:
|
||||
raise CommentClientError("Can only vote / unvote for threads or comments")
|
||||
raise CommentClientRequestError("Can only vote / unvote for threads or comments")
|
||||
params = {'user_id': self.id}
|
||||
request = perform_request('delete', url, params)
|
||||
voteable.update_attributes(request)
|
||||
|
||||
def active_threads(self, query_params={}):
|
||||
if not self.course_id:
|
||||
raise CommentClientError("Must provide course_id when retrieving active threads for the user")
|
||||
raise CommentClientRequestError("Must provide course_id when retrieving active threads for the user")
|
||||
url = _url_for_user_active_threads(self.id)
|
||||
params = {'course_id': self.course_id}
|
||||
params = merge_dict(params, query_params)
|
||||
@@ -68,7 +68,7 @@ class User(models.Model):
|
||||
|
||||
def subscribed_threads(self, query_params={}):
|
||||
if not self.course_id:
|
||||
raise CommentClientError("Must provide course_id when retrieving subscribed threads for the user")
|
||||
raise CommentClientRequestError("Must provide course_id when retrieving subscribed threads for the user")
|
||||
url = _url_for_user_subscribed_threads(self.id)
|
||||
params = {'course_id': self.course_id}
|
||||
params = merge_dict(params, query_params)
|
||||
|
||||
@@ -55,35 +55,30 @@ def perform_request(method, url, data_or_params=None, *args, **kwargs):
|
||||
headers = {'X-Edx-Api-Key': settings.API_KEY}
|
||||
request_id = uuid4()
|
||||
request_id_dict = {'request_id': request_id}
|
||||
try:
|
||||
if method in ['post', 'put', 'patch']:
|
||||
data = data_or_params
|
||||
params = request_id_dict
|
||||
else:
|
||||
data = None
|
||||
params = merge_dict(data_or_params, request_id_dict)
|
||||
with request_timer(request_id, method, url):
|
||||
response = requests.request(
|
||||
method,
|
||||
url,
|
||||
data=data,
|
||||
params=params,
|
||||
headers=headers,
|
||||
timeout=5
|
||||
)
|
||||
except Exception as err:
|
||||
log.exception("Trying to call {method} on {url} with params {params}".format(
|
||||
method=method, url=url, params=data_or_params))
|
||||
# Reraise with a single exception type
|
||||
raise CommentClientError(str(err))
|
||||
|
||||
if method in ['post', 'put', 'patch']:
|
||||
data = data_or_params
|
||||
params = request_id_dict
|
||||
else:
|
||||
data = None
|
||||
params = merge_dict(data_or_params, request_id_dict)
|
||||
with request_timer(request_id, method, url):
|
||||
response = requests.request(
|
||||
method,
|
||||
url,
|
||||
data=data,
|
||||
params=params,
|
||||
headers=headers,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if 200 < response.status_code < 500:
|
||||
raise CommentClientError(response.text)
|
||||
raise CommentClientRequestError(response.text, response.status_code)
|
||||
# Heroku returns a 503 when an application is in maintenance mode
|
||||
elif response.status_code == 503:
|
||||
raise CommentClientMaintenanceError(response.text)
|
||||
elif response.status_code == 500:
|
||||
raise CommentClientUnknownError(response.text)
|
||||
raise CommentClient500Error(response.text)
|
||||
else:
|
||||
if kwargs.get("raw", False):
|
||||
return response.text
|
||||
@@ -99,9 +94,15 @@ class CommentClientError(Exception):
|
||||
return repr(self.message)
|
||||
|
||||
|
||||
class CommentClientRequestError(CommentClientError):
|
||||
def __init__(self, msg, status_code=400):
|
||||
super(CommentClientRequestError, self).__init__(msg)
|
||||
self.status_code = status_code
|
||||
|
||||
|
||||
class CommentClient500Error(CommentClientError):
|
||||
pass
|
||||
|
||||
|
||||
class CommentClientMaintenanceError(CommentClientError):
|
||||
pass
|
||||
|
||||
|
||||
class CommentClientUnknownError(CommentClientError):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user