Updated auto_auth endpoint to always return JSON
Defaulting to a plaintext response makes no sense for an endpoint that is intended to be used by machines for testing. The endpoint now returns JSON only unless a redirect action is triggered.
This commit is contained in:
committed by
Clinton Blackburn
parent
c285b4f36d
commit
6ff614800c
@@ -5,13 +5,15 @@ from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
from mock import Mock, patch
|
||||
from mock import patch, Mock
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from opaque_keys.edx.locator import CourseLocator
|
||||
|
||||
from django_comment_common.models import FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_STUDENT, Role
|
||||
from django_comment_common.models import (
|
||||
Role, FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_STUDENT
|
||||
)
|
||||
from django_comment_common.utils import seed_permissions_roles
|
||||
from student.models import CourseEnrollment, UserProfile, anonymous_id_for_user
|
||||
from student.models import anonymous_id_for_user, CourseAccessRole, CourseEnrollment, UserProfile
|
||||
from util.testing import UrlResetMixin
|
||||
|
||||
|
||||
@@ -169,18 +171,16 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase):
|
||||
course_roles[FORUM_ROLE_MODERATOR],
|
||||
course_roles[FORUM_ROLE_ADMINISTRATOR]]))
|
||||
|
||||
@ddt.data(*COURSE_IDS_DDT)
|
||||
@ddt.unpack
|
||||
def test_json_response(self, course_id, course_key): # pylint: disable=unused-argument
|
||||
"""Verify that we can get JSON back from the auto_auth page."""
|
||||
response = self._auto_auth(HTTP_ACCEPT='application/json')
|
||||
def test_json_response(self):
|
||||
""" The view should return JSON. """
|
||||
response = self._auto_auth()
|
||||
response_data = json.loads(response.content)
|
||||
for key in ['created_status', 'username', 'email', 'password', 'user_id', 'anonymous_id']:
|
||||
self.assertIn(key, response_data)
|
||||
user = User.objects.get(username=response_data['username'])
|
||||
self.assertDictContainsSubset(
|
||||
{
|
||||
'created_status': "Logged in",
|
||||
'created_status': 'Logged in',
|
||||
'anonymous_id': anonymous_id_for_user(user, None),
|
||||
},
|
||||
response_data
|
||||
@@ -237,23 +237,23 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase):
|
||||
|
||||
self.assertTrue(response.url.endswith(url_pattern)) # pylint: disable=no-member
|
||||
|
||||
def _auto_auth(self, params=None, status_code=None, **kwargs):
|
||||
def _auto_auth(self, params=None, status_code=200, **kwargs):
|
||||
"""
|
||||
Make a request to the auto-auth end-point and check
|
||||
that the response is successful.
|
||||
|
||||
Arguments:
|
||||
params (dict): Dict of params to pass to the auto_auth view
|
||||
status_code (int): Expected response status code
|
||||
kwargs: Passed directly to the test client's get method.
|
||||
|
||||
Returns
|
||||
response: The response object for the auto_auth page.
|
||||
Returns:
|
||||
Response: The response object for the auto_auth page.
|
||||
"""
|
||||
params = params or {}
|
||||
response = self.client.get(self.url, params, **kwargs)
|
||||
|
||||
expected_status_code = status_code if status_code else 200
|
||||
self.assertEqual(response.status_code, expected_status_code)
|
||||
self.assertEqual(response.status_code, status_code)
|
||||
|
||||
# Check that session and CSRF are set in the response
|
||||
for cookie in ['csrftoken', 'sessionid']:
|
||||
@@ -270,6 +270,26 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_course_access_roles(self):
|
||||
""" Passing role names via the course_access_roles query string parameter should create CourseAccessRole
|
||||
objects associated with the user.
|
||||
"""
|
||||
expected_roles = ['finance_admin', 'sales_admin']
|
||||
course_key = CourseLocator.from_string(self.COURSE_ID_SPLIT)
|
||||
params = {
|
||||
'course_id': str(course_key),
|
||||
'course_access_roles': ','.join(expected_roles)
|
||||
}
|
||||
response = self._auto_auth(params)
|
||||
user_info = json.loads(response.content)
|
||||
|
||||
for role in expected_roles:
|
||||
self.assertTrue(
|
||||
CourseAccessRole.objects.filter(
|
||||
user__id=user_info['user_id'], course_id=course_key, org=course_key.org, role=role
|
||||
).exists()
|
||||
)
|
||||
|
||||
|
||||
class AutoAuthDisabledTestCase(AutoAuthTestCase):
|
||||
"""
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
"""
|
||||
Student Views
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import uuid
|
||||
import warnings
|
||||
from collections import defaultdict, namedtuple
|
||||
from urlparse import parse_qs, urljoin, urlsplit, urlunsplit
|
||||
from urlparse import parse_qs, urlsplit, urlunsplit
|
||||
|
||||
import analytics
|
||||
import edx_oauth2_provider
|
||||
@@ -25,7 +26,7 @@ from django.core.validators import ValidationError, validate_email
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import Signal, receiver
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseServerError
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.shortcuts import redirect
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils.encoding import force_bytes, force_text
|
||||
@@ -35,6 +36,7 @@ from django.utils.translation import get_language, ungettext
|
||||
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
from django.views.generic import TemplateView
|
||||
from eventtracking import tracker
|
||||
from ipware.ip import get_ip
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -62,9 +64,8 @@ from certificates.models import ( # pylint: disable=import-error
|
||||
from course_modes.models import CourseMode
|
||||
from courseware.access import has_access
|
||||
from courseware.courses import get_courses, sort_by_announcement, sort_by_start_date # pylint: disable=import-error
|
||||
from django_comment_common.models import Role
|
||||
from django_comment_common.models import assign_role
|
||||
from edxmako.shortcuts import render_to_response, render_to_string
|
||||
from eventtracking import tracker
|
||||
from lms.djangoapps.commerce.utils import EcommerceService # pylint: disable=import-error
|
||||
from lms.djangoapps.grades.new.course_grade_factory import CourseGradeFactory
|
||||
from lms.djangoapps.verify_student.models import SoftwareSecurePhotoVerification # pylint: disable=import-error
|
||||
@@ -99,11 +100,11 @@ from student.helpers import (
|
||||
)
|
||||
from student.models import (
|
||||
ALLOWEDTOENROLL_TO_ENROLLED,
|
||||
CourseAccessRole,
|
||||
CourseEnrollment,
|
||||
CourseEnrollmentAllowed,
|
||||
CourseEnrollmentAttribute,
|
||||
DashboardConfiguration,
|
||||
EnrollStatusChange,
|
||||
LinkedInAddToProfileConfiguration,
|
||||
LoginFailures,
|
||||
LogoutViewConfiguration,
|
||||
@@ -2131,6 +2132,27 @@ def create_account(request, post_override=None):
|
||||
return response
|
||||
|
||||
|
||||
def str2bool(s):
|
||||
s = str(s)
|
||||
return s.lower() in ('yes', 'true', 't', '1')
|
||||
|
||||
|
||||
def _clean_roles(roles):
|
||||
""" Clean roles.
|
||||
|
||||
Strips whitespace from roles, and removes empty items.
|
||||
|
||||
Args:
|
||||
roles (str[]): List of role names.
|
||||
|
||||
Returns:
|
||||
str[]
|
||||
"""
|
||||
roles = [role.strip() for role in roles]
|
||||
roles = [role for role in roles if role]
|
||||
return roles
|
||||
|
||||
|
||||
def auto_auth(request):
|
||||
"""
|
||||
Create or configure a user account, then log in as that user.
|
||||
@@ -2154,29 +2176,27 @@ def auto_auth(request):
|
||||
"""
|
||||
|
||||
# Generate a unique name to use if none provided
|
||||
unique_name = uuid.uuid4().hex[0:30]
|
||||
generated_username = uuid.uuid4().hex[0:30]
|
||||
|
||||
# Use the params from the request, otherwise use these defaults
|
||||
username = request.GET.get('username', unique_name)
|
||||
password = request.GET.get('password', unique_name)
|
||||
email = request.GET.get('email', unique_name + "@example.com")
|
||||
username = request.GET.get('username', generated_username)
|
||||
password = request.GET.get('password', username)
|
||||
email = request.GET.get('email', username + "@example.com")
|
||||
full_name = request.GET.get('full_name', username)
|
||||
is_staff = request.GET.get('staff', None)
|
||||
is_superuser = request.GET.get('superuser', None)
|
||||
course_id = request.GET.get('course_id', None)
|
||||
redirect_to = request.GET.get('redirect_to', None)
|
||||
active_status = request.GET.get('is_active')
|
||||
is_staff = str2bool(request.GET.get('staff', False))
|
||||
is_superuser = str2bool(request.GET.get('superuser', False))
|
||||
course_id = request.GET.get('course_id')
|
||||
redirect_to = request.GET.get('redirect_to')
|
||||
is_active = str2bool(request.GET.get('is_active', True))
|
||||
|
||||
# mode has to be one of 'honor'/'professional'/'verified'/'audit'/'no-id-professional'/'credit'
|
||||
# Valid modes: audit, credit, honor, no-id-professional, professional, verified
|
||||
enrollment_mode = request.GET.get('enrollment_mode', 'honor')
|
||||
|
||||
active_status = (not active_status or active_status == 'true')
|
||||
# Parse roles, stripping whitespace, and filtering out empty strings
|
||||
roles = _clean_roles(request.GET.get('roles', '').split(','))
|
||||
course_access_roles = _clean_roles(request.GET.get('course_access_roles', '').split(','))
|
||||
|
||||
course_key = None
|
||||
if course_id:
|
||||
course_key = CourseLocator.from_string(course_id)
|
||||
role_names = [v.strip() for v in request.GET.get('roles', '').split(',') if v.strip()]
|
||||
redirect_when_done = request.GET.get('redirect', '').lower() == 'true' or redirect_to
|
||||
redirect_when_done = str2bool(request.GET.get('redirect', '')) or redirect_to
|
||||
login_when_done = 'no_login' not in request.GET
|
||||
|
||||
form = AccountCreationForm(
|
||||
@@ -2199,23 +2219,18 @@ def auto_auth(request):
|
||||
user = User.objects.get(username=username)
|
||||
user.email = email
|
||||
user.set_password(password)
|
||||
user.is_active = active_status
|
||||
user.is_active = is_active
|
||||
user.save()
|
||||
profile = UserProfile.objects.get(user=user)
|
||||
reg = Registration.objects.get(user=user)
|
||||
except PermissionDenied:
|
||||
return HttpResponseForbidden(_("Account creation not allowed."))
|
||||
return HttpResponseForbidden(_('Account creation not allowed.'))
|
||||
|
||||
# Set the user's global staff bit
|
||||
if is_staff is not None:
|
||||
user.is_staff = (is_staff == "true")
|
||||
user.save()
|
||||
user.is_staff = is_staff
|
||||
user.is_superuser = is_superuser
|
||||
user.save()
|
||||
|
||||
if is_superuser is not None:
|
||||
user.is_superuser = (is_superuser == "true")
|
||||
user.save()
|
||||
|
||||
if active_status:
|
||||
if is_active:
|
||||
reg.activate()
|
||||
reg.save()
|
||||
|
||||
@@ -2226,13 +2241,17 @@ def auto_auth(request):
|
||||
profile.save()
|
||||
|
||||
# Enroll the user in a course
|
||||
if course_key is not None:
|
||||
course_key = None
|
||||
if course_id:
|
||||
course_key = CourseLocator.from_string(course_id)
|
||||
CourseEnrollment.enroll(user, course_key, mode=enrollment_mode)
|
||||
|
||||
# Apply the roles
|
||||
for role_name in role_names:
|
||||
role = Role.objects.get(name=role_name, course_id=course_key)
|
||||
user.roles.add(role)
|
||||
# Apply the roles
|
||||
for role in roles:
|
||||
assign_role(course_key, user, role)
|
||||
|
||||
for role in course_access_roles:
|
||||
CourseAccessRole.objects.update_or_create(user=user, course_id=course_key, org=course_key.org, role=role)
|
||||
|
||||
# Log in as the user
|
||||
if login_when_done:
|
||||
@@ -2241,50 +2260,33 @@ def auto_auth(request):
|
||||
|
||||
create_comments_service_user(user)
|
||||
|
||||
# Provide the user with a valid CSRF token
|
||||
# then return a 200 response unless redirect is true
|
||||
if redirect_when_done:
|
||||
# Redirect to specific page if specified
|
||||
if redirect_to:
|
||||
# Redirect to page specified by the client
|
||||
redirect_url = redirect_to
|
||||
# Redirect to course home page if course_id is known
|
||||
elif course_id:
|
||||
# Redirect to the course homepage (in LMS) or outline page (in Studio)
|
||||
try:
|
||||
# redirect to course home page in LMS
|
||||
redirect_url = reverse(
|
||||
course_home_url_name(request),
|
||||
kwargs={'course_id': course_id}
|
||||
)
|
||||
redirect_url = reverse(course_home_url_name(request), kwargs={'course_id': course_id})
|
||||
except NoReverseMatch:
|
||||
# redirect to course outline page in Studio
|
||||
redirect_url = reverse(
|
||||
'course_handler',
|
||||
kwargs={'course_key_string': course_id}
|
||||
)
|
||||
redirect_url = reverse('course_handler', kwargs={'course_key_string': course_id})
|
||||
else:
|
||||
# Redirect to the learner dashboard (in LMS) or homepage (in Studio)
|
||||
try:
|
||||
# redirect to dashboard for LMS
|
||||
redirect_url = reverse('dashboard')
|
||||
except NoReverseMatch:
|
||||
# redirect to home for Studio
|
||||
redirect_url = reverse('home')
|
||||
|
||||
return redirect(redirect_url)
|
||||
elif request.META.get('HTTP_ACCEPT') == 'application/json':
|
||||
else:
|
||||
response = JsonResponse({
|
||||
'created_status': u"Logged in" if login_when_done else "Created",
|
||||
'created_status': 'Logged in' if login_when_done else 'Created',
|
||||
'username': username,
|
||||
'email': email,
|
||||
'password': password,
|
||||
'user_id': user.id, # pylint: disable=no-member
|
||||
'anonymous_id': anonymous_id_for_user(user, None),
|
||||
})
|
||||
else:
|
||||
success_msg = u"{} user {} ({}) with password {} and user_id {}".format(
|
||||
u"Logged in" if login_when_done else "Created",
|
||||
username, email, password, user.id # pylint: disable=no-member
|
||||
)
|
||||
response = HttpResponse(success_msg)
|
||||
response.set_cookie('csrftoken', csrf(request)['csrf_token'])
|
||||
return response
|
||||
|
||||
|
||||
Reference in New Issue
Block a user