Commit 0a657bef by Miles Steele

add forum list management

parent bc9cce57
......@@ -11,6 +11,10 @@ TODO sync instructor and staff flags
from django.contrib.auth.models import User, Group
from courseware.access import get_access_group_name
from django_comment_common.models import (Role,
FORUM_ROLE_ADMINISTRATOR,
FORUM_ROLE_MODERATOR,
FORUM_ROLE_COMMUNITY_TA)
def list_with_level(course, level):
......@@ -55,3 +59,23 @@ def _change_access(course, user, level, mode):
user.groups.remove(group)
else:
raise ValueError("unrecognized mode '{}'".format(mode))
def update_forum_role_membership(course_id, user, rolename, mode):
"""
Change forum access of user.
rolename is one of [FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA]
mode is one of ['alow', 'revoke']
"""
role = Role.objects.get(course_id=course_id, name=rolename)
if mode == 'allow':
role.users.add(user)
elif mode == 'revoke':
role.users.remove(user)
print "\n" * 5
print role.users.all()
else:
raise ValueError("unrecognized mode '{}'".format(mode))
......@@ -15,11 +15,15 @@ from django.http import HttpResponse, HttpResponseBadRequest
from courseware.courses import get_course_with_access
from django.contrib.auth.models import User, Group
from django_comment_common.models import (Role,
FORUM_ROLE_ADMINISTRATOR,
FORUM_ROLE_MODERATOR,
FORUM_ROLE_COMMUNITY_TA)
from courseware.models import StudentModule
import instructor.enrollment as enrollment
from instructor.enrollment import split_input_list, enroll_emails, unenroll_emails
from instructor.access import allow_access, revoke_access, list_with_level
import instructor.access as access
import analytics.basic
import analytics.distributions
import analytics.csvs
......@@ -57,21 +61,21 @@ def access_allow_revoke(request, course_id):
Query parameters:
email is the target users email
level is one of ['instructor', 'staff']
rolename is one of ['instructor', 'staff']
mode is one of ['allow', 'revoke']
"""
course = get_course_with_access(request.user, course_id, 'instructor', depth=None)
email = request.GET.get('email')
level = request.GET.get('level')
rolename = request.GET.get('rolename')
mode = request.GET.get('mode')
user = User.objects.get(email=email)
if mode == 'allow':
allow_access(course, user, level)
access.allow_access(course, user, rolename)
elif mode == 'revoke':
revoke_access(course, user, level)
access.revoke_access(course, user, rolename)
else:
raise ValueError("unrecognized mode '{}'".format(mode))
......@@ -88,10 +92,17 @@ def list_instructors_staff(request, course_id):
"""
List instructors and staff.
Requires staff access.
rolename is one of ['instructor', 'staff']
"""
course = get_course_with_access(request.user, course_id, 'staff', depth=None)
def extract_user(user):
rolename = request.GET.get('rolename', '')
if not rolename in ['instructor', 'staff']:
return HttpResponseBadRequest()
def extract_user_info(user):
return {
'username': user.username,
'email': user.email,
......@@ -101,8 +112,7 @@ def list_instructors_staff(request, course_id):
response_payload = {
'course_id': course_id,
'instructor': map(extract_user, list_with_level(course, 'instructor')),
'staff': map(extract_user, list_with_level(course, 'staff')),
rolename: map(extract_user_info, access.list_with_level(course, rolename)),
}
response = HttpResponse(json.dumps(response_payload), content_type="application/json")
return response
......@@ -301,3 +311,76 @@ def reset_student_attempts(request, course_id):
}
response = HttpResponse(json.dumps(response_payload), content_type="application/json")
return response
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def list_forum_members(request, course_id):
"""
Resets a students attempts counter. Optionally deletes student state for a problem.
Limited to staff access.
Takes query parameter rolename
"""
course = get_course_with_access(request.user, course_id, 'staff', depth=None)
rolename = request.GET.get('rolename', '')
if not rolename in [FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA]:
return HttpResponseBadRequest()
try:
role = Role.objects.get(name=rolename, course_id=course_id)
users = role.users.all().order_by('username')
except Role.DoesNotExist:
users = []
def extract_user_info(user):
return {
'username': user.username,
'email': user.email,
'first_name': user.first_name,
'last_name': user.last_name,
}
response_payload = {
'course_id': course_id,
rolename: map(extract_user_info, users),
}
response = HttpResponse(json.dumps(response_payload), content_type="application/json")
return response
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
def update_forum_role_membership(request, course_id):
"""
Modify forum role access.
Query parameters:
email is the target users email
rolename is one of [FORUM_ROLE_ADMINISTRATOR, FORUM_ROLE_MODERATOR, FORUM_ROLE_COMMUNITY_TA]
mode is one of ['allow', 'revoke']
"""
course = get_course_with_access(request.user, course_id, 'instructor', depth=None)
email = request.GET.get('email', '')
rolename = request.GET.get('rolename', '')
mode = request.GET.get('mode', '')
if not rolename in [access.FORUM_ROLE_ADMINISTRATOR, access.FORUM_ROLE_MODERATOR, access.FORUM_ROLE_COMMUNITY_TA]:
return HttpResponseBadRequest()
try:
user = User.objects.get(email=email)
access.update_forum_role_membership(course_id, user, rolename, mode)
except User.DoesNotExist, Role.DoesNotExist:
return HttpResponseBadRequest()
response_payload = {
'course_id': course_id,
'mode': mode,
'DONE': 'YES',
}
response = HttpResponse(json.dumps(response_payload), content_type="application/json")
return response
......@@ -109,6 +109,8 @@ def _section_membership(course_id):
'unenroll_button_url': reverse('enroll_unenroll', kwargs={'course_id': course_id}),
'list_instructors_staff_url': reverse('list_instructors_staff', kwargs={'course_id': course_id}),
'access_allow_revoke_url': reverse('access_allow_revoke', kwargs={'course_id': course_id}),
'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_id}),
'update_forum_role_membership_url': reverse('update_forum_role_membership', kwargs={'course_id': course_id}),
}
return section_data
......
......@@ -94,26 +94,26 @@ class BatchEnrollment
# manages a list of instructors or staff and the control of their access.
class AuthorityList
# level is in ['instructor', 'staff']
constructor: (@$container, @level) ->
log 'setting up instructor dashboard subsection - authlist management for #{@level}'
class AuthList
# rolename is in ['instructor', 'staff'] for instructor_staff endpoints
# rolename is the name of Role for forums for the forum endpoints
constructor: (@$container, @rolename) ->
log "setting up instructor dashboard subsection - authlist management for #{@rolename}"
@$display_table = @$container.find('.auth-list-table')
$add_section = @$container.find('.auth-list-add')
$allow_field = $add_section.find("input[name='email']")
$allow_button = $add_section.find("input[name='allow']")
@list_endpoint = @$display_table.data 'endpoint'
@access_change_endpoint = $add_section.data 'endpoint'
@$add_section = @$container.find('.auth-list-add')
$allow_field = @$add_section.find("input[name='email']")
$allow_button = @$add_section.find("input[name='allow']")
$allow_button.click =>
@access_change($allow_field.val(), @level, 'allow', @reload_auth_list)
@access_change($allow_field.val(), @rolename, 'allow', @reload_auth_list)
$allow_field.val ''
@reload_auth_list()
reload_auth_list: =>
$.getJSON @list_endpoint, (data) =>
list_endpoint = @$display_table.data 'endpoint'
$.getJSON list_endpoint, {rolename: @rolename}, (data) =>
log data
@$display_table.empty()
......@@ -138,7 +138,7 @@ class AuthorityList
"<span class='revoke-link'>Revoke Access</span>"
]
table_data = data[@level]
table_data = data[@rolename]
log 'table_data', table_data
$table_placeholder = $ '<div/>', class: 'slickgrid'
......@@ -150,11 +150,11 @@ class AuthorityList
grid.onClick.subscribe (e, args) =>
item = args.grid.getDataItem(args.row)
if args.cell is 2
@access_change(item.email, @level, 'revoke', @reload_auth_list)
@access_change(item.email, @rolename, 'revoke', @reload_auth_list)
access_change: (email, level, mode, cb) ->
url = @access_change_endpoint
$.getJSON @access_change_endpoint, {email: email, level: @level, mode: mode}, (data) ->
access_change: (email, rolename, mode, cb) ->
access_change_endpoint = @$add_section.data 'endpoint'
$.getJSON access_change_endpoint, {email: email, rolename: @rolename, mode: mode}, (data) ->
log data
cb?()
......@@ -166,15 +166,31 @@ class Membership
# isolate sections from each other's errors.
plantTimeout 0, => @batchenrollment = new BatchEnrollment @$section.find '.batch-enrollment'
plantTimeout 0, => @stafflist = new AuthorityList (@$section.find '.auth-list-container.auth-list-staff'), 'staff'
plantTimeout 0, => @instructorlist = new AuthorityList (@$section.find '.auth-list-container.auth-list-instructor'), 'instructor'
plantTimeout 0, => @stafflist = new AuthList (@$section.find '.auth-list-container.auth-list-staff'), 'staff'
plantTimeout 0, => @instructorlist = new AuthList (@$section.find '.auth-list-container.auth-list-instructor'), 'instructor'
# TODO names like 'Administrator' should come from server through template.
plantTimeout 0, => @forum_admin_list = new AuthList (@$section.find '.auth-list-container.auth-list-forum-admin'), 'Administrator'
plantTimeout 0, => @forum_mod_list = new AuthList (@$section.find '.auth-list-container.auth-list-forum-moderator'), 'Moderator'
plantTimeout 0, => @forum_comta_list = new AuthList (@$section.find '.auth-list-container.auth-list-forum-community-ta'), 'Community TA'
onClickTitle: ->
@stafflist.$display_table.empty()
@stafflist.reload_auth_list()
@instructorlist.$display_table.empty()
@instructorlist.reload_auth_list()
@forum_admin_list.$display_table.empty()
@forum_admin_list.reload_auth_list()
@forum_mod_list.$display_table.empty()
@forum_mod_list.reload_auth_list()
@forum_comta_list.$display_table.empty()
@forum_comta_list.reload_auth_list()
# exports
_.defaults window, InstructorDashboard: {}
......
......@@ -92,6 +92,7 @@
.vert-right {
float: right;
width: 45%;
}
.auth-list-container {
margin-bottom: 1.5em;
......@@ -107,8 +108,6 @@
}
}
}
.batch-enrollment {
textarea {
height: 100px;
......
......@@ -8,6 +8,33 @@
<input type="button" name="enroll" value="Enroll" data-endpoint="${ section_data['enroll_button_url'] }" >
<input type="button" name="unenroll" value="Unenroll" data-endpoint="${ section_data['unenroll_button_url'] }" >
<div class="task-response"></div>
<div class="auth-list-container auth-list-forum-admin">
<h2>Instructor Management</h2>
<div class="auth-list-table" data-endpoint="${ section_data['list_forum_members_url'] }"></div>
<div class="auth-list-add" data-endpoint="${ section_data['update_forum_role_membership_url'] }">
<input type="text" name="email" placeholder="Enter Email" spellcheck="false">
<input type="button" name="allow" value="Grant Forum Admin">
</div>
</div>
<div class="auth-list-container auth-list-forum-moderator">
<h2>Instructor Management</h2>
<div class="auth-list-table" data-endpoint="${ section_data['list_forum_members_url'] }"></div>
<div class="auth-list-add" data-endpoint="${ section_data['update_forum_role_membership_url'] }">
<input type="text" name="email" placeholder="Enter Email" spellcheck="false">
<input type="button" name="allow" value="Grant Forum Moderator">
</div>
</div>
<div class="auth-list-container auth-list-forum-community-ta">
<h2>Instructor Management</h2>
<div class="auth-list-table" data-endpoint="${ section_data['list_forum_members_url'] }"></div>
<div class="auth-list-add" data-endpoint="${ section_data['update_forum_role_membership_url'] }">
<input type="text" name="email" placeholder="Enter Email" spellcheck="false">
<input type="button" name="allow" value="Grant Community TA">
</div>
</div>
</div>
<div class="vert-right instructor-staff-management">
......
......@@ -271,6 +271,10 @@ if settings.COURSEWARE_ENABLED:
'instructor.views.api.get_student_progress_url', name="get_student_progress_url"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/instructor_dashboard/api/reset_student_attempts$',
'instructor.views.api.reset_student_attempts', name="reset_student_attempts"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/instructor_dashboard/api/list_forum_members$',
'instructor.views.api.list_forum_members', name="list_forum_members"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/instructor_dashboard/api/update_forum_role_membership$',
'instructor.views.api.update_forum_role_membership', name="update_forum_role_membership"),
url(r'^courses/(?P<course_id>[^/]+/[^/]+/[^/]+)/gradebook$',
'instructor.views.legacy.gradebook', name='gradebook'),
......
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