diff --git a/TODO b/TODO index f52e6e736b51f2324f548570a4509f874929f520..38545e0bc304f62e5fbcd5332327f1239e44fb69 100644 --- a/TODO +++ b/TODO @@ -25,8 +25,6 @@ Ideas - Change "end session" link for sessions that don't actually end. -- Session reset UI - - Manual grade entry/override - Flow results analytics diff --git a/course/content.py b/course/content.py index bc0f6d7cd7920ea9b70b26cf7c21cdea6471b44f..84f71549b39beafae89e963a9a59fcbd50887e38 100644 --- a/course/content.py +++ b/course/content.py @@ -32,6 +32,7 @@ import six from django.utils.timezone import now from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured +from django.db import transaction from markdown.extensions import Extension from markdown.treeprocessors import Treeprocessor @@ -725,33 +726,53 @@ def instantiate_flow_page(location, repo, page_desc, commit_sha): return class_(None, location, page_desc) -def set_up_flow_session_page_data(repo, flow_session, +@transaction.atomic +def adjust_flow_session_page_data(repo, flow_session, course_identifier, flow_desc, commit_sha): from course.models import FlowPageData + id_to_existing_page = { + (data.group_id, data.page_id): data + for data in FlowPageData.objects.filter(flow_session=flow_session) + } + data = None ordinal = 0 for grp in flow_desc.groups: for page_desc in grp.pages: - data = FlowPageData() - data.flow_session = flow_session - data.ordinal = ordinal - data.is_last = False - data.group_id = grp.id - data.page_id = page_desc.id - - page = instantiate_flow_page( - "course '%s', flow '%s', page '%s/%s'" - % (course_identifier, flow_session.flow_id, - grp.id, page_desc.id), - repo, page_desc, commit_sha) - data.data = page.make_page_data() - data.save() + key = (grp.id, page_desc.id) + + if key in id_to_existing_page: + data = id_to_existing_page.pop(key) + if data.ordinal != ordinal: + data.ordinal = ordinal + data.save() + else: + data = FlowPageData() + data.flow_session = flow_session + data.ordinal = ordinal + data.group_id = grp.id + data.page_id = page_desc.id + + page = instantiate_flow_page( + "course '%s', flow '%s', page '%s/%s'" + % (course_identifier, flow_session.flow_id, + grp.id, page_desc.id), + repo, page_desc, commit_sha) + data.data = page.make_page_data() + data.save() ordinal += 1 - return ordinal + for data in id_to_existing_page.values(): + if data.ordinal is not None: + data.ordinal = None + data.save() + + if flow_session.page_count != ordinal: + flow_session.page_count = ordinal + flow_session.save() def get_course_commit_sha(course, participation): diff --git a/course/flow.py b/course/flow.py index 3c8eb7655bac40e3658cb6461b49eae64d272cbc..bd6f6410350946b6f2897ad35fa9c8df3359a5a3 100644 --- a/course/flow.py +++ b/course/flow.py @@ -704,7 +704,7 @@ def start_flow(pctx, flow_identifier): pctx.role, flow_identifier, fctx.flow_desc, now_datetime) if request.method == "POST": - from course.content import set_up_flow_session_page_data + from course.content import adjust_flow_session_page_data if "start" in request.POST: @@ -740,10 +740,9 @@ def start_flow(pctx, flow_identifier): grading_rule, "grade_aggregation_strategy"), )) - page_count = set_up_flow_session_page_data(fctx.repo, session, + # will implicitly modify and save the session if there are changes + adjust_flow_session_page_data(fctx.repo, session, pctx.course.identifier, fctx.flow_desc, pctx.course_commit_sha) - session.page_count = page_count - session.save() return redirect("course.flow.view_flow_page", pctx.course.identifier, session.id, 0) diff --git a/course/migrations/0046_allow_null_page_data_ordinals.py b/course/migrations/0046_allow_null_page_data_ordinals.py new file mode 100644 index 0000000000000000000000000000000000000000..cacb35fbe230e27c33eab881ed3063fc903a4730 --- /dev/null +++ b/course/migrations/0046_allow_null_page_data_ordinals.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0045_add_course_listed'), + ] + + operations = [ + migrations.AlterField( + model_name='flowpagedata', + name='ordinal', + field=models.IntegerField(null=True, blank=True), + preserve_default=True, + ), + ] diff --git a/course/migrations/0047_remove_page_data_ordinal_uniqueness.py b/course/migrations/0047_remove_page_data_ordinal_uniqueness.py new file mode 100644 index 0000000000000000000000000000000000000000..3c066c10ae8d2768bd55dcfd9f3a73fe3ca34e1b --- /dev/null +++ b/course/migrations/0047_remove_page_data_ordinal_uniqueness.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('course', '0046_allow_null_page_data_ordinals'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='flowpagedata', + unique_together=set([]), + ), + ] diff --git a/course/models.py b/course/models.py index 5fbec6a083c3b7e0c3cd3d5c3b59d0de902f9aa7..94e4c7fab1b09009bc191b31a6e33d45be270960 100644 --- a/course/models.py +++ b/course/models.py @@ -340,7 +340,7 @@ class FlowSession(models.Model): class FlowPageData(models.Model): flow_session = models.ForeignKey(FlowSession, related_name="page_data") - ordinal = models.IntegerField() + ordinal = models.IntegerField(null=True, blank=True) group_id = models.CharField(max_length=200) page_id = models.CharField(max_length=200) @@ -348,7 +348,6 @@ class FlowPageData(models.Model): data = JSONField(null=True, blank=True) class Meta: - unique_together = (("flow_session", "ordinal"),) verbose_name_plural = "flow page data" def __unicode__(self): diff --git a/course/utils.py b/course/utils.py index 5d799ee02c73a945b2fee314efb32e1ee58d34c4..9129985e09b610c3158a8c8306605e8e35230947 100644 --- a/course/utils.py +++ b/course/utils.py @@ -305,6 +305,10 @@ class FlowPageContext(FlowContext): FlowContext.__init__(self, repo, course, flow_identifier, participation, flow_session=flow_session) + from course.content import adjust_flow_session_page_data + adjust_flow_session_page_data(repo, flow_session, + course.identifier, self.flow_desc, self.course_commit_sha) + from course.models import FlowPageData page_data = self.page_data = get_object_or_404( FlowPageData, flow_session=flow_session, ordinal=ordinal)