Commit a227b14f by cahrens

Auto-enroll course staff to fix "View Live".

STUD-554

Code review feedback.
parent 25e98fcb
......@@ -5,6 +5,9 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Studio: Studio course authors (both instructors and staff) will be auto-enrolled
for their courses so that "View Live" works.
Common: Added ratelimiting to our authentication backend.
Common: Add additional logging to cover login attempts and logouts.
......
......@@ -49,7 +49,7 @@ import datetime
from pytz import UTC
from uuid import uuid4
from pymongo import MongoClient
from .utils import get_enrollment_count
TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE)
TEST_DATA_CONTENTSTORE['OPTIONS']['db'] = 'test_xcontent_%s' % uuid4().hex
......@@ -1041,12 +1041,18 @@ class ContentStoreTest(ModuleStoreTestCase):
data = parse_json(resp)
self.assertNotIn('ErrMsg', data)
self.assertEqual(data['id'], 'i4x://MITx/{0}/course/2013_Spring'.format(test_course_data['number']))
# Verify that the creator is now registered in the course.
self.assertEqual(1, get_enrollment_count(self.user, self._get_course_id(test_course_data)))
return test_course_data
def test_create_course_check_forum_seeding(self):
"""Test new course creation and verify forum seeding """
test_course_data = self.assert_created_course(number_suffix=uuid4().hex)
self.assertTrue(are_permissions_roles_seeded('MITx/{0}/2013_Spring'.format(test_course_data['number'])))
self.assertTrue(are_permissions_roles_seeded(self._get_course_id(test_course_data)))
def _get_course_id(self, test_course_data):
"""Returns the course ID (org/number/run)."""
return "{org}/{number}/{run}".format(**test_course_data)
def test_create_course_duplicate_course(self):
"""Test new course creation - error path"""
......@@ -1057,10 +1063,13 @@ class ContentStoreTest(ModuleStoreTestCase):
"""
Checks that the course did not get created
"""
course_id = self._get_course_id(self.course_data)
initially_enrolled_count = get_enrollment_count(self.user, course_id)
resp = self.client.post(reverse('create_new_course'), self.course_data)
self.assertEqual(resp.status_code, 200)
data = parse_json(resp)
self.assertEqual(data['ErrMsg'], error_message)
self.assertEqual(initially_enrolled_count, get_enrollment_count(self.user, course_id))
def test_create_course_duplicate_number(self):
"""Test new course creation - error path"""
......
"""
Tests for contentstore/views/user.py.
"""
import json
from .utils import CourseTestCase
from .utils import CourseTestCase, get_enrollment_count
from django.contrib.auth.models import User, Group
from django.core.urlresolvers import reverse
from auth.authz import get_course_groupname_for_role
......@@ -90,6 +93,7 @@ class UsersTestCase(CourseTestCase):
# no content: should not be in any roles
self.assertNotIn(self.staff_groupname, groups)
self.assertNotIn(self.inst_groupname, groups)
self.assert_not_enrolled()
def test_detail_post_staff(self):
resp = self.client.post(
......@@ -104,6 +108,7 @@ class UsersTestCase(CourseTestCase):
groups = [g.name for g in ext_user.groups.all()]
self.assertIn(self.staff_groupname, groups)
self.assertNotIn(self.inst_groupname, groups)
self.assert_enrolled()
def test_detail_post_staff_other_inst(self):
inst_group, _ = Group.objects.get_or_create(name=self.inst_groupname)
......@@ -122,6 +127,7 @@ class UsersTestCase(CourseTestCase):
groups = [g.name for g in ext_user.groups.all()]
self.assertIn(self.staff_groupname, groups)
self.assertNotIn(self.inst_groupname, groups)
self.assert_enrolled()
# check that other user is unchanged
user = User.objects.get(email=self.user.email)
groups = [g.name for g in user.groups.all()]
......@@ -141,6 +147,7 @@ class UsersTestCase(CourseTestCase):
groups = [g.name for g in ext_user.groups.all()]
self.assertNotIn(self.staff_groupname, groups)
self.assertIn(self.inst_groupname, groups)
self.assert_enrolled()
def test_detail_post_missing_role(self):
resp = self.client.post(
......@@ -152,6 +159,7 @@ class UsersTestCase(CourseTestCase):
self.assert4XX(resp.status_code)
result = json.loads(resp.content)
self.assertIn("error", result)
self.assert_not_enrolled()
def test_detail_post_bad_json(self):
resp = self.client.post(
......@@ -163,6 +171,7 @@ class UsersTestCase(CourseTestCase):
self.assert4XX(resp.status_code)
result = json.loads(resp.content)
self.assertIn("error", result)
self.assert_not_enrolled()
def test_detail_post_no_json(self):
resp = self.client.post(
......@@ -176,6 +185,7 @@ class UsersTestCase(CourseTestCase):
groups = [g.name for g in ext_user.groups.all()]
self.assertIn(self.staff_groupname, groups)
self.assertNotIn(self.inst_groupname, groups)
self.assert_enrolled()
def test_detail_delete_staff(self):
group, _ = Group.objects.get_or_create(name=self.staff_groupname)
......@@ -317,3 +327,57 @@ class UsersTestCase(CourseTestCase):
ext_user = User.objects.get(email=self.ext_user.email)
groups = [g.name for g in ext_user.groups.all()]
self.assertIn(self.staff_groupname, groups)
def test_user_not_initially_enrolled(self):
# Verify that ext_user is not enrolled in the new course before being added as a staff member.
self.assert_not_enrolled()
def test_remove_staff_does_not_enroll(self):
# Add user with staff permissions.
self.client.post(
self.detail_url,
data=json.dumps({"role": "staff"}),
content_type="application/json",
HTTP_ACCEPT="application/json",
)
self.assert_enrolled()
# Remove user from staff on course. Will not un-enroll them from the course.
resp = self.client.delete(
self.detail_url,
HTTP_ACCEPT="application/json",
)
self.assert2XX(resp.status_code)
self.assert_enrolled()
def test_staff_to_instructor_still_enrolled(self):
# Add user with staff permission.
self.client.post(
self.detail_url,
data=json.dumps({"role": "staff"}),
content_type="application/json",
HTTP_ACCEPT="application/json",
)
self.assert_enrolled()
# Now add with instructor permission. Verify still enrolled.
resp = self.client.post(
self.detail_url,
data=json.dumps({"role": "instructor"}),
content_type="application/json",
HTTP_ACCEPT="application/json",
)
self.assert2XX(resp.status_code)
self.assert_enrolled()
def assert_not_enrolled(self):
""" Asserts that self.ext_user is not enrolled in self.course. """
self.assertEqual(
0, get_enrollment_count(self.ext_user, self.course.location.course_id),
'Did not expect ext_user to be enrolled in course'
)
def assert_enrolled(self):
""" Asserts that self.ext_user is enrolled in self.course. """
self.assertEqual(
1, get_enrollment_count(self.ext_user, self.course.location.course_id),
'User ext_user should have been enrolled in the course'
)
......@@ -5,6 +5,7 @@ Utilities for contentstore tests
import json
from student.models import Registration
from student.models import CourseEnrollment
from django.contrib.auth.models import User
from django.test.client import Client
......@@ -27,6 +28,15 @@ def registration(email):
return Registration.objects.get(user__email=email)
def get_enrollment_count(user, course_id):
"""
Gets the number of enrolled registrants for given course and user=self.user.
This should always be 0 or 1.
"""
return CourseEnrollment.objects.filter(user=user, course_id=course_id).count()
class CourseTestCase(ModuleStoreTestCase):
def setUp(self):
"""
......
......@@ -44,6 +44,8 @@ from .component import (
from django_comment_common.utils import seed_permissions_roles
from student.models import CourseEnrollment
from xmodule.html_module import AboutDescriptor
__all__ = ['course_index', 'create_new_course', 'course_info',
'course_info_updates', 'get_course_settings',
......@@ -162,6 +164,9 @@ def create_new_course(request):
# seed the forums
seed_permissions_roles(new_course.location.course_id)
# auto-enroll the course creator in the course so that "View Live" will work.
CourseEnrollment.objects.get_or_create(user=request.user, course_id=new_course.location.course_id)
return JsonResponse({'id': new_course.location.url()})
......
......@@ -23,6 +23,8 @@ from course_creators.views import (
from .access import has_access
from student.models import CourseEnrollment
@login_required
@ensure_csrf_cookie
......@@ -201,6 +203,8 @@ def course_team_user(request, org, course, name, email):
return JsonResponse(msg, 400)
user.groups.add(groups["instructor"])
user.save()
# auto-enroll the course creator in the course so that "View Live" will work.
CourseEnrollment.objects.get_or_create(user=user, course_id=location.course_id)
elif role == "staff":
# if we're trying to downgrade a user from "instructor" to "staff",
# make sure we have at least one other instructor in the course team.
......@@ -214,6 +218,9 @@ def course_team_user(request, org, course, name, email):
user.groups.remove(groups["instructor"])
user.groups.add(groups["staff"])
user.save()
# auto-enroll the course creator in the course so that "View Live" will work.
CourseEnrollment.objects.get_or_create(user=user, course_id=location.course_id)
return JsonResponse()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment