diff --git a/client/src/pages/learningPath/circlePage/LearningSequence.vue b/client/src/pages/learningPath/circlePage/LearningSequence.vue index 69798e5a..0eaaba36 100644 --- a/client/src/pages/learningPath/circlePage/LearningSequence.vue +++ b/client/src/pages/learningPath/circlePage/LearningSequence.vue @@ -138,6 +138,7 @@ const learningSequenceBorderClass = computed(() => { value: learningContent.completion_status, checked: learningContent.completion_status === 'SUCCESS', }" + :disabled="!learningContent.can_user_self_toggle_course_completion" :data-cy="`${learningContent.slug}-checkbox`" @toggle="toggleCompleted(learningContent)" /> diff --git a/client/src/types.ts b/client/src/types.ts index aa60c437..b76615fc 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -43,6 +43,7 @@ export interface LearningContentInterface extends BaseCourseWagtailPage { readonly minutes: number; readonly description: string; readonly content_url: string; + readonly can_user_self_toggle_course_completion: boolean; parentCircle: Circle; parentLearningSequence?: LearningSequence; parentLearningUnit?: LearningUnit; diff --git a/server/vbv_lernwelt/competence/migrations/0003_auto_20230626_1747.py b/server/vbv_lernwelt/competence/migrations/0003_auto_20230626_1747.py new file mode 100644 index 00000000..d359769b --- /dev/null +++ b/server/vbv_lernwelt/competence/migrations/0003_auto_20230626_1747.py @@ -0,0 +1,22 @@ +# Generated by Django 3.2.13 on 2023-06-26 15:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("competence", "0002_performancecriteria_learning_unit"), + ] + + operations = [ + migrations.AddField( + model_name="performancecriteria", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="performancecriteria", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + ] diff --git a/server/vbv_lernwelt/competence/models.py b/server/vbv_lernwelt/competence/models.py index 2f64a188..14da06ce 100644 --- a/server/vbv_lernwelt/competence/models.py +++ b/server/vbv_lernwelt/competence/models.py @@ -75,6 +75,8 @@ class PerformanceCriteria(CourseBasePage): blank=True, on_delete=models.SET_NULL, ) + has_course_completion_status = models.BooleanField(default=True) + can_user_self_toggle_course_completion = models.BooleanField(default=True) content_panels = [ FieldPanel("title"), diff --git a/server/vbv_lernwelt/course/services.py b/server/vbv_lernwelt/course/services.py index 6ffa1d95..b26dd882 100644 --- a/server/vbv_lernwelt/course/services.py +++ b/server/vbv_lernwelt/course/services.py @@ -10,7 +10,15 @@ def mark_course_completion( f"Invalid value for CourseCompletionStatus: {completion_status}" ) - # TODO: check if this page can be "marked" by user + if not ( + hasattr(page.specific, "has_course_completion_status") + and page.specific.has_course_completion_status + ): + return ValueError( + f"Page {page.id} of type {get_wagtail_type(page)}" + f" cannot be marked as completed" + ) + cc, created = CourseCompletion.objects.get_or_create( user_id=user.id, page_id=page.id, diff --git a/server/vbv_lernwelt/learnpath/migrations/0008_auto_20230626_1747.py b/server/vbv_lernwelt/learnpath/migrations/0008_auto_20230626_1747.py new file mode 100644 index 00000000..ee442287 --- /dev/null +++ b/server/vbv_lernwelt/learnpath/migrations/0008_auto_20230626_1747.py @@ -0,0 +1,112 @@ +# Generated by Django 3.2.13 on 2023-06-26 15:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("learnpath", "0007_learningunit_title_hidden"), + ] + + operations = [ + migrations.AddField( + model_name="learningcontentassignment", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="learningcontentassignment", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentattendancecourse", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="learningcontentattendancecourse", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentdocumentlist", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentdocumentlist", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentfeedback", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentfeedback", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentlearningmodule", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentlearningmodule", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentmedialibrary", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentmedialibrary", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentplaceholder", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentplaceholder", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentrichtext", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentrichtext", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontenttest", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name="learningcontenttest", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentvideo", + name="can_user_self_toggle_course_completion", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="learningcontentvideo", + name="has_course_completion_status", + field=models.BooleanField(default=True), + ), + ] diff --git a/server/vbv_lernwelt/learnpath/models.py b/server/vbv_lernwelt/learnpath/models.py index 4dc97429..765f5aa9 100644 --- a/server/vbv_lernwelt/learnpath/models.py +++ b/server/vbv_lernwelt/learnpath/models.py @@ -234,17 +234,21 @@ class LearningContent(CourseBasePage): "minutes", "description", "content_url", + "can_user_self_toggle_course_completion", ] minutes = models.PositiveIntegerField(default=15) description = RichTextField(blank=True) content_url = models.TextField(blank=True) + has_course_completion_status = models.BooleanField(default=True) + can_user_self_toggle_course_completion = models.BooleanField(default=False) content_panels = [ FieldPanel("title", classname="full title"), FieldPanel("minutes"), FieldPanel("content_url"), FieldPanel("description"), + FieldPanel("can_user_self_toggle_course_completion"), ] def get_admin_display_title(self): @@ -290,26 +294,31 @@ class LearningContentAttendanceCourse(LearningContent): class LearningContentVideo(LearningContent): parent_page_types = ["learnpath.Circle"] subpage_types = [] + can_user_self_toggle_course_completion = models.BooleanField(default=True) class LearningContentPlaceholder(LearningContent): parent_page_types = ["learnpath.Circle"] subpage_types = [] + can_user_self_toggle_course_completion = models.BooleanField(default=True) class LearningContentFeedback(LearningContent): parent_page_types = ["learnpath.Circle"] subpage_types = [] + can_user_self_toggle_course_completion = models.BooleanField(default=True) class LearningContentLearningModule(LearningContent): parent_page_types = ["learnpath.Circle"] subpage_types = [] + can_user_self_toggle_course_completion = models.BooleanField(default=True) class LearningContentMediaLibrary(LearningContent): parent_page_types = ["learnpath.Circle"] subpage_types = [] + can_user_self_toggle_course_completion = models.BooleanField(default=True) class LearningContentTest(LearningContent): @@ -328,6 +337,7 @@ class LearningContentTest(LearningContent): class LearningContentRichText(LearningContent): text = RichTextField(blank=True, features=DEFAULT_RICH_TEXT_FEATURES_WITH_HEADER) + can_user_self_toggle_course_completion = models.BooleanField(default=True) parent_page_types = ["learnpath.Circle"] serialize_field_names = LearningContent.serialize_field_names + [ @@ -368,6 +378,8 @@ class LearningContentAssignment(LearningContent): class LearningContentDocumentList(LearningContent): + can_user_self_toggle_course_completion = models.BooleanField(default=True) + serialize_field_names = LearningContent.serialize_field_names + [ "documents", ] diff --git a/server/vbv_lernwelt/learnpath/serializers.py b/server/vbv_lernwelt/learnpath/serializers.py index d39bb9fb..42c576c3 100644 --- a/server/vbv_lernwelt/learnpath/serializers.py +++ b/server/vbv_lernwelt/learnpath/serializers.py @@ -10,7 +10,12 @@ from vbv_lernwelt.learnpath.models import LearningUnit class LearningUnitSerializer( get_course_serializer_class( LearningUnit, - field_names=["evaluate_url", "course_category", "children", "title_hidden"], + field_names=[ + "evaluate_url", + "course_category", + "children", + "title_hidden", + ], ) ): evaluate_url = SerializerMethodField()