diff --git a/common/lib/xmodule/xmodule/annotatable_module.py b/common/lib/xmodule/xmodule/annotatable_module.py index 338a5fe067..36428d2acb 100644 --- a/common/lib/xmodule/xmodule/annotatable_module.py +++ b/common/lib/xmodule/xmodule/annotatable_module.py @@ -39,7 +39,7 @@ class AnnotatableFields(object): ) display_name = String( display_name=_("Display Name"), - help=_("Display name for this module"), + help=_("The display name for this component."), scope=Scope.settings, default=_('Annotation'), ) diff --git a/common/lib/xmodule/xmodule/capa_base.py b/common/lib/xmodule/xmodule/capa_base.py index 783687fc8e..d02627af30 100644 --- a/common/lib/xmodule/xmodule/capa_base.py +++ b/common/lib/xmodule/xmodule/capa_base.py @@ -92,7 +92,7 @@ class CapaFields(object): """ display_name = String( display_name=_("Display Name"), - help=_("This name appears in the horizontal navigation at the top of the page."), + help=_("The display name for this component."), scope=Scope.settings, # it'd be nice to have a useful default but it screws up other things; so, # use display_name_with_default for those diff --git a/common/lib/xmodule/xmodule/conditional_module.py b/common/lib/xmodule/xmodule/conditional_module.py index a2fa824079..0c7fc1e9d2 100644 --- a/common/lib/xmodule/xmodule/conditional_module.py +++ b/common/lib/xmodule/xmodule/conditional_module.py @@ -27,7 +27,7 @@ class ConditionalFields(object): has_children = True display_name = String( display_name=_("Display Name"), - help=_("This name appears in the horizontal navigation at the top of the page."), + help=_("The display name for this component."), scope=Scope.settings, default=_('Conditional') ) diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index 903606a5fa..fc310b70d2 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -38,7 +38,7 @@ class HtmlBlock(object): """ display_name = String( display_name=_("Display Name"), - help=_("This name appears in the horizontal navigation at the top of the page."), + help=_("The display name for this component."), scope=Scope.settings, # it'd be nice to have a useful default but it screws up other things; so, # use display_name_with_default for those @@ -329,7 +329,7 @@ class HtmlDescriptor(HtmlBlock, XmlDescriptor, EditingDescriptor): # pylint: di class AboutFields(object): display_name = String( - help=_("Display name for this module"), + help=_("The display name for this component."), scope=Scope.settings, default="overview", ) @@ -364,7 +364,7 @@ class StaticTabFields(object): """ display_name = String( display_name=_("Display Name"), - help=_("This name appears in the horizontal navigation at the top of the page."), + help=_("The display name for this component."), scope=Scope.settings, default="Empty", ) diff --git a/common/lib/xmodule/xmodule/imageannotation_module.py b/common/lib/xmodule/xmodule/imageannotation_module.py index e9d68ebac1..c9b361b84a 100644 --- a/common/lib/xmodule/xmodule/imageannotation_module.py +++ b/common/lib/xmodule/xmodule/imageannotation_module.py @@ -45,7 +45,7 @@ class AnnotatableFields(object): """)) display_name = String( display_name=_("Display Name"), - help=_("Display name for this module"), + help=_("The display name for this component."), scope=Scope.settings, default=_('Image Annotation'), ) diff --git a/common/lib/xmodule/xmodule/library_content_module.py b/common/lib/xmodule/xmodule/library_content_module.py index ae46a775b5..cd06b49ec4 100644 --- a/common/lib/xmodule/xmodule/library_content_module.py +++ b/common/lib/xmodule/xmodule/library_content_module.py @@ -60,7 +60,7 @@ class LibraryContentFields(object): # to locate input elements - keep synchronized display_name = String( display_name=_("Display Name"), - help=_("Display name for this module"), + help=_("The display name for this component."), default="Randomized Content Block", scope=Scope.settings, ) diff --git a/common/lib/xmodule/xmodule/library_root_xblock.py b/common/lib/xmodule/xmodule/library_root_xblock.py index 6c9466d889..f546f2f14a 100644 --- a/common/lib/xmodule/xmodule/library_root_xblock.py +++ b/common/lib/xmodule/xmodule/library_root_xblock.py @@ -25,7 +25,7 @@ class LibraryRoot(XBlock): resources_dir = None display_name = String( - help=_("Enter the name of the library as it should appear in Studio."), + help=_("The display name for this component."), default="Library", display_name=_("Library Display Name"), scope=Scope.settings diff --git a/common/lib/xmodule/xmodule/lti_module.py b/common/lib/xmodule/xmodule/lti_module.py index df02c6ce9c..84153f621c 100644 --- a/common/lib/xmodule/xmodule/lti_module.py +++ b/common/lib/xmodule/xmodule/lti_module.py @@ -109,7 +109,7 @@ class LTIFields(object): display_name = String( display_name=_("Display Name"), help=_( - "Enter the name that students see for this component. " + "The display name for this component. " "Analytics reports may also use the display name to identify this component." ), scope=Scope.settings, diff --git a/common/lib/xmodule/xmodule/poll_module.py b/common/lib/xmodule/xmodule/poll_module.py index 9b86d01ab2..a39cd34a9a 100644 --- a/common/lib/xmodule/xmodule/poll_module.py +++ b/common/lib/xmodule/xmodule/poll_module.py @@ -23,20 +23,43 @@ from xmodule.xml_module import XmlDescriptor from xblock.fields import Scope, String, Dict, Boolean, List log = logging.getLogger(__name__) +_ = lambda text: text class PollFields(object): # Name of poll to use in links to this poll - display_name = String(help="Display name for this module", scope=Scope.settings) + display_name = String( + help=_("The display name for this component."), + scope=Scope.settings + ) - voted = Boolean(help="Whether this student has voted on the poll", scope=Scope.user_state, default=False) - poll_answer = String(help="Student answer", scope=Scope.user_state, default='') - poll_answers = Dict(help="Poll answers from all students", scope=Scope.user_state_summary) + voted = Boolean( + help=_("Whether this student has voted on the poll"), + scope=Scope.user_state, + default=False + ) + poll_answer = String( + help=_("Student answer"), + scope=Scope.user_state, + default='' + ) + poll_answers = Dict( + help=_("Poll answers from all students"), + scope=Scope.user_state_summary + ) # List of answers, in the form {'id': 'some id', 'text': 'the answer text'} - answers = List(help="Poll answers from xml", scope=Scope.content, default=[]) + answers = List( + help=_("Poll answers from xml"), + scope=Scope.content, + default=[] + ) - question = String(help="Poll question", scope=Scope.content, default='') + question = String( + help=_("Poll question"), + scope=Scope.content, + default='' + ) class PollModule(PollFields, XModule): diff --git a/common/lib/xmodule/xmodule/split_test_module.py b/common/lib/xmodule/xmodule/split_test_module.py index eb127297f8..144460590e 100644 --- a/common/lib/xmodule/xmodule/split_test_module.py +++ b/common/lib/xmodule/xmodule/split_test_module.py @@ -58,7 +58,7 @@ class SplitTestFields(object): display_name = String( display_name=_("Display Name"), - help=_("This name is used for organizing your course content, but is not shown to students."), + help=_("The display name for this component. (Not shown to learners)"), scope=Scope.settings, default=_("Content Experiment") ) diff --git a/common/lib/xmodule/xmodule/tests/test_xml_module.py b/common/lib/xmodule/xmodule/tests/test_xml_module.py index dcc0f2310d..290d5b1000 100644 --- a/common/lib/xmodule/xmodule/tests/test_xml_module.py +++ b/common/lib/xmodule/xmodule/tests/test_xml_module.py @@ -37,8 +37,12 @@ class TestFields(object): # Will not be returned by editable_metadata_fields because is not Scope.settings. student_answers = Dict(scope=Scope.user_state) # Will be returned, and can override the inherited value from XModule. - display_name = String(scope=Scope.settings, default='local default', display_name='Local Display Name', - help='local help') + display_name = String( + scope=Scope.settings, + default='local default', + display_name='Local Display Name', + help='local help' + ) # Used for testing select type, effect of to_json method string_select = CrazyJsonString( scope=Scope.settings, diff --git a/common/lib/xmodule/xmodule/textannotation_module.py b/common/lib/xmodule/xmodule/textannotation_module.py index dfcae252be..beff2b8454 100644 --- a/common/lib/xmodule/xmodule/textannotation_module.py +++ b/common/lib/xmodule/xmodule/textannotation_module.py @@ -34,7 +34,7 @@ class AnnotatableFields(object): """)) display_name = String( display_name=_("Display Name"), - help=_("Display name for this module"), + help=_("The display name for this component."), scope=Scope.settings, default=_('Text Annotation'), ) diff --git a/common/lib/xmodule/xmodule/video_module/video_xfields.py b/common/lib/xmodule/xmodule/video_module/video_xfields.py index a24fe56206..cec0036391 100644 --- a/common/lib/xmodule/xmodule/video_module/video_xfields.py +++ b/common/lib/xmodule/xmodule/video_module/video_xfields.py @@ -14,7 +14,7 @@ _ = lambda text: text class VideoFields(object): """Fields for `VideoModule` and `VideoDescriptor`.""" display_name = String( - help=_("The name students see. This name appears in the course ribbon and as a header for the video."), + help=_("The display name for this component."), display_name=_("Component Display Name"), default="Video", scope=Scope.settings diff --git a/common/lib/xmodule/xmodule/videoannotation_module.py b/common/lib/xmodule/xmodule/videoannotation_module.py index 945d676594..30ad2bfdf7 100644 --- a/common/lib/xmodule/xmodule/videoannotation_module.py +++ b/common/lib/xmodule/xmodule/videoannotation_module.py @@ -34,7 +34,7 @@ class AnnotatableFields(object): """)) display_name = String( display_name=_("Display Name"), - help=_("Display name for this module"), + help=_("The display name for this component."), scope=Scope.settings, default=_('Video Annotation'), ) diff --git a/common/lib/xmodule/xmodule/word_cloud_module.py b/common/lib/xmodule/xmodule/word_cloud_module.py index 6e12843efb..e80c556d8f 100644 --- a/common/lib/xmodule/xmodule/word_cloud_module.py +++ b/common/lib/xmodule/xmodule/word_cloud_module.py @@ -38,7 +38,7 @@ class WordCloudFields(object): """XFields for word cloud.""" display_name = String( display_name=_("Display Name"), - help=_("The label for this word cloud on the course page."), + help=_("The display name for this component."), scope=Scope.settings, default="Word cloud" ) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 1a3df2e956..7e707f4884 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -66,6 +66,11 @@ STUDIO_VIEW = 'studio_view' PREVIEW_VIEWS = [STUDENT_VIEW, AUTHOR_VIEW] +# Make '_' a no-op so we can scrape strings. Using lambda instead of +# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file +_ = lambda text: text + + class OpaqueKeyReader(IdReader): """ IdReader for :class:`DefinitionKey` and :class:`UsageKey`s. @@ -256,8 +261,8 @@ class XModuleFields(object): Common fields for XModules. """ display_name = String( - display_name="Display Name", - help="This name appears in the horizontal navigation at the top of the page.", + display_name=_("Display Name"), + help=_("The display name for this component."), scope=Scope.settings, # it'd be nice to have a useful default but it screws up other things; so, # use display_name_with_default for those diff --git a/lms/djangoapps/grades/migrations/0009_auto_20170111_1507.py b/lms/djangoapps/grades/migrations/0009_auto_20170111_1507.py new file mode 100644 index 0000000000..d71c45a811 --- /dev/null +++ b/lms/djangoapps/grades/migrations/0009_auto_20170111_1507.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('grades', '0008_persistentsubsectiongrade_first_attempted'), + ] + + operations = [ + migrations.AlterIndexTogether( + name='persistentcoursegrade', + index_together=set([('passed_timestamp', 'course_id'), ('modified', 'course_id')]), + ), + migrations.AlterIndexTogether( + name='persistentsubsectiongrade', + index_together=set([('modified', 'course_id', 'usage_key')]), + ), + ] diff --git a/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py b/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py new file mode 100644 index 0000000000..39cf1fdf49 --- /dev/null +++ b/lms/djangoapps/grades/migrations/0010_auto_20170112_1156.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('grades', '0009_auto_20170111_1507'), + ] + + operations = [ + migrations.AlterIndexTogether( + name='persistentsubsectiongrade', + index_together=set([('modified', 'course_id', 'usage_key'), ('first_attempted', 'course_id', 'user_id')]), + ), + ] diff --git a/lms/djangoapps/grades/models.py b/lms/djangoapps/grades/models.py index e95cda16e0..cb21a7539a 100644 --- a/lms/djangoapps/grades/models.py +++ b/lms/djangoapps/grades/models.py @@ -253,6 +253,17 @@ class PersistentSubsectionGrade(DeleteGradesMixin, TimeStampedModel): # * Course staff can see all grades for a course using (course_id,) ('course_id', 'user_id', 'usage_key'), ] + # Allows querying in the following ways: + # (modified): find all the grades updated within a certain timespan + # (modified, course_id): find all the grades updated within a timespan for a certain course + # (modified, course_id, usage_key): find all the grades updated within a timespan for a subsection + # in a course + # (first_attempted, course_id, user_id): find all attempted subsections in a course for a user + # (first_attempted, course_id): find all attempted subsections in a course for all users + index_together = [ + ('modified', 'course_id', 'usage_key'), + ('first_attempted', 'course_id', 'user_id') + ] # primary key will need to be large for this table id = UnsignedBigIntAutoField(primary_key=True) # pylint: disable=invalid-name @@ -502,11 +513,14 @@ class PersistentCourseGrade(DeleteGradesMixin, TimeStampedModel): # (course_id) for instructors to see all course grades, implicitly created via the unique_together constraint # (user_id) for course dashboard; explicitly declared as an index below # (passed_timestamp, course_id) for tracking when users first earned a passing grade. + # (modified): find all the grades updated within a certain timespan + # (modified, course_id): find all the grades updated within a certain timespan for a course unique_together = [ ('course_id', 'user_id'), ] index_together = [ ('passed_timestamp', 'course_id'), + ('modified', 'course_id') ] # primary key will need to be large for this table diff --git a/lms/djangoapps/instructor_task/tasks.py b/lms/djangoapps/instructor_task/tasks.py index 5a24516701..7ad7cf2a60 100644 --- a/lms/djangoapps/instructor_task/tasks.py +++ b/lms/djangoapps/instructor_task/tasks.py @@ -193,7 +193,7 @@ def calculate_problem_grade_report(entry_id, xmodule_instance_args): return run_main_task(entry_id, task_fn, action_name) -@task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY) # pylint: disable=not-callable +@task(base=BaseInstructorTask) # pylint: disable=not-callable def calculate_students_features_csv(entry_id, xmodule_instance_args): """ Compute student profile information for a course and upload the @@ -252,7 +252,7 @@ def proctored_exam_results_csv(entry_id, xmodule_instance_args): return run_main_task(entry_id, task_fn, action_name) -@task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY) # pylint: disable=not-callable +@task(base=BaseInstructorTask) # pylint: disable=not-callable def calculate_may_enroll_csv(entry_id, xmodule_instance_args): """ Compute information about invited students who have not enrolled @@ -293,7 +293,7 @@ def cohort_students(entry_id, xmodule_instance_args): return run_main_task(entry_id, task_fn, action_name) -@task(base=BaseInstructorTask, routing_key=settings.GRADES_DOWNLOAD_ROUTING_KEY) # pylint: disable=not-callable +@task(base=BaseInstructorTask) # pylint: disable=not-callable def export_ora2_data(entry_id, xmodule_instance_args): """ Generate a CSV of ora2 responses and push it to S3. diff --git a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion.py b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion.py index 14f83f8c81..44341eef53 100644 --- a/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion.py +++ b/openedx/core/lib/xblock_builtin/xblock_discussion/xblock_discussion.py @@ -39,7 +39,7 @@ class DiscussionXBlock(XBlock, StudioEditableXBlockMixin, XmlParserMixin): discussion_id = String(scope=Scope.settings, default=UNIQUE_ID) display_name = String( display_name=_("Display Name"), - help=_("Display name for this component"), + help=_("The display name for this component."), default="Discussion", scope=Scope.settings ) diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index 84c7cc2e1d..17ffa685a9 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -72,7 +72,7 @@ git+https://github.com/edx/lettuce.git@0.2.20.002#egg=lettuce==0.2.20.002 # Our libraries: git+https://github.com/edx/XBlock.git@xblock-0.4.13#egg=XBlock==0.4.13 --e git+https://github.com/edx/codejail.git@6b17c33a89bef0ac510926b1d7fea2748b73aadd#egg=codejail +-e git+https://github.com/edx/codejail.git@0b2dc694f05ddc8fee3e65d837cee57b6ce51a6b#egg=codejail==0.0 -e git+https://github.com/edx/event-tracking.git@0.2.1#egg=event-tracking==0.2.1 -e git+https://github.com/edx/django-splash.git@v0.2#egg=django-splash==0.2 -e git+https://github.com/edx/acid-block.git@e46f9cda8a03e121a00c7e347084d142d22ebfb7#egg=acid-xblock @@ -91,7 +91,7 @@ git+https://github.com/edx/xblock-utils.git@v1.0.3#egg=xblock-utils==1.0.3 -e git+https://github.com/edx/edx-reverification-block.git@0.0.5#egg=edx-reverification-block==0.0.5 git+https://github.com/edx/edx-user-state-client.git@1.0.1#egg=edx-user-state-client==1.0.1 git+https://github.com/edx/xblock-lti-consumer.git@v1.1.0#egg=xblock-lti-consumer==1.1.0 -git+https://github.com/edx/edx-proctoring.git@0.16.2#egg=edx-proctoring==0.16.2 +git+https://github.com/edx/edx-proctoring.git@0.17.0#egg=edx-proctoring==0.17.0 # Third Party XBlocks -e git+https://github.com/mitodl/edx-sga@172a90fd2738f8142c10478356b2d9ed3e55334a#egg=edx-sga