diff --git a/course/admin.py b/course/admin.py index ace25a802a41fd5c869d0bf336fb645281b57e46..faf862d6d2c762db7a70dfadb40ca2c14d2fea37 100644 --- a/course/admin.py +++ b/course/admin.py @@ -532,7 +532,7 @@ class FlowPageVisitAdmin(admin.ModelAdmin): get_flow_id.admin_order_field = "flow_session__flow_id" # type: ignore def get_page_id(self, obj): - if obj.page_data.ordinal is None: + if obj.page_data.page_ordinal is None: return string_concat("%s/%s (", _("not in use"), ")") % ( obj.page_data.group_id, obj.page_data.page_id) @@ -540,7 +540,7 @@ class FlowPageVisitAdmin(admin.ModelAdmin): return "%s/%s (%s)" % ( obj.page_data.group_id, obj.page_data.page_id, - obj.page_data.ordinal) + obj.page_data.page_ordinal) get_page_id.short_description = _("Page ID") # type: ignore get_page_id.admin_order_field = "page_data__page_id" # type: ignore diff --git a/course/auth.py b/course/auth.py index 8388545d1030e1500e6bb373e67f3fbe8217dbc7..2199cf2be66e16cf224ba7250aa7c713742eae7a 100644 --- a/course/auth.py +++ b/course/auth.py @@ -270,6 +270,24 @@ def stop_impersonating(request): raise PermissionDenied() if not hasattr(request, "relate_impersonate_original_user"): + # prevent user without pperm to stop_impersonating + my_participations = Participation.objects.filter( + user=request.user, + status=participation_status.active) + + may_impersonate = False + for part in my_participations: + perms = [ + perm + for perm, argument in part.permissions() + if perm == pperm.impersonate_role] + if any(perms): + may_impersonate = True + break + + if not may_impersonate: + raise PermissionDenied() + messages.add_message(request, messages.ERROR, _("Not currently impersonating anyone.")) return redirect("relate-home") diff --git a/course/flow.py b/course/flow.py index 3ce19d96c61dd178a6890b93bc421d4abd927b5f..56f4484e64f27cc479659e35a19e22e0df347d2b 100644 --- a/course/flow.py +++ b/course/flow.py @@ -125,8 +125,8 @@ def _adjust_flow_session_page_data_inner(repo, flow_session, from course.models import FlowPageData def remove_page(fpd): - if fpd.ordinal is not None: - fpd.ordinal = None + if fpd.page_ordinal is not None: + fpd.page_ordinal = None fpd.save() desc_group_ids = [] @@ -173,7 +173,7 @@ def _adjust_flow_session_page_data_inner(repo, flow_session, data = page.initialize_page_data(pctx) return FlowPageData( flow_session=flow_session, - ordinal=None, + page_ordinal=None, page_type=new_page_desc.type, group_id=grp.id, page_id=new_page_desc.id, @@ -181,8 +181,8 @@ def _adjust_flow_session_page_data_inner(repo, flow_session, title=page.title(pctx, data)) def add_page(fpd): - if fpd.ordinal != ordinal[0]: - fpd.ordinal = ordinal[0] + if fpd.page_ordinal != ordinal[0]: + fpd.page_ordinal = ordinal[0] fpd.save() page_desc = find_page_desc(fpd.page_id) @@ -206,8 +206,8 @@ def _adjust_flow_session_page_data_inner(repo, flow_session, .filter( flow_session=flow_session, group_id=grp.id, - ordinal__isnull=False) - .order_by("ordinal")): + page_ordinal__isnull=False) + .order_by("page_ordinal")): if (fpd.page_id in available_page_ids and len(group_pages) < max_page_count): @@ -270,7 +270,7 @@ def _adjust_flow_session_page_data_inner(repo, flow_session, FlowPageData.objects .filter( flow_session=flow_session, - ordinal__isnull=False) + page_ordinal__isnull=False) .exclude(group_id__in=desc_group_ids) ): remove_page(fpd) @@ -524,14 +524,14 @@ def assemble_page_grades(flow_sessions): all_answer_visits = ( get_multiple_flow_session_graded_answers_qset(flow_sessions) .order_by("visit_time") - .values("id", "flow_session_id", "page_data__ordinal", + .values("id", "flow_session_id", "page_data__page_ordinal", "is_submitted_answer")) for answer_visit in all_answer_visits: fsess_idx = id_to_fsess_idx[answer_visit["flow_session_id"]] - ordinal = answer_visit["page_data__ordinal"] - if ordinal is not None: - answer_visit_ids[fsess_idx][ordinal] = answer_visit["id"] + page_ordinal = answer_visit["page_data__page_ordinal"] + if page_ordinal is not None: + answer_visit_ids[fsess_idx][page_ordinal] = answer_visit["id"] if not flow_sessions[fsess_idx].in_progress: assert answer_visit["is_submitted_answer"] is True @@ -571,8 +571,8 @@ def assemble_answer_visits(flow_session): .order_by("visit_time")) for page_visit in answer_page_visits: - if page_visit.page_data.ordinal is not None: - answer_visits[page_visit.page_data.ordinal] = page_visit + if page_visit.page_data.page_ordinal is not None: + answer_visits[page_visit.page_data.page_ordinal] = page_visit if not flow_session.in_progress: assert page_visit.is_submitted_answer is True @@ -586,8 +586,8 @@ def get_all_page_data(flow_session): return (FlowPageData.objects .filter( flow_session=flow_session, - ordinal__isnull=False) - .order_by("ordinal")) + page_ordinal__isnull=False) + .order_by("page_ordinal")) def get_interaction_kind( @@ -601,7 +601,7 @@ def get_interaction_kind( ikind = flow_session_interaction_kind.noninteractive for i, page_data in enumerate(all_page_data): - assert i == page_data.ordinal + assert i == page_data.page_ordinal page = instantiate_flow_page_with_ctx(fctx, page_data) if page.expects_answer(): @@ -629,7 +629,7 @@ def get_session_answered_page_data( is_interactive_flow = False # type: bool for i, page_data in enumerate(all_page_data): - assert i == page_data.ordinal + assert i == page_data.page_ordinal avisit = answer_visits[i] if avisit is not None: @@ -815,7 +815,7 @@ def gather_grade_info( for i, page_data in enumerate(all_page_data): page = instantiate_flow_page_with_ctx(fctx, page_data) - assert i == page_data.ordinal + assert i == page_data.page_ordinal av = answer_visits[i] @@ -927,7 +927,7 @@ def grade_page_visits( answer_visit.save() else: - page_data = flow_session.page_data.get(ordinal=i) + page_data = flow_session.page_data.get(page_ordinal=i) page = instantiate_flow_page_with_ctx(fctx, page_data) if not page.expects_answer(): @@ -1701,7 +1701,7 @@ def add_buttons_to_form(form, fpctx, flow_session, permissions): css_class="relate-save-button relate-submit-button")) else: # Only offer 'save and move on' if student will receive no feedback - if fpctx.page_data.ordinal + 1 < flow_session.page_count: + if fpctx.page_data.page_ordinal + 1 < flow_session.page_count: form.helper.add_input( Submit("save_and_next", mark_safe_lazy( @@ -1744,13 +1744,13 @@ def create_flow_page_visit(request, flow_session, page_data): @course_view -def view_flow_page(pctx, flow_session_id, ordinal): +def view_flow_page(pctx, flow_session_id, page_ordinal): # type: (CoursePageContext, int, int) -> http.HttpResponse request = pctx.request login_exam_ticket = get_login_exam_ticket(request) - ordinal = int(ordinal) + page_ordinal = int(page_ordinal) flow_session_id = int(flow_session_id) flow_session = get_and_check_flow_session(pctx, flow_session_id) @@ -1769,10 +1769,10 @@ def view_flow_page(pctx, flow_session_id, ordinal): respect_preview=True) try: - fpctx = FlowPageContext(pctx.repo, pctx.course, flow_id, ordinal, - participation=pctx.participation, - flow_session=flow_session, - request=pctx.request) + fpctx = FlowPageContext(pctx.repo, pctx.course, flow_id, page_ordinal, + participation=pctx.participation, + flow_session=flow_session, + request=pctx.request) except PageOrdinalOutOfRange: return redirect("relate-view_flow_page", pctx.course.identifier, @@ -2012,13 +2012,13 @@ def view_flow_page(pctx, flow_session_id, ordinal): from django.db import connection with connection.cursor() as c: c.execute( - "SELECT DISTINCT course_flowpagedata.ordinal " + "SELECT DISTINCT course_flowpagedata.page_ordinal " "FROM course_flowpagevisit " "INNER JOIN course_flowpagedata " "ON course_flowpagedata.id = course_flowpagevisit.page_data_id " "WHERE course_flowpagedata.flow_session_id = %s " "AND course_flowpagevisit.answer IS NOT NULL " - "ORDER BY course_flowpagedata.ordinal", + "ORDER BY course_flowpagedata.page_ordinal", [flow_session.id]) flow_page_ordinals_with_answers = set(row[0] for row in c.fetchall()) @@ -2026,9 +2026,9 @@ def view_flow_page(pctx, flow_session_id, ordinal): args = { "flow_identifier": fpctx.flow_id, "flow_desc": fpctx.flow_desc, - "ordinal": fpctx.ordinal, + "page_ordinal": fpctx.page_ordinal, "page_data": fpctx.page_data, - "percentage": int(100*(fpctx.ordinal+1) / flow_session.page_count), + "percentage": int(100 * (fpctx.page_ordinal+1) / flow_session.page_count), "flow_session": flow_session, "all_page_data": all_page_data, "flow_page_ordinals_with_answers": flow_page_ordinals_with_answers, @@ -2106,7 +2106,7 @@ def get_prev_answer_visits_dropdown_content(pctx, flow_session_id, page_ordinal) flow_session = get_and_check_flow_session(pctx, int(flow_session_id)) page_data = get_object_or_404( - FlowPageData, flow_session=flow_session, ordinal=page_ordinal) + FlowPageData, flow_session=flow_session, page_ordinal=page_ordinal) prev_answer_visits = get_prev_answer_visits_qset(page_data) def serialize(obj): @@ -2243,9 +2243,9 @@ def post_flow_page( if (pressed_button == "save_and_next" and not will_receive_feedback(permissions)): return redirect("relate-view_flow_page", - fpctx.course.identifier, - flow_session.id, - fpctx.ordinal + 1) + fpctx.course.identifier, + flow_session.id, + fpctx.page_ordinal + 1) elif (pressed_button == "save_and_finish" and not will_receive_feedback(permissions)): return redirect("relate-finish_flow_session_view", @@ -2292,16 +2292,16 @@ def post_flow_page( # {{{ view: send interaction email to course staffs in flow pages @course_view -def send_email_about_flow_page(pctx, flow_session_id, ordinal): +def send_email_about_flow_page(pctx, flow_session_id, page_ordinal): # {{{ check if interaction email is allowed for this page. - ordinal = int(ordinal) + page_ordinal = int(page_ordinal) flow_session_id = int(flow_session_id) flow_session = get_and_check_flow_session(pctx, flow_session_id) flow_id = flow_session.flow_id - fpctx = FlowPageContext(pctx.repo, pctx.course, flow_id, ordinal, + fpctx = FlowPageContext(pctx.repo, pctx.course, flow_id, page_ordinal, participation=pctx.participation, flow_session=flow_session, request=pctx.request) @@ -2332,13 +2332,13 @@ def send_email_about_flow_page(pctx, flow_session_id, ordinal): FlowSession, id=int(flow_session_id)) from course.models import FlowPageData page_id = FlowPageData.objects.get( - flow_session=flow_session_id, ordinal=ordinal).page_id + flow_session=flow_session_id, page_ordinal=page_ordinal).page_id review_url = reverse( "relate-view_flow_page", kwargs={'course_identifier': pctx.course.identifier, 'flow_session_id': flow_session_id, - 'ordinal': ordinal + 'page_ordinal': page_ordinal } ) @@ -2428,7 +2428,7 @@ def send_email_about_flow_page(pctx, flow_session_id, ordinal): "also receive a copy of the email.")) return redirect("relate-view_flow_page", - pctx.course.identifier, flow_session_id, ordinal) + pctx.course.identifier, flow_session_id, page_ordinal) else: form = FlowPageInteractionEmailForm(review_uri) @@ -2471,7 +2471,7 @@ class FlowPageInteractionEmailForm(StyledForm): # {{{ view: update page bookmark state @course_view -def update_page_bookmark_state(pctx, flow_session_id, ordinal): +def update_page_bookmark_state(pctx, flow_session_id, page_ordinal): if pctx.request.method != "POST": raise SuspiciousOperation(_("only POST allowed")) @@ -2488,8 +2488,8 @@ def update_page_bookmark_state(pctx, flow_session_id, ordinal): bookmark_state = bookmark_state == "1" fpd = get_object_or_404(FlowPageData.objects, - flow_session=flow_session, - ordinal=ordinal) + flow_session=flow_session, + page_ordinal=page_ordinal) fpd.bookmarked = bookmark_state fpd.save() @@ -2841,13 +2841,13 @@ class UnsubmitFlowPageForm(forms.Form): @course_view -def view_unsubmit_flow_page(pctx, flow_session_id, ordinal): +def view_unsubmit_flow_page(pctx, flow_session_id, page_ordinal): # type: (CoursePageContext, int, int) -> http.HttpResponse request = pctx.request now_datetime = get_now_or_fake_time(request) - ordinal = int(ordinal) + page_ordinal = int(page_ordinal) flow_session_id = int(flow_session_id) try: @@ -2880,7 +2880,7 @@ def view_unsubmit_flow_page(pctx, flow_session_id, ordinal): # }}} page_data = get_object_or_404( - FlowPageData, flow_session=flow_session, ordinal=ordinal) + FlowPageData, flow_session=flow_session, page_ordinal=page_ordinal) visit = get_first_from_qset( get_prev_answer_visits_qset(page_data) @@ -2890,7 +2890,7 @@ def view_unsubmit_flow_page(pctx, flow_session_id, ordinal): messages.add_message(request, messages.INFO, _("No prior answers found that could be un-submitted.")) return redirect("relate-view_flow_page", - pctx.course.identifier, flow_session_id, ordinal) + pctx.course.identifier, flow_session_id, page_ordinal) if request.method == 'POST': form = UnsubmitFlowPageForm(request.POST) @@ -2901,7 +2901,7 @@ def view_unsubmit_flow_page(pctx, flow_session_id, ordinal): _("Flow page changes reallowed. ")) return redirect("relate-view_flow_page", - pctx.course.identifier, flow_session_id, ordinal) + pctx.course.identifier, flow_session_id, page_ordinal) else: form = UnsubmitFlowPageForm() diff --git a/course/grading.py b/course/grading.py index c7d42d76c4524814b8261fce91955f6c6c2ba54c..9ddca160348e8ffd28ef242757420ec89dd29225 100644 --- a/course/grading.py +++ b/course/grading.py @@ -81,7 +81,7 @@ def get_prev_visit_grades( return (FlowPageVisitGrade.objects .filter( visit__flow_session_id=flow_session_id, - visit__page_data__ordinal=page_ordinal, + visit__page_data__page_ordinal=page_ordinal, visit__is_submitted_answer=True) .order_by(*order_by_args) .select_related("visit")) @@ -157,8 +157,8 @@ def grade_flow_page(pctx, flow_session_id, page_ordinal): pctx.course.identifier, respect_preview=False) fpctx = FlowPageContext(pctx.repo, pctx.course, flow_session.flow_id, - page_ordinal, participation=flow_session.participation, - flow_session=flow_session, request=pctx.request) + page_ordinal, participation=flow_session.participation, + flow_session=flow_session, request=pctx.request) if fpctx.page_desc is None: raise http.Http404() @@ -369,7 +369,7 @@ def grade_flow_page(pctx, flow_session_id, page_ordinal): "flow_identifier": fpctx.flow_id, "flow_session": flow_session, "flow_desc": fpctx.flow_desc, - "ordinal": fpctx.ordinal, + "page_ordinal": fpctx.page_ordinal, "page_data": fpctx.page_data, "body": fpctx.page.body( @@ -454,7 +454,7 @@ def show_grader_statistics(pctx, flow_id): graders = set() - # tuples: (ordinal, id) + # tuples: (page_ordinal, id) pages = set() counts = {} @@ -463,7 +463,7 @@ def show_grader_statistics(pctx, flow_id): def commit_grade_info(grade): grader = grade.grader - page = (grade.visit.page_data.ordinal, + page = (grade.visit.page_data.page_ordinal, grade.visit.page_data.group_id + "/" + grade.visit.page_data.page_id) graders.add(grader) diff --git a/course/migrations/0107_rename_flowpagedata_ordinal_to_page_ordinal.py b/course/migrations/0107_rename_flowpagedata_ordinal_to_page_ordinal.py new file mode 100644 index 0000000000000000000000000000000000000000..b0d102eeba429cd0c45e83fbfde33919b50f1dc9 --- /dev/null +++ b/course/migrations/0107_rename_flowpagedata_ordinal_to_page_ordinal.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-19 02:37 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0106_add_auth_tokens_permission'), + ] + + operations = [ + migrations.RenameField( + model_name='flowpagedata', + old_name='ordinal', + new_name='page_ordinal', + ), + ] diff --git a/course/migrations/0108_alter_page_ordinal_verbose_name.py b/course/migrations/0108_alter_page_ordinal_verbose_name.py new file mode 100644 index 0000000000000000000000000000000000000000..db491409be66f085cc13f9621cf5713a2db9143a --- /dev/null +++ b/course/migrations/0108_alter_page_ordinal_verbose_name.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-19 02:44 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0107_rename_flowpagedata_ordinal_to_page_ordinal'), + ] + + operations = [ + migrations.AlterField( + model_name='flowpagedata', + name='page_ordinal', + field=models.IntegerField(blank=True, null=True, verbose_name='Page ordinal'), + ), + ] diff --git a/course/migrations/0109_add_manage_authentication_tokens_permssion.py b/course/migrations/0109_add_manage_authentication_tokens_permssion.py new file mode 100644 index 0000000000000000000000000000000000000000..8116b95dab45c141f51d17dc108c7efd98354a53 --- /dev/null +++ b/course/migrations/0109_add_manage_authentication_tokens_permssion.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2017-12-19 02:45 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0108_alter_page_ordinal_verbose_name'), + ] + + operations = [ + migrations.AlterField( + model_name='participationpermission', + name='permission', + field=models.CharField(choices=[('edit_course', 'Edit course'), ('use_admin_interface', 'Use admin interface'), ('manage_authentication_tokens', 'Manage authentication tokens'), ('impersonate_role', 'Impersonate role'), ('set_fake_time', 'Set fake time'), ('set_pretend_facility', 'Pretend to be in facility'), ('edit_course_permissions', 'Edit course permissions'), ('view_hidden_course_page', 'View hidden course page'), ('view_calendar', 'View calendar'), ('send_instant_message', 'Send instant message'), ('access_files_for', 'Access files for'), ('included_in_grade_statistics', 'Included in grade statistics'), ('skip_during_manual_grading', 'Skip during manual grading'), ('edit_exam', 'Edit exam'), ('issue_exam_ticket', 'Issue exam ticket'), ('batch_issue_exam_ticket', 'Batch issue exam ticket'), ('view_participant_masked_profile', "View participants' masked profile only"), ('view_flow_sessions_from_role', 'View flow sessions from role'), ('view_gradebook', 'View gradebook'), ('edit_grading_opportunity', 'Edit grading opportunity'), ('assign_grade', 'Assign grade'), ('view_grader_stats', 'View grader stats'), ('batch_import_grade', 'Batch-import grades'), ('batch_export_grade', 'Batch-export grades'), ('batch_download_submission', 'Batch-download submissions'), ('impose_flow_session_deadline', 'Impose flow session deadline'), ('batch_impose_flow_session_deadline', 'Batch-impose flow session deadline'), ('end_flow_session', 'End flow session'), ('batch_end_flow_session', 'Batch-end flow sessions'), ('regrade_flow_session', 'Regrade flow session'), ('batch_regrade_flow_session', 'Batch-regrade flow sessions'), ('recalculate_flow_session_grade', 'Recalculate flow session grade'), ('batch_recalculate_flow_session_grade', 'Batch-recalculate flow sesssion grades'), ('reopen_flow_session', 'Reopen flow session'), ('grant_exception', 'Grant exception'), ('view_analytics', 'View analytics'), ('preview_content', 'Preview content'), ('update_content', 'Update content'), ('use_markup_sandbox', 'Use markup sandbox'), ('use_page_sandbox', 'Use page sandbox'), ('test_flow', 'Test flow'), ('edit_events', 'Edit events'), ('query_participation', 'Query participation'), ('edit_participation', 'Edit participation'), ('preapprove_participation', 'Preapprove participation'), ('manage_instant_flow_requests', 'Manage instant flow requests')], db_index=True, max_length=200, verbose_name='Permission'), + ), + migrations.AlterField( + model_name='participationrolepermission', + name='permission', + field=models.CharField(choices=[('edit_course', 'Edit course'), ('use_admin_interface', 'Use admin interface'), ('manage_authentication_tokens', 'Manage authentication tokens'), ('impersonate_role', 'Impersonate role'), ('set_fake_time', 'Set fake time'), ('set_pretend_facility', 'Pretend to be in facility'), ('edit_course_permissions', 'Edit course permissions'), ('view_hidden_course_page', 'View hidden course page'), ('view_calendar', 'View calendar'), ('send_instant_message', 'Send instant message'), ('access_files_for', 'Access files for'), ('included_in_grade_statistics', 'Included in grade statistics'), ('skip_during_manual_grading', 'Skip during manual grading'), ('edit_exam', 'Edit exam'), ('issue_exam_ticket', 'Issue exam ticket'), ('batch_issue_exam_ticket', 'Batch issue exam ticket'), ('view_participant_masked_profile', "View participants' masked profile only"), ('view_flow_sessions_from_role', 'View flow sessions from role'), ('view_gradebook', 'View gradebook'), ('edit_grading_opportunity', 'Edit grading opportunity'), ('assign_grade', 'Assign grade'), ('view_grader_stats', 'View grader stats'), ('batch_import_grade', 'Batch-import grades'), ('batch_export_grade', 'Batch-export grades'), ('batch_download_submission', 'Batch-download submissions'), ('impose_flow_session_deadline', 'Impose flow session deadline'), ('batch_impose_flow_session_deadline', 'Batch-impose flow session deadline'), ('end_flow_session', 'End flow session'), ('batch_end_flow_session', 'Batch-end flow sessions'), ('regrade_flow_session', 'Regrade flow session'), ('batch_regrade_flow_session', 'Batch-regrade flow sessions'), ('recalculate_flow_session_grade', 'Recalculate flow session grade'), ('batch_recalculate_flow_session_grade', 'Batch-recalculate flow sesssion grades'), ('reopen_flow_session', 'Reopen flow session'), ('grant_exception', 'Grant exception'), ('view_analytics', 'View analytics'), ('preview_content', 'Preview content'), ('update_content', 'Update content'), ('use_markup_sandbox', 'Use markup sandbox'), ('use_page_sandbox', 'Use page sandbox'), ('test_flow', 'Test flow'), ('edit_events', 'Edit events'), ('query_participation', 'Query participation'), ('edit_participation', 'Edit participation'), ('preapprove_participation', 'Preapprove participation'), ('manage_instant_flow_requests', 'Manage instant flow requests')], db_index=True, max_length=200, verbose_name='Permission'), + ), + ] diff --git a/course/models.py b/course/models.py index f7165d86e8dd6ebdd983330bec79715a07562a3a..f33bf50c3711da9427f758188de01bbd79e99ad4 100644 --- a/course/models.py +++ b/course/models.py @@ -910,8 +910,8 @@ class FlowSession(models.Model): class FlowPageData(models.Model): flow_session = models.ForeignKey(FlowSession, related_name="page_data", verbose_name=_('Flow session'), on_delete=models.CASCADE) - ordinal = models.IntegerField(null=True, blank=True, - verbose_name=_('Ordinal')) + page_ordinal = models.IntegerField(null=True, blank=True, + verbose_name=_('Page ordinal')) # This exists to catch changing page types in course content, # which will generally lead to an inconsistency disaster. @@ -943,10 +943,10 @@ class FlowPageData(models.Model): def __unicode__(self): # flow page data return (_("Data for page '%(group_id)s/%(page_id)s' " - "(ordinal %(ordinal)s) in %(flow_session)s") % { + "(page ordinal %(page_ordinal)s) in %(flow_session)s") % { 'group_id': self.group_id, 'page_id': self.page_id, - 'ordinal': self.ordinal, + 'page_ordinal': self.page_ordinal, 'flow_session': self.flow_session}) if six.PY3: @@ -954,13 +954,13 @@ class FlowPageData(models.Model): # Django's templates are a little daft. No arithmetic--really? def previous_ordinal(self): - return self.ordinal - 1 + return self.page_ordinal - 1 def next_ordinal(self): - return self.ordinal + 1 + return self.page_ordinal + 1 def human_readable_ordinal(self): - return self.ordinal + 1 + return self.page_ordinal + 1 # }}} diff --git a/course/templates/course/flow-confirm-completion.html b/course/templates/course/flow-confirm-completion.html index f2913372dc3d6b801ab0949dc49b6ba73971e871..3e5062566588e5b13a51ffe38d6e7c1259f64a4e 100644 --- a/course/templates/course/flow-confirm-completion.html +++ b/course/templates/course/flow-confirm-completion.html @@ -16,7 +16,7 @@