Files
edx-platform/lms/lib/comment_client/utils.py
2019-01-08 15:41:24 -05:00

156 lines
4.6 KiB
Python

"""" Common utilities for comment client wrapper """
import logging
from contextlib import contextmanager
from time import time
from uuid import uuid4
import requests
from django.utils.translation import get_language
from .settings import SERVICE_HOST as COMMENTS_SERVICE
log = logging.getLogger(__name__)
def strip_none(dic):
return dict([(k, v) for k, v in dic.iteritems() if v is not None])
def strip_blank(dic):
def _is_blank(v):
return isinstance(v, str) and len(v.strip()) == 0
return dict([(k, v) for k, v in dic.iteritems() if not _is_blank(v)])
def extract(dic, keys):
if isinstance(keys, str):
return strip_none({keys: dic.get(keys)})
else:
return strip_none({k: dic.get(k) for k in keys})
def perform_request(method, url, data_or_params=None, raw=False,
metric_action=None, metric_tags=None, paged_results=False):
# To avoid dependency conflict
from django_comment_common.models import ForumsConfig
config = ForumsConfig.current()
if not config.enabled:
raise CommentClientMaintenanceError('service disabled')
if metric_tags is None:
metric_tags = []
metric_tags.append(u'method:{}'.format(method))
if metric_action:
metric_tags.append(u'action:{}'.format(metric_action))
if data_or_params is None:
data_or_params = {}
headers = {
'X-Edx-Api-Key': config.api_key,
'Accept-Language': get_language(),
}
request_id = uuid4()
request_id_dict = {'request_id': request_id}
if method in ['post', 'put', 'patch']:
data = data_or_params
params = request_id_dict
else:
data = None
params = data_or_params.copy()
params.update(request_id_dict)
response = requests.request(
method,
url,
data=data,
params=params,
headers=headers,
timeout=config.connection_timeout
)
metric_tags.append(u'status_code:{}'.format(response.status_code))
if response.status_code > 200:
metric_tags.append(u'result:failure')
else:
metric_tags.append(u'result:success')
if 200 < response.status_code < 500:
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 CommentClient500Error(response.text)
else:
if raw:
return response.text
else:
try:
data = response.json()
except ValueError:
raise CommentClientError(
u"Invalid JSON response for request {request_id}; first 100 characters: '{content}'".format(
request_id=request_id,
content=response.text[:100]
)
)
return data
class CommentClientError(Exception):
pass
class CommentClientRequestError(CommentClientError):
def __init__(self, msg, status_codes=400):
super(CommentClientRequestError, self).__init__(msg)
self.status_code = status_codes
class CommentClient500Error(CommentClientError):
pass
class CommentClientMaintenanceError(CommentClientError):
pass
class CommentClientPaginatedResult(object):
""" class for paginated results returned from comment services"""
def __init__(self, collection, page, num_pages, thread_count=0, corrected_text=None):
self.collection = collection
self.page = page
self.num_pages = num_pages
self.thread_count = thread_count
self.corrected_text = corrected_text
def check_forum_heartbeat():
"""
Check the forum connection via its built-in heartbeat service and create an answer which can be used in the LMS
heartbeat django application.
This function can be connected to the LMS heartbeat checker through the HEARTBEAT_CHECKS variable.
"""
# To avoid dependency conflict
from django_comment_common.models import ForumsConfig
config = ForumsConfig.current()
if not config.enabled:
# If this check is enabled but forums disabled, don't connect, just report no error
return 'forum', True, 'OK'
try:
res = requests.get(
'%s/heartbeat' % COMMENTS_SERVICE,
timeout=config.connection_timeout
).json()
if res['OK']:
return 'forum', True, 'OK'
else:
return 'forum', False, res.get('check', 'Forum heartbeat failed')
except Exception as fail:
return 'forum', False, unicode(fail)