Skip to content

Commit fcf43b5

Browse files
authored
Merge branch 'main' into SCRUM-31_change_pw
2 parents dcfe016 + 191ad73 commit fcf43b5

5 files changed

+81
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.0.2 on 2024-03-17 14:53
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('api', '0005_remove_course_schedule'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='attendenceacknowledgement',
15+
name='attended_student',
16+
field=models.BooleanField(default=None, null=True),
17+
),
18+
migrations.AlterField(
19+
model_name='attendenceacknowledgement',
20+
name='attended_teacher',
21+
field=models.BooleanField(default=None, null=True),
22+
),
23+
]

api/models.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ def get_teachers(self):
7474
return [uc.user for uc in UserCourse.objects.filter(user__role=AccountRoles.TEACHER)]
7575

7676
def get_lectures(self):
77-
return [lecture for lecture in CourseLecture.objects.filter(course=self)]
77+
return CourseLecture.objects.filter(course=self)
78+
79+
def get_lectures_week(self, year : int, week : int):
80+
return CourseLecture.objects.filter(course=self, start_time__year=year, start_time__week=week)
7881

7982
def is_user_enrolled(self, user : User):
8083
return bool(UserCourse.objects.filter(user=user, course=self))
@@ -99,13 +102,13 @@ class CourseLecture(models.Model):
99102
default=LectureTypes.LECTURE,
100103
)
101104

102-
def set_attendence_user(self, student : User, teacher=False):
105+
def set_attendence_user(self, student : User, attended : bool, teacher=False):
103106
queryset = AttendenceAcknowledgement.objects.filter(lecture=self, student=student)
104107
if not queryset: ack = AttendenceAcknowledgement.objects.create(lecture=self, student=student)
105108
else: ack = queryset[0]
106109

107-
if teacher: ack.attended_teacher = True
108-
else: ack.attended_student = True
110+
if teacher: ack.attended_teacher = attended
111+
else: ack.attended_student = attended
109112
ack.save()
110113

111114
def get_attendence_user(self, student : User):
@@ -117,8 +120,8 @@ def get_attendence(self):
117120
return [] if not queryset else queryset[0]
118121

119122
class AttendenceAcknowledgement(models.Model):
120-
attended_student = models.BooleanField(default=False)
121-
attended_teacher = models.BooleanField(default=False)
123+
attended_student = models.BooleanField(default=None, null=True)
124+
attended_teacher = models.BooleanField(default=None, null=True)
122125
student = models.ForeignKey(User, null=False, related_name='user_ack', on_delete=models.CASCADE)
123126
lecture = models.ForeignKey(CourseLecture, null=False, related_name='lecture_ack', on_delete=models.CASCADE)
124127

api/serializers.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,23 @@ def validate(self, attrs):
123123
return attrs
124124

125125
class SetAttendenceTeacherSerializer(serializers.Serializer):
126-
usernames = serializers.ListField(required=True, allow_empty=False, child=serializers.CharField(max_length=150))
126+
usernames = serializers.DictField(required=True, allow_empty=False, child=
127+
serializers.CharField(max_length=150)
128+
)
127129

128-
def validate_attendence(self, username):
130+
def validate_attendence(self, username, attended):
129131
user_query = User.objects.all().filter(username=username)
132+
if (attended := attended.lower()) not in ["true", "false"]: raise serializers.ValidationError({"error": f"invalid attendence state: '{attended}'"})
130133
if not user_query: raise serializers.ValidationError({"error": f"user '{username}' does not exist"})
131134
if user_query[0].role != AccountRoles.STUDENT: raise serializers.ValidationError({"error": f"cannot set the attendence of a non-student: '{username}' is {user_query[0].role}"})
132135

133136
course : Course = self.context.get("course")
134137
if not course.is_user_enrolled(user_query[0]): raise serializers.ValidationError({"error": f"user '{username}' is not enrolled in '{course.course_name}'"})
135138

136139
def validate(self, attrs):
137-
for username in attrs["usernames"]: self.validate_enroll(username)
140+
for username, attended in attrs["usernames"].items(): self.validate_attendence(username, attended)
138141
return attrs
139142

140143
class MailTestSerializer(serializers.Serializer):
141-
email = serializers.CharField(required=True)
144+
email = serializers.CharField(required=True)
145+

api/urls.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
SetTeacherAttView,
2828
test,
2929
MailTestView,
30+
UnsetStudentAttView,
3031
genAdmin,
3132

3233
GetTokenView,
@@ -83,10 +84,11 @@
8384
# path('course/lecture/<pk>/delete', GetCourseByName.as_view(), name='lecture_add'),
8485

8586
path('lecture/<pk>/get', GetLectureView.as_view(), name='lecture_get'),
86-
path('lecture/<pk>/student_att', SetStudentAttView.as_view(), name='lecture_att_student'),
87+
path('lecture/<pk>/student_set_att', SetStudentAttView.as_view(), name='lecture_set_att_student'),
88+
path('lecture/<pk>/student_unset_att', UnsetStudentAttView.as_view(), name='lecture_unset_att_student'),
8789
path('lecture/<pk>/teacher_att', SetTeacherAttView.as_view(), name='lecture_att_teacher'),
8890

89-
path('schedule/get', GetScheduleView.as_view(), name='schedule_get'),
91+
path('schedule/get/<year>/<week>', GetScheduleView.as_view(), name='schedule_get'),
9092

9193
# Documentation
9294
path('schema/', SpectacularAPIView.as_view(), name='schema'),

api/views.py

+37-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import datetime
22
import os
3+
from typing import List
34
from django.http import JsonResponse
45
from django.contrib.auth import get_user_model
56

@@ -332,6 +333,15 @@ def get(self, _, pk):
332333
serializer = self.serializer_class(queryset[0])
333334
return Response(serializer.data, status=status.HTTP_200_OK)
334335

336+
def setAttendence(self, request, attended):
337+
if request.user.role != AccountRoles.STUDENT:
338+
return Response({"error": f"cannot set the attendence of a non-student"}, status=status.HTTP_200_OK)
339+
340+
lecture : CourseLecture = self.get_object()
341+
lecture.set_attendence_user(request.user, attended=attended, teacher=False)
342+
343+
return Response({"ok": f"successfully set attendence"}, status=status.HTTP_200_OK)
344+
335345
class SetStudentAttView(generics.GenericAPIView):
336346
authentication_classes = [JWTAuthentication]
337347
permission_classes = [IsStudent]
@@ -341,13 +351,19 @@ class SetStudentAttView(generics.GenericAPIView):
341351
serializer_class = CourseLecture
342352

343353
def post(self, request, *args, **kwargs):
344-
if request.user.role != AccountRoles.STUDENT:
345-
return Response({"error": f"cannot set the attendence of a non-student"}, status=status.HTTP_200_OK)
346-
347-
lecture : CourseLecture = self.get_object()
348-
lecture.set_attendence_user(request.user, teacher=False)
354+
return setAttendence(self, request, True)
349355

350-
return Response({"ok": f"successfully set attendence"}, status=status.HTTP_200_OK)
356+
class UnsetStudentAttView(generics.GenericAPIView):
357+
authentication_classes = [JWTAuthentication]
358+
permission_classes = [IsStudent]
359+
lookup_field = 'pk'
360+
361+
queryset = CourseLecture.objects.all()
362+
serializer_class = CourseLecture
363+
364+
def post(self, request, *args, **kwargs):
365+
print(request.user)
366+
return setAttendence(self, request, False)
351367

352368
class SetTeacherAttView(generics.GenericAPIView):
353369
authentication_classes = [JWTAuthentication]
@@ -364,27 +380,34 @@ def post(self, request, *args, **kwargs):
364380

365381
queryset = User.objects.all()
366382
usernames = result.data["usernames"]
367-
for username in usernames:
383+
for username, attended in usernames.items():
368384
user = queryset.filter(username=username)[0]
369-
lecture.set_attendence_user(user, teacher=True)
385+
lecture.set_attendence_user(user, attended=(attended=="true"), teacher=True)
370386

371387
return Response({"ok": f"succesfully set attendence for {len(usernames)} students"}, status=status.HTTP_200_OK)
372388

389+
373390
class GetScheduleView(generics.GenericAPIView):
374391
authentication_classes = [JWTAuthentication]
375392
permission_classes = [IsStudent]
376393

377-
def get(self, request, *args, **kwargs):
394+
def get(self, request, year, week):
395+
if not year.isdigit() or int(year) < 1970:
396+
return Response({"error": f"invalid year parameter"}, status=status.HTTP_400_BAD_REQUEST)
397+
if not week.isdigit() or int(week) < 0 or int(week) > 52:
398+
return Response({"error": f"invalid week parameter"}, status=status.HTTP_400_BAD_REQUEST)
399+
378400
user = User.objects.all().filter(username=request.user.username)[0]
379-
courses = user.get_enrolled_courses()
401+
courses : List[Course] = user.get_enrolled_courses()
380402
all_lectures = []
381-
for course in courses:
382-
lectures_obj = course.get_lectures()
403+
for course in courses:
404+
lectures_obj = course.get_lectures_week(int(year), int(week))
383405
lectures = LectureSerializer(lectures_obj, many=True)
384406
for i, lecture_obj in enumerate(lectures_obj):
385407
att = lecture_obj.get_attendence_user(user)
386-
lectures.data[i]["attended_student"] = att.attended_student if att is not None else False
387-
lectures.data[i]["attended_teacher"] = att.attended_teacher if att is not None else False
408+
lectures.data[i]["course_name"] = lecture_obj.course.course_name
409+
lectures.data[i]["attended_student"] = att.attended_student if att is not None else None
410+
lectures.data[i]["attended_teacher"] = att.attended_teacher if att is not None else None
388411
all_lectures += lectures.data
389412

390413
# Sort chronological order

0 commit comments

Comments
 (0)