Commit 1a5fc065 by Victor Shnayder Committed by Victor Shnayder

Add beta test group management view to instructor dashboard

* still needs to support uploading a list
* also want to clean up and refactor the code a bit
parent 58a9fded
...@@ -329,7 +329,7 @@ def _course_staff_group_name(location): ...@@ -329,7 +329,7 @@ def _course_staff_group_name(location):
""" """
return 'staff_%s' % Location(location).course return 'staff_%s' % Location(location).course
def _course_beta_test_group_name(location): def course_beta_test_group_name(location):
""" """
Get the name of the beta tester group for a location. Right now, that's Get the name of the beta tester group for a location. Right now, that's
beta_testers_COURSE. beta_testers_COURSE.
...@@ -388,7 +388,7 @@ def _adjust_start_date_for_beta_testers(user, descriptor): ...@@ -388,7 +388,7 @@ def _adjust_start_date_for_beta_testers(user, descriptor):
user_groups = [g.name for g in user.groups.all()] user_groups = [g.name for g in user.groups.all()]
beta_group = _course_beta_test_group_name(descriptor.location) beta_group = course_beta_test_group_name(descriptor.location)
if beta_group in user_groups: if beta_group in user_groups:
debug("Adjust start time: user in group %s", beta_group) debug("Adjust start time: user in group %s", beta_group)
# time_structs don't support subtraction, so convert to datetimes, # time_structs don't support subtraction, so convert to datetimes,
......
...@@ -18,7 +18,7 @@ import xmodule.modulestore.django ...@@ -18,7 +18,7 @@ import xmodule.modulestore.django
# Need access to internal func to put users in the right group # Need access to internal func to put users in the right group
from courseware import grades from courseware import grades
from courseware.access import (has_access, _course_staff_group_name, from courseware.access import (has_access, _course_staff_group_name,
_course_beta_test_group_name) course_beta_test_group_name)
from courseware.models import StudentModuleCache from courseware.models import StudentModuleCache
from student.models import Registration from student.models import Registration
...@@ -645,7 +645,7 @@ class TestViewAuth(PageLoader): ...@@ -645,7 +645,7 @@ class TestViewAuth(PageLoader):
self.assertFalse(has_access(student_user, self.toy, 'load')) self.assertFalse(has_access(student_user, self.toy, 'load'))
# now add the student to the beta test group # now add the student to the beta test group
group_name = _course_beta_test_group_name(self.toy.location) group_name = course_beta_test_group_name(self.toy.location)
g = Group.objects.create(name=group_name) g = Group.objects.create(name=group_name)
g.user_set.add(student_user) g.user_set.add(student_user)
......
...@@ -179,7 +179,7 @@ class TestInstructorDashboardForumAdmin(ct.PageLoader): ...@@ -179,7 +179,7 @@ class TestInstructorDashboardForumAdmin(ct.PageLoader):
self.assertTrue(response.content.find('Removed "{0}" from "{1}" forum role = "{2}"'.format(username, course.id, rolename))>=0) self.assertTrue(response.content.find('Removed "{0}" from "{1}" forum role = "{2}"'.format(username, course.id, rolename))>=0)
self.assertFalse(has_forum_access(username, course.id, rolename)) self.assertFalse(has_forum_access(username, course.id, rolename))
def test_add_and_readd_forum_admin_users(self): def test_add_and_read_forum_admin_users(self):
course = self.toy course = self.toy
self.initialize_roles(course.id) self.initialize_roles(course.id)
url = reverse('instructor_dashboard', kwargs={'course_id': course.id}) url = reverse('instructor_dashboard', kwargs={'course_id': course.id})
......
...@@ -19,9 +19,13 @@ from mitxmako.shortcuts import render_to_response ...@@ -19,9 +19,13 @@ from mitxmako.shortcuts import render_to_response
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from courseware import grades from courseware import grades
from courseware.access import has_access, get_access_group_name from courseware.access import (has_access, get_access_group_name,
course_beta_test_group_name)
from courseware.courses import get_course_with_access from courseware.courses import get_course_with_access
from django_comment_client.models import Role, FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA from django_comment_client.models import (Role,
FORUM_ROLE_ADMINISTRATOR,
FORUM_ROLE_MODERATOR,
FORUM_ROLE_COMMUNITY_TA)
from django_comment_client.utils import has_forum_access from django_comment_client.utils import has_forum_access
from psychometrics import psychoanalyze from psychometrics import psychoanalyze
from student.models import CourseEnrollment, CourseEnrollmentAllowed from student.models import CourseEnrollment, CourseEnrollmentAllowed
...@@ -44,7 +48,6 @@ FORUM_ROLE_REMOVE = 'remove' ...@@ -44,7 +48,6 @@ FORUM_ROLE_REMOVE = 'remove'
@ensure_csrf_cookie @ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True) @cache_control(no_cache=True, no_store=True, must_revalidate=True)
def instructor_dashboard(request, course_id): def instructor_dashboard(request, course_id):
"""Display the instructor dashboard for a course.""" """Display the instructor dashboard for a course."""
course = get_course_with_access(request.user, course_id, 'staff') course = get_course_with_access(request.user, course_id, 'staff')
...@@ -105,6 +108,16 @@ def instructor_dashboard(request, course_id): ...@@ -105,6 +108,16 @@ def instructor_dashboard(request, course_id):
except Group.DoesNotExist: except Group.DoesNotExist:
group = Group(name=grpname) # create the group group = Group(name=grpname) # create the group
group.save() group.save()
def get_beta_group(course):
"""
Get the group for beta testers of course.
"""
# Not using get_group because there is no access control action called
# 'beta', so adding it to get_access_group_name doesn't really make
# sense.
name = course_beta_test_group_name(course.location)
(group, created) = Group.objects.get_or_create(name=name)
return group return group
# process actions from form POST # process actions from form POST
...@@ -311,6 +324,44 @@ def instructor_dashboard(request, course_id): ...@@ -311,6 +324,44 @@ def instructor_dashboard(request, course_id):
track.views.server_track(request, 'remove-instructor {0}'.format(user), {}, page='idashboard') track.views.server_track(request, 'remove-instructor {0}'.format(user), {}, page='idashboard')
#---------------------------------------- #----------------------------------------
# Group management
elif 'List beta testers' in action:
group = get_beta_group(course)
msg += 'Beta test group = {0}'.format(group.name)
datatable = _group_members_table(group, "List of beta_testers", course_id)
track.views.server_track(request, 'list-beta-testers', {}, page='idashboard')
elif action == 'Add beta testers':
uname = request.POST['betausers']
try:
user = User.objects.get(username=uname)
except User.DoesNotExist:
msg += '<font color="red">Error: unknown username "{0}"</font>'.format(uname)
user = None
if user is not None:
group = get_beta_group(course)
msg += '<font color="green">Added {0} to beta testers group = {1}</font>'.format(user, group.name)
log.debug('staffgrp={0}'.format(group.name))
user.groups.add(group)
track.views.server_track(request, 'add-beta-tester {0}'.format(user), {}, page='idashboard')
elif action == 'Remove beta testers':
uname = request.POST['betausers']
try:
user = User.objects.get(username=uname)
except User.DoesNotExist:
msg += '<font color="red">Error: unknown username "{0}"</font>'.format(uname)
user = None
if user is not None:
group = get_beta_group(course)
msg += '<font color="green">Removed {0} from beta tester group = {1}</font>'.format(user, group.name)
log.debug('staffgrp={0}'.format(group.name))
user.groups.remove(group)
track.views.server_track(request, 'remove-beta-tester {0}'.format(user), {}, page='idashboard')
#----------------------------------------
# forum administration # forum administration
elif action == 'List course forum admins': elif action == 'List course forum admins':
...@@ -522,7 +573,7 @@ def _do_remote_gradebook(user, course, action, args=None, files=None): ...@@ -522,7 +573,7 @@ def _do_remote_gradebook(user, course, action, args=None, files=None):
return msg, datatable return msg, datatable
def _list_course_forum_members(course_id, rolename, datatable): def _list_course_forum_members(course_id, rolename, datatable):
''' """
Fills in datatable with forum membership information, for a given role, Fills in datatable with forum membership information, for a given role,
so that it will be displayed on instructor dashboard. so that it will be displayed on instructor dashboard.
...@@ -530,7 +581,7 @@ def _list_course_forum_members(course_id, rolename, datatable): ...@@ -530,7 +581,7 @@ def _list_course_forum_members(course_id, rolename, datatable):
rolename = one of "Administrator", "Moderator", "Community TA" rolename = one of "Administrator", "Moderator", "Community TA"
Returns message status string to append to displayed message, if role is unknown. Returns message status string to append to displayed message, if role is unknown.
''' """
# make sure datatable is set up properly for display first, before checking for errors # make sure datatable is set up properly for display first, before checking for errors
datatable['header'] = ['Username', 'Full name', 'Roles'] datatable['header'] = ['Username', 'Full name', 'Roles']
datatable['title'] = 'List of Forum {0}s in course {1}'.format(rolename, course_id) datatable['title'] = 'List of Forum {0}s in course {1}'.format(rolename, course_id)
...@@ -590,6 +641,27 @@ def _update_forum_role_membership(uname, course, rolename, add_or_remove): ...@@ -590,6 +641,27 @@ def _update_forum_role_membership(uname, course, rolename, add_or_remove):
return msg return msg
def _group_members_table(group, title, course_id):
"""
Return a data table of usernames and names of users in group_name.
Arguments:
group -- a django group.
title -- a descriptive title to show the user
Returns:
a dictionary with keys
'header': ['Username', 'Full name'],
'data': [[username, name] for all users]
'title': "{title} in course {course}"
"""
uset = group.user_set.all()
datatable = {'header': ['Username', 'Full name']}
datatable['data'] = [[x.username, x.profile.name] for x in uset]
datatable['title'] = '{0} in course {1}'.format(title, course_id)
return datatable
def get_student_grade_summary_data(request, course, course_id, get_grades=True, get_raw_scores=False, use_offline=False): def get_student_grade_summary_data(request, course, course_id, get_grades=True, get_raw_scores=False, use_offline=False):
''' '''
......
...@@ -59,7 +59,7 @@ function goto( mode) ...@@ -59,7 +59,7 @@ function goto( mode)
<a href="#" onclick="goto('Admin');" class="${modeflag.get('Admin')}">Admin</a> | <a href="#" onclick="goto('Admin');" class="${modeflag.get('Admin')}">Admin</a> |
<a href="#" onclick="goto('Forum Admin');" class="${modeflag.get('Forum Admin')}">Forum Admin</a> | <a href="#" onclick="goto('Forum Admin');" class="${modeflag.get('Forum Admin')}">Forum Admin</a> |
<a href="#" onclick="goto('Enrollment');" class="${modeflag.get('Enrollment')}">Enrollment</a> <a href="#" onclick="goto('Enrollment');" class="${modeflag.get('Enrollment')}">Enrollment</a>
] <a href="#" onclick="goto('Manage Groups');" class="${modeflag.get('Manage Groups')}">Manage Groups</a> ]
</h2> </h2>
<div style="text-align:right"><span id="djangopid">${djangopid}</span> <div style="text-align:right"><span id="djangopid">${djangopid}</span>
...@@ -168,7 +168,8 @@ function goto( mode) ...@@ -168,7 +168,8 @@ function goto( mode)
<p> <p>
<input type="submit" name="action" value="List course staff members"> <input type="submit" name="action" value="List course staff members">
<p> <p>
<input type="text" name="staffuser"> <input type="submit" name="action" value="Remove course staff"> <input type="text" name="staffuser">
<input type="submit" name="action" value="Remove course staff">
<input type="submit" name="action" value="Add course staff"> <input type="submit" name="action" value="Add course staff">
<hr width="40%" style="align:left"> <hr width="40%" style="align:left">
%endif %endif
...@@ -258,6 +259,21 @@ function goto( mode) ...@@ -258,6 +259,21 @@ function goto( mode)
##----------------------------------------------------------------------------- ##-----------------------------------------------------------------------------
%if modeflag.get('Manage Groups'):
%if instructor_access:
<hr width="40%" style="align:left">
<p>
<input type="submit" name="action" value="List beta testers">
<p>
Enter usernames or emails for students who should be beta-testers. They will get to see course materials early, as configured via the <tt>days_early_for_beta</tt> option in the course policy.
</p>
<input type="textarea" name="betausers">
<input type="submit" name="action" value="Add beta testers">
<input type="submit" name="action" value="Remove beta testers">
<hr width="40%" style="align:left">
%endif
%endif
</form> </form>
##----------------------------------------------------------------------------- ##-----------------------------------------------------------------------------
......
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