Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ cms/envs/private.py
.idea/
.redcar/

### NFS artifacts
.nfs*

### OS X artifacts
*.DS_Store
.AppleDouble
Expand Down
10 changes: 9 additions & 1 deletion common/lib/xmodule/xmodule/capa_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .fields import Timedelta, Date
from django.utils.timezone import UTC
from django.utils.translation import ugettext as _
from .utils import get_extended_due_date

log = logging.getLogger("mitx.courseware")

Expand Down Expand Up @@ -95,6 +96,13 @@ class CapaFields(object):
values={"min": 0}, scope=Scope.settings
)
due = Date(help="Date that this problem is due by", scope=Scope.settings)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)
graceperiod = Timedelta(
help="Amount of time after the due date that submissions will be accepted",
scope=Scope.settings
Expand Down Expand Up @@ -186,7 +194,7 @@ def __init__(self, *args, **kwargs):
"""
XModule.__init__(self, *args, **kwargs)

due_date = self.due
due_date = get_extended_due_date(self)

if self.graceperiod is not None and due_date:
self.close_date = due_date + self.graceperiod
Expand Down
8 changes: 8 additions & 0 deletions common/lib/xmodule/xmodule/combined_open_ended_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"accept_file_upload",
"skip_spelling_checks",
"due",
"extended_due",
"graceperiod",
"weight",
"min_to_calibrate",
Expand Down Expand Up @@ -262,6 +263,13 @@ class CombinedOpenEndedFields(object):
help="Date that this problem is due by",
scope=Scope.settings
)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)
graceperiod = Timedelta(
help="Amount of time after the due date that submissions will be accepted",
scope=Scope.settings
Expand Down
10 changes: 9 additions & 1 deletion common/lib/xmodule/xmodule/foldit_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from xmodule.xml_module import XmlDescriptor
from xblock.fields import Scope, Integer, String
from .fields import Date
from .utils import get_extended_due_date


log = logging.getLogger(__name__)
Expand All @@ -20,6 +21,13 @@ class FolditFields(object):
required_level = Integer(default=4, scope=Scope.settings)
required_sublevel = Integer(default=5, scope=Scope.settings)
due = Date(help="Date that this problem is due by", scope=Scope.settings)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)

show_basic_score = String(scope=Scope.settings, default='false')
show_leaderboard = String(scope=Scope.settings, default='false')
Expand All @@ -40,7 +48,7 @@ def __init__(self, *args, **kwargs):
show_leaderboard="false"/>
"""
XModule.__init__(self, *args, **kwargs)
self.due_time = self.due
self.due_time = get_extended_due_date(self)

def is_complete(self):
"""
Expand Down
7 changes: 7 additions & 0 deletions common/lib/xmodule/xmodule/modulestore/inheritance.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ class InheritanceMixin(XBlockMixin):
scope=Scope.settings
)
due = Date(help="Date that this problem is due by", scope=Scope.settings)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)
giturl = String(help="url root for course data git repository", scope=Scope.settings)
xqa_key = String(help="DO NOT USE", scope=Scope.settings)
graceperiod = Timedelta(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ def __init__(self, system, location, definition, descriptor,
'peer_grade_finished_submissions_when_none_pending', False
)

due_date = instance_state.get('due', None)
due_date = instance_state.get('extended_due', None)
if due_date is None:
due_date = instance_state.get('due', None)

grace_period_string = instance_state.get('graceperiod', None)
try:
Expand Down
17 changes: 13 additions & 4 deletions common/lib/xmodule/xmodule/peer_grading_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
from pkg_resources import resource_string
from .capa_module import ComplexEncoder
from .x_module import XModule, module_attr
from xmodule.raw_module import RawDescriptor
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem
from .raw_module import RawDescriptor
from .modulestore.exceptions import ItemNotFoundError, NoPathToItem
from .timeinfo import TimeInfo
from .utils import get_extended_due_date
from xblock.fields import Dict, String, Scope, Boolean, Float
from xmodule.fields import Date, Timedelta

Expand Down Expand Up @@ -46,6 +47,13 @@ class PeerGradingFields(object):
due = Date(
help="Due date that should be displayed.",
scope=Scope.settings)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)
graceperiod = Timedelta(
help="Amount of grace to give on the due date.",
scope=Scope.settings
Expand Down Expand Up @@ -130,7 +138,8 @@ def __init__(self, *args, **kwargs):
raise

try:
self.timeinfo = TimeInfo(self.due, self.graceperiod)
self.timeinfo = TimeInfo(
get_extended_due_date(self), self.graceperiod)
except Exception:
log.error("Error parsing due date information in location {0}".format(self.location))
raise
Expand Down Expand Up @@ -552,7 +561,7 @@ def peer_grading(self, _data=None):
except (NoPathToItem, ItemNotFoundError):
continue
if descriptor:
problem['due'] = descriptor.due
problem['due'] = get_extended_due_date(descriptor)
grace_period = descriptor.graceperiod
try:
problem_timeinfo = TimeInfo(problem['due'], grace_period)
Expand Down
20 changes: 15 additions & 5 deletions common/lib/xmodule/xmodule/seq_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@

from lxml import etree

from xmodule.mako_module import MakoModuleDescriptor
from xmodule.xml_module import XmlDescriptor
from xmodule.x_module import XModule
from xmodule.progress import Progress
from xmodule.exceptions import NotFoundError
from xblock.fields import Integer, Scope
from xblock.fragment import Fragment
from pkg_resources import resource_string

from .exceptions import NotFoundError
from .fields import Date
from .mako_module import MakoModuleDescriptor
from .progress import Progress
from .x_module import XModule
from .xml_module import XmlDescriptor

log = logging.getLogger(__name__)

# HACK: This shouldn't be hard-coded to two types
Expand All @@ -25,6 +27,14 @@ class SequenceFields(object):
# NOTE: Position is 1-indexed. This is silly, but there are now student
# positions saved on prod, so it's not easy to fix.
position = Integer(help="Last tab viewed in this sequence", scope=Scope.user_state)
due = Date(help="Date that this problem is due by", scope=Scope.settings)
extended_due = Date(
help="Date that this problem is due by for a particular student. This "
"may differ from the global due date if an instructor has granted "
"an extension to the student.",
default=None,
scope=Scope.user_state,
)


class SequenceModule(SequenceFields, XModule):
Expand Down
37 changes: 10 additions & 27 deletions common/lib/xmodule/xmodule/tests/test_capa_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,10 @@ def answer_key():
"_2_1")

@staticmethod
def create(graceperiod=None,
due=None,
max_attempts=None,
showanswer=None,
rerandomize=None,
force_save_button=None,
attempts=None,
def create(attempts=None,
problem_state=None,
correct=False,
done=None,
text_customization=None
**kwargs
):
"""
All parameters are optional, and are added to the created problem if specified.
Expand All @@ -99,24 +92,7 @@ def create(graceperiod=None,
location = Location(["i4x", "edX", "capa_test", "problem",
"SampleProblem{0}".format(CapaFactory.next_num())])
field_data = {'data': CapaFactory.sample_problem_xml}

if graceperiod is not None:
field_data['graceperiod'] = graceperiod
if due is not None:
field_data['due'] = due
if max_attempts is not None:
field_data['max_attempts'] = max_attempts
if showanswer is not None:
field_data['showanswer'] = showanswer
if force_save_button is not None:
field_data['force_save_button'] = force_save_button
if rerandomize is not None:
field_data['rerandomize'] = rerandomize
if done is not None:
field_data['done'] = done
if text_customization is not None:
field_data['text_customization'] = text_customization

field_data.update(kwargs)
descriptor = Mock(weight="1")
if problem_state is not None:
field_data.update(problem_state)
Expand Down Expand Up @@ -328,6 +304,13 @@ def test_closed(self):
due=self.yesterday_str)
self.assertTrue(module.closed())

def test_due_date_extension(self):

module = CapaFactory.create(
max_attempts="1", attempts="0", due=self.yesterday_str,
extended_due=self.tomorrow_str)
self.assertFalse(module.closed())

def test_parse_get_params(self):

# We have to set up Django settings in order to use QueryDict
Expand Down
7 changes: 7 additions & 0 deletions common/lib/xmodule/xmodule/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@


def get_extended_due_date(node):
due_date = getattr(node, 'extended_due', None)
if not due_date:
due_date = getattr(node, 'due', None)
return due_date
2 changes: 2 additions & 0 deletions lms/djangoapps/courseware/grades.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from xmodule import graders
from xmodule.capa_module import CapaModule
from xmodule.graders import Score
from xmodule.utils import get_extended_due_date
from .models import StudentModule

log = logging.getLogger("mitx.courseware")
Expand Down Expand Up @@ -328,6 +329,7 @@ def progress_summary(student, request, course, field_data_cache):
'section_total': section_total,
'format': module_format,
'due': section_module.due,
'due': get_extended_due_date(section_module),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we have multiple definitions of 'due' here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

'graded': graded,
})

Expand Down
3 changes: 2 additions & 1 deletion lms/djangoapps/courseware/module_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.utils import get_extended_due_date
from xmodule.x_module import ModuleSystem
from xmodule_modifiers import replace_course_urls, replace_jump_to_id_urls, replace_static_urls, add_histogram, wrap_xblock

Expand Down Expand Up @@ -110,7 +111,7 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
sections.append({'display_name': section.display_name_with_default,
'url_name': section.url_name,
'format': section.format if section.format is not None else '',
'due': section.due,
'due': get_extended_due_date(section),
'active': active,
'graded': section.graded,
})
Expand Down
Loading