Newer
Older
from django.core.urlresolvers import reverse
Calen Pennington
committed
from django.contrib.auth.decorators import login_required
Piotr Mitros
committed
from mitxmako.shortcuts import render_to_response, render_to_string
#from django.views.decorators.csrf import ensure_csrf_cookie
from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.cache import cache_control
Piotr Mitros
committed
from module_render import toc_for_course, get_module, get_section
Calen Pennington
committed
from models import StudentModuleCache
from student.models import UserProfile
from multicourse import multicourse_settings
from util.cache import cache, cache_if_anonymous
from student.models import UserTestGroup, CourseEnrollment
Bridger Maxwell
committed
from courseware.courses import check_course
Bridger Maxwell
committed
from xmodule.modulestore.django import modulestore
log = logging.getLogger("mitx.courseware")
Calen Pennington
committed
template_imports = {'urllib': urllib}
def user_groups(user):
if not user.is_authenticated():
return []
# TODO: Rewrite in Django
key = 'user_group_names_{user.id}'.format(user=user)
cache_expiration = 60 * 60 # one hour
# Kill caching on dev machines -- we switch groups a lot
group_names = cache.get(key)
if group_names is None:
group_names = [u.name for u in UserTestGroup.objects.filter(users=user)]
cache.set(key, group_names, cache_expiration)
return group_names
def format_url_params(params):
return [urllib.quote(string.replace(' ', '_')) for string in params]
Piotr Mitros
committed
# TODO: Clean up how 'error' is done.
courses = modulestore().get_courses()
universities = dict()
for university, group in itertools.groupby(courses, lambda course: course.org):
universities.setdefault(university, [])
[universities[university].append(course) for course in group]
return render_to_response("courses.html", { 'universities': universities })
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
Bridger Maxwell
committed
def gradebook(request, course_id):
if 'course_admin' not in user_groups(request.user):
Bridger Maxwell
committed
course = check_course(course_id)
Bridger Maxwell
committed
Bridger Maxwell
committed
student_module_cache = StudentModuleCache(student, course)
course, _, _, _ = get_module(request.user, request, course.location, student_module_cache)
student_info.append({
'username': student.username,
'id': student.id,
'email': student.email,
'grade_info': grades.grade_sheet(student, course, student_module_cache),
'realname': UserProfile.objects.get(user=student).name
return render_to_response('gradebook.html', {'students': student_info, 'course': course})
Calen Pennington
committed
Calen Pennington
committed
@login_required
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
Bridger Maxwell
committed
def profile(request, course_id, student_id=None):
''' User profile. Show username, location, etc, as well as grades .
We need to allow the user to change some of these settings .'''
Bridger Maxwell
committed
course = check_course(course_id)
student = request.user
if 'course_admin' not in user_groups(request.user):
raise Http404
Calen Pennington
committed
student = User.objects.get(id=int(student_id))
Calen Pennington
committed
user_info = UserProfile.objects.get(user=student)
Bridger Maxwell
committed
student_module_cache = StudentModuleCache(request.user, course)
course, _, _, _ = get_module(request.user, request, course.location, student_module_cache)
context = {'name': user_info.name,
'username': student.username,
'location': user_info.location,
'language': user_info.language,
'email': student.email,
'format_url_params': format_url_params,
'csrf': csrf(request)['csrf_token']
}
Calen Pennington
committed
context.update(grades.grade_sheet(student, course, student_module_cache))
def render_accordion(request, course, chapter, section):
''' Draws navigation bar. Takes current position in accordion as
parameter.
If chapter and section are '' or None, renders a default accordion.
Returns (initialization_javascript, content)'''
# TODO (cpennington): do the right thing with courses
toc = toc_for_course(request.user, request, course, chapter, section)
active_chapter = 1
active_chapter = i
Calen Pennington
committed
context = dict([('active_chapter', active_chapter),
('toc', toc),
('course_name', course.title),
('course_id', course.id),
Calen Pennington
committed
('csrf', csrf(request)['csrf_token'])] + template_imports.items())
return render_to_string('accordion.html', context)
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
Bridger Maxwell
committed
def index(request, course_id, chapter=None, section=None,
position=None):
''' Displays courseware accordion, and any associated content.
If course, chapter, and section aren't all specified, just returns
the accordion. If they are specified, returns an error if they don't
point to a valid module.
Arguments:
- request : HTTP request
- course : coursename (str)
- chapter : chapter name (str)
- section : section name (str)
- position : position in module, eg of <sequential> module (str)
Returns:
- HTTPresponse
'''
Bridger Maxwell
committed
course = check_course(course_id)
def clean(s):
''' Fixes URLs -- we convert spaces to _ in URLs to prevent
funny encoding characters and keep the URLs readable. This undoes
that transformation.
'''
return s.replace('_', ' ') if s is not None else None
chapter = clean(chapter)
section = clean(section)
if settings.ENABLE_MULTICOURSE:
settings.MODULESTORE['default']['OPTIONS']['data_dir'] = settings.DATA_DIR + multicourse_settings.get_course_xmlpath(course)
Calen Pennington
committed
context = {
'csrf': csrf(request)['csrf_token'],
'accordion': render_accordion(request, course, chapter, section),
'COURSE_TITLE': course.title,
'course': course,
'init': '',
'content': ''
Calen Pennington
committed
}
look_for_module = chapter is not None and section is not None
if look_for_module:
# TODO (cpennington): Pass the right course in here
section = get_section(course, chapter, section)
Calen Pennington
committed
student_module_cache = StudentModuleCache(request.user, section)
Calen Pennington
committed
module, _, _, _ = get_module(request.user, request, section.location, student_module_cache)
Calen Pennington
committed
context['content'] = module.get_html()
Piotr Mitros
committed
Piotr Mitros
committed
result = render_to_response('courseware.html', context)
return result
Calen Pennington
committed
Calen Pennington
committed
def jump_to(request, probname=None):
'''
Jump to viewing a specific problem. The problem is specified by a
problem name - currently the filename (minus .xml) of the problem.
Maybe this should change to a more generic tag, eg "name" given as
an attribute in <problem>.
We do the jump by (1) reading course.xml to find the first
instance of <problem> with the given filename, then (2) finding
the parent element of the problem, then (3) rendering that parent
element with a specific computed position value (if it is
<sequential>).
'''
# get coursename if stored
coursename = multicourse_settings.get_coursename_from_request(request)
# begin by getting course.xml tree
xml = content_parser.course_file(request.user, coursename)
# look for problem of given name
pxml = xml.xpath('//problem[@filename="%s"]' % probname)
# get the parent element
parent = pxml.getparent()
# figure out chapter and section names
chapter = None
section = None
branch = parent
if branch.tag == 'section':
section = branch.get('name')
if branch.tag == 'chapter':
chapter = branch.get('name')
branch = branch.getparent()
position = None
if parent.tag == 'sequential':
position = parent.index(pxml) + 1 # position in sequence
return index(request,
course=coursename, chapter=chapter,
section=section, position=position)
Matthew Mongeau
committed
Matthew Mongeau
committed
@ensure_csrf_cookie
Bridger Maxwell
committed
def course_info(request, course_id):
course = check_course(course_id)
Matthew Mongeau
committed
Bridger Maxwell
committed
return render_to_response('info.html', {'course': course})
@ensure_csrf_cookie
def course_about(request, course_id):
def registered_for_course(course, user):
if user.is_authenticated():
return CourseEnrollment.objects.filter(user = user, course_id=course.id).exists()
else:
return False
course = check_course(course_id, course_must_be_open=False)
registered = registered_for_course(course, request.user)
return render_to_response('portal/course_about.html', {'course': course, 'registered': registered})
@login_required
@ensure_csrf_cookie
def enroll(request, course_id):
course = check_course(course_id, course_must_be_open=False)
user = request.user
enrollment, created = CourseEnrollment.objects.get_or_create(user=user, course_id=course.id)
return redirect(reverse('dashboard'))
def university_profile(request, org_id):
all_courses = modulestore().get_courses()
valid_org_ids = set(c.org for c in all_courses)
if org_id not in valid_org_ids:
raise Http404("University Profile not found for {0}".format(org_id))
# Only grab courses for this org...
courses=[c for c in all_courses if c.org == org_id]
context = dict(courses=courses, org_id=org_id)
template_file = "university_profile/{0}.html".format(org_id).lower()
return render_to_response(template_file, context)