From 8d7c4ad8ded01bae8277c08a7a319b4bb4a67de0 Mon Sep 17 00:00:00 2001 From: Bridger Maxwell Date: Thu, 12 Jul 2012 16:27:20 -0400 Subject: [PATCH] Added a start date to courses. Created a decorator to retrieve the course and check that it is open. --- common/lib/xmodule/xmodule/course_module.py | 13 ++++++- common/lib/xmodule/xmodule/x_module.py | 3 +- common/lib/xmodule/xmodule/xml_module.py | 2 +- lms/djangoapps/courseware/views.py | 42 +++++++++++++-------- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 8435cfca9e..08a9553763 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -1,3 +1,5 @@ +from datetime import datetime +import dateutil.parser from fs.errors import ResourceNotFoundError import logging from path import path @@ -13,6 +15,14 @@ log = logging.getLogger(__name__) class CourseDescriptor(SequenceDescriptor): module_class = SequenceModule + def __init__(self, system, definition=None, **kwargs): + super(CourseDescriptor, self).__init__(system, definition, **kwargs) + + self.start = dateutil.parser.parse(self.metadata["start"]) + + def has_started(self): + return datetime.now() > self.start + @classmethod def id_to_location(cls, course_id): org, course, name = course_id.split('/') @@ -24,7 +34,7 @@ class CourseDescriptor(SequenceDescriptor): @property def title(self): - self.metadata['display_name'] + return self.metadata['display_name'] @property def instructors(self): @@ -69,6 +79,7 @@ class CourseDescriptor(SequenceDescriptor): elif section_key == "title": return self.metadata.get('display_name', self.name) elif section_key == "university": + return self.metadata.get('start') return self.location.org elif section_key == "number": return self.number diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index ed678fdd0e..e1ad27beea 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -214,7 +214,7 @@ class XModuleDescriptor(Plugin): # A list of metadata that this module can inherit from its parent module inheritable_metadata = ( - 'graded', 'due', 'graceperiod', 'showanswer', 'rerandomize', + 'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize', # This is used by the XMLModuleStore to provide for locations for static files, # and will need to be removed when that code is removed @@ -251,6 +251,7 @@ class XModuleDescriptor(Plugin): display_name: The name to use for displaying this module to the user format: The format of this module ('Homework', 'Lab', etc) graded (bool): Whether this module is should be graded or not + start (string): The date for which this module will be available due (string): The due date for this module graceperiod (string): The amount of grace period to allow when enforcing the due date showanswer (string): When to show answers for this module diff --git a/common/lib/xmodule/xmodule/xml_module.py b/common/lib/xmodule/xmodule/xml_module.py index b0bfaebab5..de6447ada6 100644 --- a/common/lib/xmodule/xmodule/xml_module.py +++ b/common/lib/xmodule/xmodule/xml_module.py @@ -88,7 +88,7 @@ class XmlDescriptor(XModuleDescriptor): # The attributes will be removed from the definition xml passed # to definition_from_xml, and from the xml returned by definition_to_xml metadata_attributes = ('format', 'graceperiod', 'showanswer', 'rerandomize', - 'due', 'graded', 'name', 'slug') + 'start', 'due', 'graded', 'name', 'slug') # A dictionary mapping xml attribute names to functions of the value # that return the metadata key and value diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index c011ac7be6..d2516a7361 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -27,6 +27,25 @@ log = logging.getLogger("mitx.courseware") template_imports = {'urllib': urllib} +def check_course(function, course_must_be_open=True): + def inner_function(*args, **kwargs): + course_id = kwargs['course_id'] + + try: + course_loc = CourseDescriptor.id_to_location(course_id) + course = modulestore().get_item(course_loc) + except KeyError: + raise Http404("Course not found.") + + if course_must_be_open and not course.has_started(): + raise Http404 + + del kwargs['course_id'] + kwargs['course'] = course + + return function(*args, **kwargs) + return inner_function + def user_groups(user): if not user.is_authenticated(): @@ -84,12 +103,12 @@ def gradebook(request, course_id): @login_required +@check_course @cache_control(no_cache=True, no_store=True, must_revalidate=True) -def profile(request, course_id, student_id=None): +def profile(request, course, 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 .''' - course_location = CourseDescriptor.id_to_location(course_id) if student_id is None: student = request.user else: @@ -99,8 +118,8 @@ def profile(request, course_id, student_id=None): user_info = UserProfile.objects.get(user=student) - student_module_cache = StudentModuleCache(request.user, modulestore().get_item(course_location)) - course, _, _, _ = get_module(request.user, request, course_location, student_module_cache) + 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, @@ -142,8 +161,9 @@ def render_accordion(request, course, chapter, section): @ensure_csrf_cookie +@check_course @cache_control(no_cache=True, no_store=True, must_revalidate=True) -def index(request, course_id=None, chapter=None, section=None, +def index(request, course, chapter=None, section=None, position=None): ''' Displays courseware accordion, and any associated content. If course, chapter, and section aren't all specified, just returns @@ -169,9 +189,6 @@ def index(request, course_id=None, chapter=None, section=None, ''' return s.replace('_', ' ') if s is not None else None - course_location = CourseDescriptor.id_to_location(course_id) - course = modulestore().get_item(course_location) - chapter = clean(chapter) section = clean(section) @@ -249,13 +266,8 @@ def jump_to(request, probname=None): @ensure_csrf_cookie -def course_info(request, course_id): +@check_course +def course_info(request, course): csrf_token = csrf(request)['csrf_token'] - try: - course_location = CourseDescriptor.id_to_location(course_id) - course = modulestore().get_item(course_location) - except KeyError: - raise Http404("Course not found") - return render_to_response('info.html', {'csrf': csrf_token, 'course': course})