From f71e2e6ff39cdede44eb6c5027608deca89eb09c Mon Sep 17 00:00:00 2001 From: Daniel Egger Date: Tue, 21 May 2024 16:56:04 +0200 Subject: [PATCH] Propagate "deducted" fields via API --- .../vbv_lernwelt/assignment/graphql/types.py | 9 +++++ ...ntcompletion_evaluation_points_deducted.py | 18 ---------- .../0014_evaluation_points_deducted.py | 31 +++++++++++++++++ server/vbv_lernwelt/assignment/models.py | 34 +++++++++++++++++-- server/vbv_lernwelt/assignment/serializers.py | 2 ++ server/vbv_lernwelt/assignment/services.py | 8 ++--- .../course/creators/test_course.py | 2 ++ 7 files changed, 78 insertions(+), 26 deletions(-) delete mode 100644 server/vbv_lernwelt/assignment/migrations/0014_assignmentcompletion_evaluation_points_deducted.py create mode 100644 server/vbv_lernwelt/assignment/migrations/0014_evaluation_points_deducted.py diff --git a/server/vbv_lernwelt/assignment/graphql/types.py b/server/vbv_lernwelt/assignment/graphql/types.py index 612cb83b..fa29bdc9 100644 --- a/server/vbv_lernwelt/assignment/graphql/types.py +++ b/server/vbv_lernwelt/assignment/graphql/types.py @@ -19,6 +19,7 @@ class AssignmentCompletionObjectType(DjangoObjectType): # rounded to sensible representation evaluation_points = graphene.Float() + evaluation_points_final = graphene.Float() evaluation_max_points = graphene.Float() class Meta: @@ -38,6 +39,9 @@ class AssignmentCompletionObjectType(DjangoObjectType): "evaluation_user", "additional_json_data", "edoniq_extended_time_flag", + "evaluation_points_deducted", + "evaluation_points_deducted_reason", + "evaluation_points_deducted_user", "evaluation_passed", "task_completion_data", ) @@ -47,6 +51,11 @@ class AssignmentCompletionObjectType(DjangoObjectType): return round(self.evaluation_points, 1) # noqa return None + def resolve_evaluation_points_final(self, info): + if self.evaluation_points: + return round(self.evaluation_points_final, 1) # noqa + return None + def resolve_evaluation_max_points(self, info): if self.evaluation_max_points: return round(self.evaluation_max_points, 1) # noqa diff --git a/server/vbv_lernwelt/assignment/migrations/0014_assignmentcompletion_evaluation_points_deducted.py b/server/vbv_lernwelt/assignment/migrations/0014_assignmentcompletion_evaluation_points_deducted.py deleted file mode 100644 index fa92117b..00000000 --- a/server/vbv_lernwelt/assignment/migrations/0014_assignmentcompletion_evaluation_points_deducted.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 3.2.20 on 2024-05-21 13:43 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assignment', '0013_assignment_competence_certificate_weight'), - ] - - operations = [ - migrations.AddField( - model_name='assignmentcompletion', - name='evaluation_points_deducted', - field=models.FloatField(default=0.0, verbose_name='Punkteabzug'), - ), - ] diff --git a/server/vbv_lernwelt/assignment/migrations/0014_evaluation_points_deducted.py b/server/vbv_lernwelt/assignment/migrations/0014_evaluation_points_deducted.py new file mode 100644 index 00000000..e2407765 --- /dev/null +++ b/server/vbv_lernwelt/assignment/migrations/0014_evaluation_points_deducted.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.20 on 2024-05-21 14:52 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('assignment', '0013_assignment_competence_certificate_weight'), + ] + + operations = [ + migrations.AddField( + model_name='assignmentcompletion', + name='evaluation_points_deducted', + field=models.FloatField(default=0.0, verbose_name='Punkteabzug'), + ), + migrations.AddField( + model_name='assignmentcompletion', + name='evaluation_points_deducted_reason', + field=models.TextField(blank=True, default='', verbose_name='Punkteabzug Begründung'), + ), + migrations.AddField( + model_name='assignmentcompletion', + name='evaluation_points_deducted_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/server/vbv_lernwelt/assignment/models.py b/server/vbv_lernwelt/assignment/models.py index 758e10bf..e3a0118a 100644 --- a/server/vbv_lernwelt/assignment/models.py +++ b/server/vbv_lernwelt/assignment/models.py @@ -343,14 +343,26 @@ class AssignmentCompletion(models.Model): evaluation_points_deducted = models.FloatField( default=0.0, verbose_name="Punkteabzug" ) + evaluation_points_deducted_reason = models.TextField( + default="", blank=True, verbose_name="Punkteabzug Begründung" + ) + evaluation_points_deducted_user = models.ForeignKey( + User, + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="+", + ) + evaluation_max_points = models.FloatField(null=True, blank=True) evaluation_passed = models.BooleanField(null=True, blank=True) edoniq_extended_time_flag = models.BooleanField(default=False) @property def evaluation_points_final(self): - # with Django>=5 it can be replaced with a `GeneratedField` - return (self.evaluation_points or 0.0) - self.evaluation_points_deducted + if self.evaluation_points is None: + return None + return self.evaluation_points - self.evaluation_points_deducted assignment_user = models.ForeignKey(User, on_delete=models.CASCADE) assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE) @@ -399,6 +411,14 @@ class AssignmentCompletion(models.Model): data[task.id] = get_task_data(task, self.completion_data) return data + def save( + self, + **kwargs, + ): + if self.evaluation_points_deducted > 0: + recalculate_assignment_passed(self) + super().save(**kwargs) + def get_file_info(file_id): file_info = UploadFile.objects.filter(id=file_id).first() @@ -456,3 +476,13 @@ class AssignmentCompletionAuditLog(models.Model): evaluation_points = models.FloatField(null=True, blank=True) evaluation_max_points = models.FloatField(null=True, blank=True) evaluation_passed = models.BooleanField(null=True, blank=True) + + +def recalculate_assignment_passed(ac: AssignmentCompletion): + if ac.evaluation_points_final is not None and ac.evaluation_max_points is not None: + # if more or equal than 55% of the points are reached, the assignment is passed + ac.evaluation_passed = ( + ac.evaluation_points_final / ac.evaluation_max_points + ) >= 0.55 + + return ac diff --git a/server/vbv_lernwelt/assignment/serializers.py b/server/vbv_lernwelt/assignment/serializers.py index 746aa6c2..18d27044 100644 --- a/server/vbv_lernwelt/assignment/serializers.py +++ b/server/vbv_lernwelt/assignment/serializers.py @@ -21,6 +21,8 @@ class AssignmentCompletionSerializer(serializers.ModelSerializer): "evaluation_user", "additional_json_data", "evaluation_points", + "evaluation_points_deducted", + "evaluation_points_deducted_reason", "evaluation_max_points", "evaluation_passed", ] diff --git a/server/vbv_lernwelt/assignment/services.py b/server/vbv_lernwelt/assignment/services.py index 5598305c..7b441d8e 100644 --- a/server/vbv_lernwelt/assignment/services.py +++ b/server/vbv_lernwelt/assignment/services.py @@ -10,7 +10,7 @@ from vbv_lernwelt.assignment.models import ( AssignmentCompletionAuditLog, AssignmentCompletionStatus, AssignmentType, - is_valid_assignment_completion_status, + is_valid_assignment_completion_status, recalculate_assignment_passed, ) from vbv_lernwelt.core.models import User from vbv_lernwelt.core.utils import find_first @@ -146,11 +146,7 @@ def update_assignment_completion( # if no evaluation_passed is provided, we calculate it from the points if evaluation_passed is None and ac.evaluation_max_points > 0: - if evaluation_points is not None and ac.evaluation_max_points is not None: - # if more or equal than 60% of the points are reached, the assignment is passed - ac.evaluation_passed = ( - evaluation_points / ac.evaluation_max_points - ) >= 0.55 + recalculate_assignment_passed(ac) else: ac.evaluation_passed = evaluation_passed diff --git a/server/vbv_lernwelt/course/creators/test_course.py b/server/vbv_lernwelt/course/creators/test_course.py index 90f58254..aca34760 100644 --- a/server/vbv_lernwelt/course/creators/test_course.py +++ b/server/vbv_lernwelt/course/creators/test_course.py @@ -403,6 +403,7 @@ def create_test_assignment_evaluation_data( # take the last input score as deduction if there is one left... if points_deducted > 0: ac.evaluation_points_deducted = points_deducted + ac.evaluation_points_deducted_reason = "Assignment Punkteabug Test" ac.save() @@ -433,6 +434,7 @@ def create_edoniq_test_result_data( if evaluation_points_deducted > 0: ac.evaluation_points_deducted = evaluation_points_deducted + ac.evaluation_points_deducted_reason = "Edoniq Punkteabug Test" ac.save()