Skip to content

Commit

Permalink
Add option for users to set personalized points goals for modules
Browse files Browse the repository at this point in the history
  • Loading branch information
mikaelGusse committed Jun 4, 2024
1 parent 1604329 commit 616beb2
Show file tree
Hide file tree
Showing 16 changed files with 231 additions and 8 deletions.
11 changes: 10 additions & 1 deletion course/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from aplus.api import api_reverse
from exercise.models import SubmissionDraft
from lib.fields import UsersSearchSelectField
from .models import Enrollment, StudentGroup
from .models import CourseModule, Enrollment, StudentGroup, StudentModuleGoal
from userprofile.models import UserProfile


Expand Down Expand Up @@ -162,3 +162,12 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
required=False,
label=_('LABEL_ENROLL_FROM_SIS'),
)

class StudentModuleGoalForm(forms.ModelForm):
student = forms.ModelChoiceField(queryset=UserProfile.objects.all())
module = forms.ModelChoiceField(queryset=CourseModule.objects.all())
personalized_points_goal = forms.IntegerField(initial=0)

class Meta:
model = StudentModuleGoal
fields = ['student', 'module', 'personalized_points_goal']
20 changes: 20 additions & 0 deletions course/migrations/0060_coursemodule_personalized_points_goal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.11 on 2024-06-03 11:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("course", "0059_submissiontag"),
]

operations = [
migrations.AddField(
model_name="coursemodule",
name="personalized_points_goal",
field=models.PositiveIntegerField(
default=100, verbose_name="LABEL_PERSONALIZED_POINTS_GOAL"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.11 on 2024-06-03 12:52

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("course", "0060_coursemodule_personalized_points_goal"),
]

operations = [
migrations.RemoveField(
model_name="coursemodule",
name="personalized_points_goal",
),
]
44 changes: 44 additions & 0 deletions course/migrations/0062_studentmodulegoal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.2.11 on 2024-06-03 13:02

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("userprofile", "0008_delete_studentmodulegoal"),
("course", "0061_remove_coursemodule_personalized_points_goal"),
]

operations = [
migrations.CreateModel(
name="StudentModuleGoal",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("personalized_points_goal", models.IntegerField(default=0)),
(
"module",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="course.coursemodule",
),
),
(
"student",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="userprofile.userprofile",
),
),
],
),
]
6 changes: 6 additions & 0 deletions course/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,12 @@ def number_of_submitters(self):
.filter(submissions__exercise__course_module=self).distinct().count()


class StudentModuleGoal(models.Model):
student = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
module = models.ForeignKey(CourseModule, on_delete=models.CASCADE)
personalized_points_goal = models.IntegerField(default=0)


class LearningObjectCategory(models.Model):
"""
Learning objects may be grouped to different categories.
Expand Down
4 changes: 2 additions & 2 deletions course/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
from lib.helpers import settings_text, remove_query_param_from_url, is_ajax
from lib.viewbase import BaseTemplateView, BaseRedirectMixin, BaseFormView, BaseView, BaseRedirectView
from userprofile.viewbase import UserProfileView
from .forms import GroupsForm, GroupSelectForm
from .models import Course, CourseInstance, CourseModule, Enrollment
from .forms import GroupsForm, GroupSelectForm, StudentModuleGoalForm
from .models import Course, CourseInstance, CourseModule, Enrollment, StudentModuleGoal
from .permissions import EnrollInfoVisiblePermission
from .renders import group_info_context
from .viewbase import CourseModuleBaseView, CourseInstanceMixin, EnrollableViewMixin, CourseMixin
Expand Down
20 changes: 20 additions & 0 deletions exercise/migrations/0051_baseexercise_personalized_points_goal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 4.2.11 on 2024-06-03 10:21

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("exercise", "0050_submissiontagging"),
]

operations = [
migrations.AddField(
model_name="baseexercise",
name="personalized_points_goal",
field=models.PositiveIntegerField(
default=100, verbose_name="LABEL_PERSONALIZED_POINTS_GOAL"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.11 on 2024-06-03 11:26

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("exercise", "0051_baseexercise_personalized_points_goal"),
]

operations = [
migrations.RemoveField(
model_name="baseexercise",
name="personalized_points_goal",
),
]
1 change: 1 addition & 0 deletions exercise/templates/exercise/_user_results.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
aria-expanded="{% if accessible and not after_open or open %}true{% else %}false{% endif %}" aria-controls="#module{{ module.id }}">
<h3 class="panel-title">
{% points_badge module "pull-right" %}
POINTS AAAAAH {{ studentmodulegoals }}
{% if not accessible %}
<span class="badge pull-right">
{% translate "OPENS ON" %} {{ module.opening_time }}
Expand Down
5 changes: 5 additions & 0 deletions exercise/templates/exercise/student_module_goal.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
13 changes: 12 additions & 1 deletion exercise/templatetags/exercise.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _

from course.models import CourseInstance, CourseModule
from course.models import CourseInstance, CourseModule, StudentModuleGoal
from lib.errors import TagUsageError
from lib.helpers import format_points as _format_points, is_ajax as _is_ajax
from userprofile.models import UserProfile
Expand All @@ -29,6 +29,9 @@

register = template.Library()

def calculate_personalized_points_goal(student):
# TODO: Implement the logic to calculate the personalized points goal for the given student
return 0

def _prepare_now(context):
if 'now' not in context:
Expand All @@ -49,6 +52,12 @@ def _prepare_context(context: Context, student: Optional[User] = None) -> Cached

context["studentpoints"] = CachedPoints(instance, student, context['is_course_staff'])

# Add personalized_points_goal to the context
if 'personalized_points_goal' not in context:
context["personalized_points_goal"] = StudentModuleGoal.objects.filter(
student=student,
).select_related('personalized_points_goal')

return context["studentpoints"]


Expand Down Expand Up @@ -110,6 +119,7 @@ def user_results(context: Context, student: Optional[User] = None) -> Dict[str,
.order_by()
)
values['exercise_submitter_counts'] = {row['submissions__exercise_id']: row['count'] for row in counts}
print("StudentModuleGoalObjects", StudentModuleGoal.objects.all())
return values


Expand Down Expand Up @@ -200,6 +210,7 @@ def _points_data(
'missing_points': points < required,
'passed': getattr(obj, 'passed', True),
'full_score': points >= max_points,
'personalized_points_goal': getattr(obj, 'personalized_points_goal', 100),
'submitted': getattr(obj, 'submission_count', 0) > 0,
'graded': getattr(obj, 'graded', True),
'unconfirmed': getattr(obj, 'unconfirmed', False),
Expand Down
3 changes: 3 additions & 0 deletions exercise/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
re_path(EDIT_URL_PREFIX + r'results/$',
staff_views.AllResultsView.as_view(),
name="all-results"),
re_path(MODULE_URL_PREFIX + r'student_module_goal/$',
views.StudentModuleGoalView.as_view(),
name="student_module_goal"),
re_path(EDIT_URL_PREFIX + r'analytics/$',
staff_views.AnalyticsView.as_view(),
name="analytics"),
Expand Down
25 changes: 22 additions & 3 deletions exercise/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
from django.db import DatabaseError

from authorization.permissions import ACCESS
from course.models import CourseModule, SubmissionTag
from course.viewbase import CourseInstanceBaseView, EnrollableViewMixin
from course.forms import StudentModuleGoalForm
from course.models import CourseModule, StudentModuleGoal, SubmissionTag
from course.viewbase import CourseInstanceBaseView, CourseModuleBaseView, EnrollableViewMixin
from lib.helpers import query_dict_to_list_of_tuples, safe_file_name, is_ajax
from lib.remote_page import RemotePageNotFound, request_for_response
from lib.viewbase import BaseRedirectMixin, BaseView
from lib.viewbase import BaseFormView, BaseRedirectMixin, BaseView
from userprofile.models import UserProfile
from .cache.points import ExercisePoints
from .models import BaseExercise, LearningObject, LearningObjectDisplay
Expand Down Expand Up @@ -561,3 +562,21 @@ def post(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
self.exercise.set_submission_draft(self.profile, submission_data_list)
# Simple OK response
return HttpResponse()


class StudentModuleGoalView(CourseModuleBaseView, BaseFormView):
access_mode = ACCESS.STUDENT
template_name = "exercise/student_module_goal.html"
form_class = StudentModuleGoalForm

def get_common_objects(self):
super().get_common_objects()

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
return kwargs

def form_valid(self, form):
form.save()
messages.success(self.request, _('MODULE_GOAL_UPDATED'))
return super().form_valid(form)
36 changes: 36 additions & 0 deletions userprofile/migrations/0007_studentmodulegoal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 4.2.11 on 2024-06-03 12:52

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("userprofile", "0006_auto_20210812_1536"),
]

operations = [
migrations.CreateModel(
name="StudentModuleGoal",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("personalized_points_goal", models.IntegerField(default=0)),
(
"student",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="userprofile.userprofile",
),
),
],
),
]
16 changes: 16 additions & 0 deletions userprofile/migrations/0008_delete_studentmodulegoal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 4.2.11 on 2024-06-03 13:02

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("userprofile", "0007_studentmodulegoal"),
]

operations = [
migrations.DeleteModel(
name="StudentModuleGoal",
),
]
1 change: 0 additions & 1 deletion userprofile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ def create_user_profile(sender, instance, created, **kwargs): # pylint: disable=
# Attach to the post_save signal.
post_save.connect(create_user_profile, sender=User)


class GraderUser(AnonymousUser):
def __init__(self, username: str, permissions: ObjectPermissions, **extra: Any):
self.username = username
Expand Down

0 comments on commit 616beb2

Please sign in to comment.