-added zendesk api endpoints
This commit is contained in:
@@ -94,6 +94,7 @@ from openedx.core.djangoapps.programs.utils import ProgramMarketingDataExtender
|
||||
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
from openedx.core.djangoapps.util.user_messages import PageLevelMessages
|
||||
from openedx.core.djangoapps.zendesk_proxy.utils import create_zendesk_ticket
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.features.course_duration_limits.access import generate_course_expired_fragment
|
||||
from openedx.features.course_experience import (
|
||||
@@ -112,7 +113,7 @@ from track import segment
|
||||
from util.cache import cache, cache_if_anonymous
|
||||
from util.db import outer_atomic
|
||||
from util.milestones_helpers import get_prerequisite_courses_display
|
||||
from util.views import _record_feedback_in_zendesk, ensure_valid_course_key, ensure_valid_usage_key
|
||||
from util.views import ensure_valid_course_key, ensure_valid_usage_key
|
||||
from xmodule.course_module import COURSE_VISIBILITY_PUBLIC, COURSE_VISIBILITY_PUBLIC_OUTLINE
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem
|
||||
@@ -1625,7 +1626,7 @@ def financial_assistance_request(request):
|
||||
# Thrown if fields are missing
|
||||
return HttpResponseBadRequest(u'The field {} is required.'.format(text_type(err)))
|
||||
|
||||
zendesk_submitted = _record_feedback_in_zendesk(
|
||||
zendesk_submitted = create_zendesk_ticket(
|
||||
legal_name,
|
||||
email,
|
||||
u'Financial assistance request for learner {username} in course {course_name}'.format(
|
||||
@@ -1633,12 +1634,12 @@ def financial_assistance_request(request):
|
||||
course_name=course.display_name
|
||||
),
|
||||
u'Financial Assistance Request',
|
||||
{'course_id': course_id},
|
||||
tags={'course_id': course_id},
|
||||
# Send the application as additional info on the ticket so
|
||||
# that it is not shown when support replies. This uses
|
||||
# OrderedDict so that information is presented in the right
|
||||
# order.
|
||||
OrderedDict((
|
||||
additional_info=OrderedDict((
|
||||
('Username', username),
|
||||
('Full Name', legal_name),
|
||||
('Course ID', course_id),
|
||||
@@ -1650,8 +1651,7 @@ def financial_assistance_request(request):
|
||||
(FA_EFFORT_LABEL, '\n' + effort + '\n\n'),
|
||||
('Client IP', ip_address),
|
||||
)),
|
||||
group_name='Financial Assistance',
|
||||
require_update=True
|
||||
group='Financial Assistance',
|
||||
)
|
||||
|
||||
if not zendesk_submitted:
|
||||
|
||||
@@ -11,21 +11,25 @@ from django.conf import settings
|
||||
import requests
|
||||
from rest_framework import status
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_zendesk_ticket(requester_name, requester_email, subject, body, custom_fields=None, uploads=None, tags=None):
|
||||
def _std_error_message(details, payload):
|
||||
"""Internal helper to standardize error message. This allows for simpler splunk alerts."""
|
||||
return u'zendesk_proxy action required\n{}\nNo ticket created for payload {}'.format(details, payload)
|
||||
|
||||
|
||||
def _get_request_headers():
|
||||
return {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': u"Bearer {}".format(settings.ZENDESK_OAUTH_ACCESS_TOKEN),
|
||||
}
|
||||
|
||||
def create_zendesk_ticket(requester_name, requester_email, subject, body, group=None, custom_fields=None, uploads=None, tags=None, additional_info=None):
|
||||
"""
|
||||
Create a Zendesk ticket via API.
|
||||
|
||||
Note that we do this differently in other locations (lms/djangoapps/commerce/signals.py and
|
||||
common/djangoapps/util/views.py). Both of those callers use basic auth, and should be switched over to this oauth
|
||||
implementation once the immediate pressures of zendesk_proxy are resolved.
|
||||
"""
|
||||
def _std_error_message(details, payload):
|
||||
"""Internal helper to standardize error message. This allows for simpler splunk alerts."""
|
||||
return u'zendesk_proxy action required\n{}\nNo ticket created for payload {}'.format(details, payload)
|
||||
|
||||
if tags:
|
||||
# Remove duplicates from tags list
|
||||
tags = list(set(tags))
|
||||
@@ -46,22 +50,22 @@ def create_zendesk_ticket(requester_name, requester_email, subject, body, custom
|
||||
}
|
||||
}
|
||||
|
||||
if not (settings.ZENDESK_URL and settings.ZENDESK_OAUTH_ACCESS_TOKEN):
|
||||
log.error(_std_error_message("zendesk not configured", data))
|
||||
return status.HTTP_503_SERVICE_UNAVAILABLE
|
||||
|
||||
if group:
|
||||
group_id = get_zendesk_group_by_name(group)
|
||||
data['ticket']['group_id'] = group_id
|
||||
|
||||
# Encode the data to create a JSON payload
|
||||
payload = json.dumps(data)
|
||||
|
||||
if not (settings.ZENDESK_URL and settings.ZENDESK_OAUTH_ACCESS_TOKEN):
|
||||
log.error(_std_error_message("zendesk not configured", payload))
|
||||
return status.HTTP_503_SERVICE_UNAVAILABLE
|
||||
|
||||
# Set the request parameters
|
||||
url = urljoin(settings.ZENDESK_URL, '/api/v2/tickets.json')
|
||||
headers = {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': u"Bearer {}".format(settings.ZENDESK_OAUTH_ACCESS_TOKEN),
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, data=payload, headers=headers)
|
||||
response = requests.post(url, data=payload, headers=_get_request_headers())
|
||||
|
||||
# Check for HTTP codes other than 201 (Created)
|
||||
if response.status_code == status.HTTP_201_CREATED:
|
||||
@@ -73,7 +77,72 @@ def create_zendesk_ticket(requester_name, requester_email, subject, body, custom
|
||||
payload
|
||||
)
|
||||
)
|
||||
if additional_info:
|
||||
ticket = json.loads(response.text)['ticket']
|
||||
return post_additional_info_as_comment(ticket['id'], additional_info)
|
||||
|
||||
return response.status_code
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.exception(_std_error_message('Internal server error', payload))
|
||||
return status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
|
||||
|
||||
def get_zendesk_group_by_name(name):
|
||||
"""
|
||||
Calls the Zendesk list-groups api
|
||||
|
||||
Returns the group Id matching the name.
|
||||
"""
|
||||
url = urljoin(settings.ZENDESK_URL, '/api/v2/groups.json')
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=_get_request_headers())
|
||||
|
||||
groups = json.loads(response.text)['groups']
|
||||
for group in groups:
|
||||
if group['name'] == name:
|
||||
return group['id']
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
log.exception(_std_error_message('Internal server error', 'None'))
|
||||
|
||||
return status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
log.exception(_std_error_message('Tried to get zendesk group which does not exist', name))
|
||||
raise Exception
|
||||
|
||||
|
||||
def post_additional_info_as_comment(ticket_id, additional_info):
|
||||
"""
|
||||
Post the Additional Provided as a comment, So that it is only visible
|
||||
to management and not students.
|
||||
"""
|
||||
additional_info_string = (
|
||||
u"Additional information:\n\n" +
|
||||
u"\n".join(u"%s: %s" % (key, value) for (key, value) in additional_info.items() if value is not None)
|
||||
)
|
||||
|
||||
data = {
|
||||
'ticket': {
|
||||
'comment': {
|
||||
'body': additional_info_string,
|
||||
'publuc': False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
url = urljoin(settings.ZENDESK_URL, 'api/v2/tickets/{}.json'.format(ticket_id))
|
||||
|
||||
try:
|
||||
response = requests.put(url, data=json.dumps(data), headers=_get_request_headers())
|
||||
if response.status_code == 200:
|
||||
log.debug(u'Successfully created comment for ticket {}'.format(ticket_id))
|
||||
else:
|
||||
log.error(
|
||||
_std_error_message(
|
||||
u'Unexpected response: {} - {}'.format(response.status_code, response.content),
|
||||
data
|
||||
)
|
||||
)
|
||||
return response.status_code
|
||||
except Exception: # pylint: disable=broad-except
|
||||
log.exception(_std_error_message('Internal server error', data))
|
||||
return status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
|
||||
Reference in New Issue
Block a user