|
|
|
|
@@ -11,7 +11,6 @@ import requests
|
|
|
|
|
from requests.status_codes import codes
|
|
|
|
|
import urllib
|
|
|
|
|
from collections import OrderedDict
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
from StringIO import StringIO
|
|
|
|
|
|
|
|
|
|
@@ -21,7 +20,6 @@ from django.http import HttpResponse
|
|
|
|
|
from django_future.csrf import ensure_csrf_cookie
|
|
|
|
|
from django.views.decorators.cache import cache_control
|
|
|
|
|
from mitxmako.shortcuts import render_to_response
|
|
|
|
|
import requests
|
|
|
|
|
from django.core.urlresolvers import reverse
|
|
|
|
|
|
|
|
|
|
from courseware import grades
|
|
|
|
|
@@ -36,11 +34,7 @@ from django_comment_client.models import (Role,
|
|
|
|
|
from django_comment_client.utils import has_forum_access
|
|
|
|
|
from psychometrics import psychoanalyze
|
|
|
|
|
from student.models import CourseEnrollment, CourseEnrollmentAllowed
|
|
|
|
|
from xmodule.course_module import CourseDescriptor
|
|
|
|
|
from xmodule.modulestore import Location
|
|
|
|
|
from xmodule.modulestore.django import modulestore
|
|
|
|
|
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
|
|
|
|
|
from xmodule.modulestore.search import path_to_location
|
|
|
|
|
import xmodule.graders as xmgraders
|
|
|
|
|
import track.views
|
|
|
|
|
|
|
|
|
|
@@ -48,14 +42,15 @@ from .offline_gradecalc import student_grades, offline_grades_available
|
|
|
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
template_imports = {'urllib': urllib}
|
|
|
|
|
|
|
|
|
|
# internal commands for managing forum roles:
|
|
|
|
|
FORUM_ROLE_ADD = 'add'
|
|
|
|
|
FORUM_ROLE_REMOVE = 'remove'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def split_by_comma_and_whitespace(s):
|
|
|
|
|
"""
|
|
|
|
|
Return string s, split by , or whitespace
|
|
|
|
|
"""
|
|
|
|
|
return re.split(r'[\s,]', s)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -141,7 +136,7 @@ def instructor_dashboard(request, course_id):
|
|
|
|
|
# '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)
|
|
|
|
|
(group, _) = Group.objects.get_or_create(name=name)
|
|
|
|
|
return group
|
|
|
|
|
|
|
|
|
|
# process actions from form POST
|
|
|
|
|
@@ -237,13 +232,13 @@ def instructor_dashboard(request, course_id):
|
|
|
|
|
if '/' not in problem_to_reset: # allow state of modules other than problem to be reset
|
|
|
|
|
problem_to_reset = "problem/" + problem_to_reset # but problem is the default
|
|
|
|
|
try:
|
|
|
|
|
(org, course_name, run) = course_id.split("/")
|
|
|
|
|
(org, course_name, _) = course_id.split("/")
|
|
|
|
|
module_state_key = "i4x://" + org + "/" + course_name + "/" + problem_to_reset
|
|
|
|
|
module_to_reset = StudentModule.objects.get(student_id=student_to_reset.id,
|
|
|
|
|
course_id=course_id,
|
|
|
|
|
module_state_key=module_state_key)
|
|
|
|
|
msg += "Found module to reset. "
|
|
|
|
|
except Exception as e:
|
|
|
|
|
except Exception:
|
|
|
|
|
msg += "<font color='red'>Couldn't find module with that urlname. </font>"
|
|
|
|
|
|
|
|
|
|
if "Delete student state for problem" in action:
|
|
|
|
|
@@ -352,7 +347,7 @@ def instructor_dashboard(request, course_id):
|
|
|
|
|
return_csv('', datatable, fp=fp)
|
|
|
|
|
fp.seek(0)
|
|
|
|
|
files = {'datafile': fp}
|
|
|
|
|
msg2, dataset = _do_remote_gradebook(request.user, course, 'post-grades', files=files)
|
|
|
|
|
msg2, _ = _do_remote_gradebook(request.user, course, 'post-grades', files=files)
|
|
|
|
|
msg += msg2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -423,7 +418,7 @@ def instructor_dashboard(request, course_id):
|
|
|
|
|
datatable = {'header': ['username', 'email'] + profkeys}
|
|
|
|
|
def getdat(u):
|
|
|
|
|
p = u.profile
|
|
|
|
|
return [u.username, u.email] + [getattr(p,x,'') for x in profkeys]
|
|
|
|
|
return [u.username, u.email] + [getattr(p, x, '') for x in profkeys]
|
|
|
|
|
|
|
|
|
|
datatable['data'] = [getdat(u) for u in enrolled_students]
|
|
|
|
|
datatable['title'] = 'Student profile data for course %s' % course_id
|
|
|
|
|
@@ -433,17 +428,17 @@ def instructor_dashboard(request, course_id):
|
|
|
|
|
elif 'Download CSV of all responses to problem' in action:
|
|
|
|
|
problem_to_dump = request.POST.get('problem_to_dump','')
|
|
|
|
|
|
|
|
|
|
if problem_to_dump[-4:]==".xml":
|
|
|
|
|
problem_to_dump=problem_to_dump[:-4]
|
|
|
|
|
if problem_to_dump[-4:] == ".xml":
|
|
|
|
|
problem_to_dump = problem_to_dump[:-4]
|
|
|
|
|
try:
|
|
|
|
|
(org, course_name, run)=course_id.split("/")
|
|
|
|
|
module_state_key="i4x://"+org+"/"+course_name+"/problem/"+problem_to_dump
|
|
|
|
|
(org, course_name, run) = course_id.split("/")
|
|
|
|
|
module_state_key = "i4x://" + org + "/" + course_name + "/problem/" + problem_to_dump
|
|
|
|
|
smdat = StudentModule.objects.filter(course_id=course_id,
|
|
|
|
|
module_state_key=module_state_key)
|
|
|
|
|
smdat = smdat.order_by('student')
|
|
|
|
|
msg += "Found %d records to dump " % len(smdat)
|
|
|
|
|
except Exception as err:
|
|
|
|
|
msg+="<font color='red'>Couldn't find module with that urlname. </font>"
|
|
|
|
|
msg += "<font color='red'>Couldn't find module with that urlname. </font>"
|
|
|
|
|
msg += "<pre>%s</pre>" % escape(err)
|
|
|
|
|
smdat = []
|
|
|
|
|
|
|
|
|
|
@@ -741,7 +736,7 @@ def _list_course_forum_members(course_id, rolename, datatable):
|
|
|
|
|
# make sure datatable is set up properly for display first, before checking for errors
|
|
|
|
|
datatable['header'] = ['Username', 'Full name', 'Roles']
|
|
|
|
|
datatable['title'] = 'List of Forum {0}s in course {1}'.format(rolename, course_id)
|
|
|
|
|
datatable['data'] = [];
|
|
|
|
|
datatable['data'] = []
|
|
|
|
|
try:
|
|
|
|
|
role = Role.objects.get(name=rolename, course_id=course_id)
|
|
|
|
|
except Role.DoesNotExist:
|
|
|
|
|
@@ -923,7 +918,7 @@ def get_student_grade_summary_data(request, course, course_id, get_grades=True,
|
|
|
|
|
datarow = [student.id, student.username, student.profile.name, student.email]
|
|
|
|
|
try:
|
|
|
|
|
datarow.append(student.externalauthmap.external_email)
|
|
|
|
|
except: # ExternalAuthMap.DoesNotExist
|
|
|
|
|
except: # ExternalAuthMap.DoesNotExist
|
|
|
|
|
datarow.append('')
|
|
|
|
|
|
|
|
|
|
if get_grades:
|
|
|
|
|
@@ -1040,7 +1035,8 @@ def _do_enroll_students(course, course_id, students, overload=False):
|
|
|
|
|
datatable['data'] = [[x, status[x]] for x in status]
|
|
|
|
|
datatable['title'] = 'Enrollment of students'
|
|
|
|
|
|
|
|
|
|
def sf(stat): return [x for x in status if status[x] == stat]
|
|
|
|
|
def sf(stat):
|
|
|
|
|
return [x for x in status if status[x] == stat]
|
|
|
|
|
|
|
|
|
|
data = dict(added=sf('added'), rejected=sf('rejected') + sf('exists'),
|
|
|
|
|
deleted=sf('deleted'), datatable=datatable)
|
|
|
|
|
@@ -1136,7 +1132,7 @@ def dump_grading_context(course):
|
|
|
|
|
'''
|
|
|
|
|
msg = "-----------------------------------------------------------------------------\n"
|
|
|
|
|
msg += "Course grader:\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg += '%s\n' % course.grader.__class__
|
|
|
|
|
graders = {}
|
|
|
|
|
if isinstance(course.grader, xmgraders.WeightedSubsectionsGrader):
|
|
|
|
|
@@ -1151,7 +1147,7 @@ def dump_grading_context(course):
|
|
|
|
|
|
|
|
|
|
gc = course.grading_context
|
|
|
|
|
msg += "graded sections:\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg += '%s\n' % gc['graded_sections'].keys()
|
|
|
|
|
for (gs, gsvals) in gc['graded_sections'].items():
|
|
|
|
|
msg += "--> Section %s:\n" % (gs)
|
|
|
|
|
|