Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main to side #28

Merged
merged 3 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class AddLectureSerializer(serializers.Serializer):
start_time = serializers.DateTimeField(required=True)
end_time = serializers.DateTimeField(required=True)
lecture_type = serializers.CharField(required=True)
lecture_series = serializers.BooleanField(default=False)

def validate(self, attrs):
start_time, end_time = attrs["start_time"], attrs["end_time"]
Expand Down
8 changes: 6 additions & 2 deletions api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from django_rest_passwordreset.views import ResetPasswordConfirm, ResetPasswordValidateToken
from .views import (
AddLectureView,
DestroyLectureView,
DisenrollCourseView,
GetCourseLecturesView,
GetFullCoursePage,
Expand Down Expand Up @@ -76,23 +77,26 @@
path('course/update/<pk>', UpdateCourseView.as_view(), name='course_update'),
path('course/delete/<pk>', DestroyCourseView.as_view(), name='course_delete'),
path('course/enroll/<pk>', EnrollCourseView.as_view(), name='course_enroll'),
path('course/disenroll/<pk>', DisenrollCourseView.as_view(), name='course_enroll'),
path('course/enroll/<pk>/<username>', EnrollCourseView.as_view(), name='course_enroll_username'),
path('course/disenroll/<pk>', DisenrollCourseView.as_view(), name='course_disenroll'),
path('course/disenroll/<pk>/<username>', DisenrollCourseView.as_view(), name='course_disenroll_username'),
path('course/mass_enroll/<pk>', MassEnrollCourseView.as_view(), name='course_mass_enroll'),
path('course/get/<pk>', GetFullCoursePage.as_view(), name='course_get'),
path('course/getall/', GetCoursesAll.as_view(), name='course_getall'),


path('course/lecture/<pk>/get', GetCourseLecturesView.as_view(), name='course_get_lecture'),
path('course/lecture/<pk>/add', AddLectureView.as_view(), name='course_add_lecture'),
path('course/lecture/<pk>/delete', DestroyLectureView.as_view(), name='course_lecture_delete'),
# path('course/lecture/<pk>/update', GetCourseByName.as_view(), name='lecture_add'), # TODO
# path('course/lecture/<pk>/delete', GetCourseByName.as_view(), name='lecture_add'),

path('lecture/<pk>/get', GetLectureView.as_view(), name='lecture_get'),
path('lecture/<pk>/student_set_att', SetStudentAttView.as_view(), name='lecture_set_att_student'),
path('lecture/<pk>/student_unset_att', UnsetStudentAttView.as_view(), name='lecture_unset_att_student'),
path('lecture/<pk>/teacher_att', SetTeacherAttView.as_view(), name='lecture_att_teacher'),

path('schedule/get/<year>/<week>', GetScheduleView.as_view(), name='schedule_get'),
path('schedule/get/<year>/<week>/<course_id>', GetScheduleView.as_view(), name='schedule_get'),

# Documentation
path('schema/', SpectacularAPIView.as_view(), name='schema'),
Expand Down
80 changes: 65 additions & 15 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ def get(self, request):
for course_serialized in serializer.data:
course : Course = queryset.filter(pk=course_serialized["id"])[0]
course_serialized["enrolled"] = course.is_user_enrolled(user=request.user)
course_serialized["num_students"] = len(course.get_enrolled_students())
course_serialized["num_teachers"] = len(course.get_teachers())

return Response(serializer.data, status=status.HTTP_200_OK)

class EnrollCourseView(generics.GenericAPIView):
Expand All @@ -288,15 +291,23 @@ class EnrollCourseView(generics.GenericAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer

def post(self, request, *args, **kwargs):
if request.user.role == AccountRoles.ADMIN:
def post(self, request, username=None, *args, **kwargs):
if username is not None:
if user.role != AccountRoles.ADMIN:
return Response({"error": f"unauthorized"}, status=status.HTTP_401_UNAUTHORIZED)
queryset = User.objects.all().filter(username=username)
if not queryset:
return Response({"error": f"{username} is not a valid user"}, status=status.HTTP_400_BAD_REQUEST)
user = queryset[0]
else:
user = request.user
username = user.username

if user.role == AccountRoles.ADMIN:
return Response({"error": f"cannot enroll an admin account into a course"}, status=status.HTTP_400_BAD_REQUEST)

obj : Course = self.get_object()
user = request.user
username = user.username

if obj.is_user_enrolled(request.user):
if obj.is_user_enrolled(user):
return Response({"error": f"{username} is already enrolled in {obj.course_name}"}, status=status.HTTP_400_BAD_REQUEST)

obj.add_user_to_course(user)
Expand All @@ -314,12 +325,20 @@ class DisenrollCourseView(generics.GenericAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer

def post(self, request, *args, **kwargs):
obj : Course = self.get_object()
user = request.user
username = user.username
def post(self, request, username=None, *args, **kwargs):
if username is not None:
if request.user.role != AccountRoles.ADMIN:
return Response({"error": f"unauthorized"}, status=status.HTTP_401_UNAUTHORIZED)
queryset = User.objects.all().filter(username=username)
if not queryset:
return Response({"error": f"{username} is not a valid user"}, status=status.HTTP_400_BAD_REQUEST)
user = queryset[0]
else:
user = request.user
username = user.username

if not obj.is_user_enrolled(request.user):
obj : Course = self.get_object()
if not obj.is_user_enrolled(user):
return Response({"error": f"{username} is not enrolled in {obj.course_name}"}, status=status.HTTP_400_BAD_REQUEST)

obj.remove_user_from_course(user)
Expand Down Expand Up @@ -376,6 +395,8 @@ class AddLectureView(generics.GenericAPIView):
queryset = Course.objects.all()
serializer_class = CourseSerializer

holiday_weeks = [1, 8, 18, 29, 30, 31, 32, 33, 34, 42, 52]

def post(self, request, *args, **kwargs):
course : Course = self.get_object()
result = AddLectureSerializer(data=request.data, context={ "course": course })
Expand All @@ -384,10 +405,32 @@ def post(self, request, *args, **kwargs):
data = result.data
start_time = datetime.datetime.fromisoformat(data["start_time"])
end_time = datetime.datetime.fromisoformat(data["end_time"])
course.add_lecture_to_course(start_time, end_time, data["lecture_type"])

if not data["lecture_series"]:
course.add_lecture_to_course(start_time, end_time, data["lecture_type"])
else:
curr_week = start_time.strftime("%W")
exclude_weeks = list(self.holiday_weeks)
if curr_week in exclude_weeks: exclude_weeks.remove(curr_week)

start_string = start_time.strftime("%Y %a %H %M %S ")
end_string = end_time.strftime("%Y %a %H %M %S ")
for i in range(1, 53):
if i in exclude_weeks: continue
new_start = datetime.datetime.strptime(start_string + str(i), "%Y %a %H %M %S %W")
new_end = datetime.datetime.strptime(end_string + str(i), "%Y %a %H %M %S %W")
course.add_lecture_to_course(new_start, new_end, data["lecture_type"])

return Response({"ok": f"successfully created lecture"}, status=status.HTTP_200_OK)

class DestroyLectureView(generics.DestroyAPIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsTeacher]
lookup_field = 'pk'

queryset = CourseLecture.objects.all()
serializer_class = LectureSerializer

class GetLectureView(generics.RetrieveAPIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsStudent]
Expand Down Expand Up @@ -431,7 +474,6 @@ class UnsetStudentAttView(generics.GenericAPIView):
serializer_class = CourseLecture

def post(self, request, *args, **kwargs):
print(request.user)
return setAttendence(self, request, False)

class SetTeacherAttView(generics.GenericAPIView):
Expand Down Expand Up @@ -460,14 +502,22 @@ class GetScheduleView(generics.GenericAPIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsStudent]

def get(self, request, year, week):
def get(self, request, year, week, course_id=None):
if not year.isdigit() or int(year) < 1970:
return Response({"error": f"invalid year parameter"}, status=status.HTTP_400_BAD_REQUEST)
if not week.isdigit() or int(week) < 0 or int(week) > 52:
return Response({"error": f"invalid week parameter"}, status=status.HTTP_400_BAD_REQUEST)

user = User.objects.all().filter(username=request.user.username)[0]
courses : List[Course] = user.get_enrolled_courses()

if course_id is None:
courses : List[Course] = user.get_enrolled_courses()
else:
queryset = Course.objects.all().filter(pk=course_id)
if not queryset:
return Response({"error": f"course ID is not valid"}, status=status.HTTP_400_BAD_REQUEST)
courses : List[Course] = [queryset[0]]

all_lectures = []
for course in courses:
lectures_obj = course.get_lectures_week(int(year), int(week))
Expand Down
Loading