From a9a623971fe745b37a5f136364f7bc1f0ff7f528 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Thu, 11 Apr 2024 01:02:27 -0700 Subject: [PATCH 01/14] Added a update_sections endpoint using action decorator. added basic validation of course sections and sections passed. --- app/serializers/course_member.py | 2 +- app/views/course_member.py | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/app/serializers/course_member.py b/app/serializers/course_member.py index 962b7f0..94262c7 100644 --- a/app/serializers/course_member.py +++ b/app/serializers/course_member.py @@ -19,5 +19,5 @@ class CourseMemberSerializer(serializers.ModelSerializer): sections = SectionSerializer(many=True, read_only=True) class Meta: - model = CourseMember + model = CourseMember fields = "__all__" diff --git a/app/views/course_member.py b/app/views/course_member.py index b0d890f..288023b 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -2,10 +2,17 @@ from app.models.course_member import CourseMember from app.paginators.pagination import ExamplePagination +from app.models.section import Section +from app.models.course import Course from app.filters.course_member import FilterStudents from app.serializers.course_member import CourseMemberSerializer +from app.serializers.section import SectionSerializer from rest_framework.response import Response +from rest_framework.decorators import action +from rest_framework import status + +from django.shortcuts import get_object_or_404 class CourseMemberViewSet(viewsets.ModelViewSet): @@ -30,3 +37,33 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): else: serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) + + def fetch_course_sections(self, course_id): + course = get_object_or_404(Course, pk=course_id) + sections = course.sections.all() + serializer = SectionSerializer(sections, many=True) + return serializer.data + + @action(detail=True, methods=["put"], url_path="update-sections") + def update_sections(self, request, *args, **kwargs): + course_member = self.get_object() + section_ids = request.data.get("sections") + + if section_ids is None: + return Response({"message": "Sections are required."}, status=status.HTTP_400_BAD_REQUEST) + if not isinstance(section_ids, list): + return Response({"message": "Sections must be a list."}, status=status.HTTP_400_BAD_REQUEST) + try: + section_ids = [int(section_id) for section_id in section_ids] + except ValueError: + return Response({"message": "Sections must be integers."}, status=status.HTTP_400_BAD_REQUEST) + + course_sections = self.fetch_course_sections(course_member.course.id) + valid_section_ids = {section["id"] for section in course_sections} + + if not set(section_ids).issubset(valid_section_ids): + return Response({"message": "One or more sections are not part of the course."}, status=status.HTTP_400_BAD_REQUEST) + + proposed_new_sections = Section.objects.filter(id__in=section_ids) + course_member.sections.set(proposed_new_sections) + return Response({"message": "Sections updated successfully."}, status=status.HTTP_200_OK) From 876ca21437d8864b9da61c355a716a5ec41ad6e5 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Thu, 11 Apr 2024 01:05:27 -0700 Subject: [PATCH 02/14] linted --- app/serializers/course_member.py | 2 +- app/views/course_member.py | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/serializers/course_member.py b/app/serializers/course_member.py index 94262c7..962b7f0 100644 --- a/app/serializers/course_member.py +++ b/app/serializers/course_member.py @@ -19,5 +19,5 @@ class CourseMemberSerializer(serializers.ModelSerializer): sections = SectionSerializer(many=True, read_only=True) class Meta: - model = CourseMember + model = CourseMember fields = "__all__" diff --git a/app/views/course_member.py b/app/views/course_member.py index 288023b..0a53be5 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -37,7 +37,7 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): else: serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) - + def fetch_course_sections(self, course_id): course = get_object_or_404(Course, pk=course_id) sections = course.sections.all() @@ -50,20 +50,34 @@ def update_sections(self, request, *args, **kwargs): section_ids = request.data.get("sections") if section_ids is None: - return Response({"message": "Sections are required."}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"message": "Sections are required."}, + status=status.HTTP_400_BAD_REQUEST, + ) if not isinstance(section_ids, list): - return Response({"message": "Sections must be a list."}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"message": "Sections must be a list."}, + status=status.HTTP_400_BAD_REQUEST, + ) try: section_ids = [int(section_id) for section_id in section_ids] except ValueError: - return Response({"message": "Sections must be integers."}, status=status.HTTP_400_BAD_REQUEST) - + return Response( + {"message": "Sections must be integers."}, + status=status.HTTP_400_BAD_REQUEST, + ) + course_sections = self.fetch_course_sections(course_member.course.id) valid_section_ids = {section["id"] for section in course_sections} if not set(section_ids).issubset(valid_section_ids): - return Response({"message": "One or more sections are not part of the course."}, status=status.HTTP_400_BAD_REQUEST) + return Response( + {"message": "One or more sections are not part of the course."}, + status=status.HTTP_400_BAD_REQUEST, + ) proposed_new_sections = Section.objects.filter(id__in=section_ids) - course_member.sections.set(proposed_new_sections) - return Response({"message": "Sections updated successfully."}, status=status.HTTP_200_OK) + course_member.sections.set(proposed_new_sections) + return Response( + {"message": "Sections updated successfully."}, status=status.HTTP_200_OK + ) From de462bab49506ff2f192fe05cd69b5408008e8ce Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Thu, 11 Apr 2024 15:16:34 -0700 Subject: [PATCH 03/14] Still needs to pivot to using Schema/Pydantic library --- app/views/course_member.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index 0a53be5..b5fbd76 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -38,17 +38,17 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) - def fetch_course_sections(self, course_id): - course = get_object_or_404(Course, pk=course_id) - sections = course.sections.all() - serializer = SectionSerializer(sections, many=True) - return serializer.data - @action(detail=True, methods=["put"], url_path="update-sections") def update_sections(self, request, *args, **kwargs): course_member = self.get_object() + section_ids = request.data.get("sections") + if course_member.role != CourseMember.STUDENT: + return Response( + {"message": "Only students can be assigned to sections."}, + status=status.HTTP_400_BAD_REQUEST, + ) if section_ids is None: return Response( {"message": "Sections are required."}, @@ -67,17 +67,14 @@ def update_sections(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST, ) - course_sections = self.fetch_course_sections(course_member.course.id) - valid_section_ids = {section["id"] for section in course_sections} - - if not set(section_ids).issubset(valid_section_ids): + attempted_sections_returned = Section.objects.filter(id__in=section_ids) + if len(attempted_sections_returned) != len(section_ids): return Response( - {"message": "One or more sections are not part of the course."}, + {"message": "One or more sections do not exist."}, status=status.HTTP_400_BAD_REQUEST, ) - proposed_new_sections = Section.objects.filter(id__in=section_ids) - course_member.sections.set(proposed_new_sections) - return Response( - {"message": "Sections updated successfully."}, status=status.HTTP_200_OK - ) + proposed_sections_update = Section.objects.filter(id__in=section_ids) + course_member.sections.set(proposed_sections_update) + serializer = self.get_serializer(course_member) + return Response(serializer.data) From b00a5291533b624395079193471399a6f3f5bb9e Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Thu, 11 Apr 2024 15:34:20 -0700 Subject: [PATCH 04/14] made endpoint return updated instance --- app/views/course_member.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index b5fbd76..d7f1b8a 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -1,9 +1,8 @@ from rest_framework import viewsets -from app.models.course_member import CourseMember +from app.models.course_member import CourseMember, UserRole from app.paginators.pagination import ExamplePagination from app.models.section import Section -from app.models.course import Course from app.filters.course_member import FilterStudents from app.serializers.course_member import CourseMemberSerializer from app.serializers.section import SectionSerializer @@ -44,7 +43,7 @@ def update_sections(self, request, *args, **kwargs): section_ids = request.data.get("sections") - if course_member.role != CourseMember.STUDENT: + if course_member.role != UserRole.STUDENT: return Response( {"message": "Only students can be assigned to sections."}, status=status.HTTP_400_BAD_REQUEST, From 52e77774da6b68b3149c68ce3a476aeac186a205 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Fri, 12 Apr 2024 23:19:44 -0700 Subject: [PATCH 05/14] created serializer to validate the sections field in course-members/update-sections --- app/serializers/student_sections_update.py | 27 +++++++++++++ app/views/course_member.py | 46 ++++++++-------------- 2 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 app/serializers/student_sections_update.py diff --git a/app/serializers/student_sections_update.py b/app/serializers/student_sections_update.py new file mode 100644 index 0000000..8f0dbe5 --- /dev/null +++ b/app/serializers/student_sections_update.py @@ -0,0 +1,27 @@ +from rest_framework import serializers +from app.models.section import Section +from app.models.course import Course # Assuming you have a Course model + +class StudentSectionsUpdateSerializer(serializers.Serializer): + sections = serializers.ListField( + child=serializers.IntegerField(), + required=True, + error_messages={"required": "Sections is required.", "invalid": "Sections must be a list of integers."}, + ) + + def validate_sections(self, value): + if not all(isinstance(section_id, int) for section_id in value): + raise serializers.ValidationError("Sections must be a list of integers.") + + course = self.context.get('course') + + course_sections_ids = Section.objects.filter(course=course).values_list('id', flat=True) + if not all(section_id in course_sections_ids for section_id in value): + raise serializers.ValidationError("One or more sections do not exist or are not part of the course.") + return value + + def update(self, instance, validated_data): + section_ids = validated_data["sections"] + sections = Section.objects.filter(id__in=section_ids) + instance.sections.set(sections) + return instance diff --git a/app/views/course_member.py b/app/views/course_member.py index d7f1b8a..5b57875 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -5,13 +5,14 @@ from app.models.section import Section from app.filters.course_member import FilterStudents from app.serializers.course_member import CourseMemberSerializer -from app.serializers.section import SectionSerializer +from app.serializers.student_sections_update import StudentSectionsUpdateSerializer from rest_framework.response import Response from rest_framework.decorators import action from rest_framework import status from django.shortcuts import get_object_or_404 +from django.db import transaction class CourseMemberViewSet(viewsets.ModelViewSet): @@ -38,42 +39,27 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): return Response(serializer.data) @action(detail=True, methods=["put"], url_path="update-sections") + @transaction.atomic def update_sections(self, request, *args, **kwargs): course_member = self.get_object() - section_ids = request.data.get("sections") - if course_member.role != UserRole.STUDENT: return Response( {"message": "Only students can be assigned to sections."}, status=status.HTTP_400_BAD_REQUEST, ) - if section_ids is None: - return Response( - {"message": "Sections are required."}, - status=status.HTTP_400_BAD_REQUEST, - ) - if not isinstance(section_ids, list): - return Response( - {"message": "Sections must be a list."}, - status=status.HTTP_400_BAD_REQUEST, - ) - try: - section_ids = [int(section_id) for section_id in section_ids] - except ValueError: - return Response( - {"message": "Sections must be integers."}, - status=status.HTTP_400_BAD_REQUEST, - ) - attempted_sections_returned = Section.objects.filter(id__in=section_ids) - if len(attempted_sections_returned) != len(section_ids): - return Response( - {"message": "One or more sections do not exist."}, - status=status.HTTP_400_BAD_REQUEST, - ) + serializer = StudentSectionsUpdateSerializer( + instance=course_member, + data=request.data, + context={"course": course_member.course}, + ) + serializer.is_valid(raise_exception=True) + if serializer.is_valid(raise_exception=True): + section_ids = serializer.validated_data["sections"] + proposed_sections_update = Section.objects.filter(id__in=section_ids) + course_member.sections.set(proposed_sections_update) + course_member.save() - proposed_sections_update = Section.objects.filter(id__in=section_ids) - course_member.sections.set(proposed_sections_update) - serializer = self.get_serializer(course_member) - return Response(serializer.data) + return_course_member_serializer = self.get_serializer(course_member) + return Response(return_course_member_serializer.data) From b19d0ffea414523cfee3453b7d5da6fcb05be935 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Fri, 12 Apr 2024 23:20:57 -0700 Subject: [PATCH 06/14] lint --- app/serializers/student_sections_update.py | 16 ++++++++++++---- app/views/course_member.py | 8 ++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/serializers/student_sections_update.py b/app/serializers/student_sections_update.py index 8f0dbe5..140f0fb 100644 --- a/app/serializers/student_sections_update.py +++ b/app/serializers/student_sections_update.py @@ -2,22 +2,30 @@ from app.models.section import Section from app.models.course import Course # Assuming you have a Course model + class StudentSectionsUpdateSerializer(serializers.Serializer): sections = serializers.ListField( child=serializers.IntegerField(), required=True, - error_messages={"required": "Sections is required.", "invalid": "Sections must be a list of integers."}, + error_messages={ + "required": "Sections is required.", + "invalid": "Sections must be a list of integers.", + }, ) def validate_sections(self, value): if not all(isinstance(section_id, int) for section_id in value): raise serializers.ValidationError("Sections must be a list of integers.") - course = self.context.get('course') + course = self.context.get("course") - course_sections_ids = Section.objects.filter(course=course).values_list('id', flat=True) + course_sections_ids = Section.objects.filter(course=course).values_list( + "id", flat=True + ) if not all(section_id in course_sections_ids for section_id in value): - raise serializers.ValidationError("One or more sections do not exist or are not part of the course.") + raise serializers.ValidationError( + "One or more sections do not exist or are not part of the course." + ) return value def update(self, instance, validated_data): diff --git a/app/views/course_member.py b/app/views/course_member.py index 5b57875..f99eeaa 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -56,10 +56,10 @@ def update_sections(self, request, *args, **kwargs): ) serializer.is_valid(raise_exception=True) if serializer.is_valid(raise_exception=True): - section_ids = serializer.validated_data["sections"] - proposed_sections_update = Section.objects.filter(id__in=section_ids) - course_member.sections.set(proposed_sections_update) - course_member.save() + section_ids = serializer.validated_data["sections"] + proposed_sections_update = Section.objects.filter(id__in=section_ids) + course_member.sections.set(proposed_sections_update) + course_member.save() return_course_member_serializer = self.get_serializer(course_member) return Response(return_course_member_serializer.data) From 587368222162885fb78f483d28b39eb3644a0bd2 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Sat, 13 Apr 2024 13:33:22 -0700 Subject: [PATCH 07/14] Moved serializer for endpoint into course_member.py. Removed dead code/function. Address nit. --- app/serializers/course_member.py | 22 +++++++++++++++++++++- app/views/course_member.py | 12 +++++------- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/serializers/course_member.py b/app/serializers/course_member.py index 962b7f0..0387c8e 100644 --- a/app/serializers/course_member.py +++ b/app/serializers/course_member.py @@ -5,6 +5,7 @@ from app.serializers.attribute import AttributeResponseSerializer from app.serializers.relationship import RelationshipSerializer from app.serializers.section import SectionSerializer +from app.models.section import Section class CourseMemberSerializer(serializers.ModelSerializer): @@ -17,7 +18,26 @@ class CourseMemberSerializer(serializers.ModelSerializer): user = MyUserSerializer(read_only=True) sections = SectionSerializer(many=True, read_only=True) - class Meta: model = CourseMember fields = "__all__" + +class UpdateStudentSectionsRequest(serializers.Serializer): + sections = serializers.ListField( + child=serializers.IntegerField(), + required=True, + error_messages={ + "required": "Sections is required.", + "invalid": "Sections must be a list of integers.", + }, + ) + + def validate_sections(self, value): + course = self.context.get("course") + sections_passed_in = set(value) + course_sections_ids = Section.objects.filter(course=course, id__in = sections_passed_in) + if len(sections_passed_in) != course_sections_ids.count(): + raise serializers.ValidationError( + "One or more sections do not exist or are not part of the course." + ) + return value \ No newline at end of file diff --git a/app/views/course_member.py b/app/views/course_member.py index f99eeaa..b07936d 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -4,8 +4,7 @@ from app.paginators.pagination import ExamplePagination from app.models.section import Section from app.filters.course_member import FilterStudents -from app.serializers.course_member import CourseMemberSerializer -from app.serializers.student_sections_update import StudentSectionsUpdateSerializer +from app.serializers.course_member import CourseMemberSerializer, UpdateStudentSectionsRequest from rest_framework.response import Response from rest_framework.decorators import action @@ -49,15 +48,14 @@ def update_sections(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST, ) - serializer = StudentSectionsUpdateSerializer( + StudentSectionsRequestSerializer = UpdateStudentSectionsRequest( instance=course_member, data=request.data, context={"course": course_member.course}, ) - serializer.is_valid(raise_exception=True) - if serializer.is_valid(raise_exception=True): - section_ids = serializer.validated_data["sections"] - proposed_sections_update = Section.objects.filter(id__in=section_ids) + if StudentSectionsRequestSerializer.is_valid(raise_exception=True): + section_ids = StudentSectionsRequestSerializer.get("sections") + proposed_sections_update = Section.objects.filter(id__in=section_ids, course=course_member.course) course_member.sections.set(proposed_sections_update) course_member.save() From c896a42b5fe0e3e08d3dc440bdb091a306c8263a Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Sat, 13 Apr 2024 13:38:54 -0700 Subject: [PATCH 08/14] Changed back from using .get() --- app/views/course_member.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index b07936d..7286c2e 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -54,7 +54,7 @@ def update_sections(self, request, *args, **kwargs): context={"course": course_member.course}, ) if StudentSectionsRequestSerializer.is_valid(raise_exception=True): - section_ids = StudentSectionsRequestSerializer.get("sections") + section_ids = StudentSectionsRequestSerializer._validated_data["sections"] proposed_sections_update = Section.objects.filter(id__in=section_ids, course=course_member.course) course_member.sections.set(proposed_sections_update) course_member.save() From 6084a3491b4f61777b6ed2135b91136ff4a772f7 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Sat, 13 Apr 2024 22:29:00 -0700 Subject: [PATCH 09/14] linted, cleaned up code. --- app/serializers/course_member.py | 8 +++-- app/serializers/student_sections_update.py | 35 ---------------------- app/views/course_member.py | 13 ++++++-- 3 files changed, 16 insertions(+), 40 deletions(-) delete mode 100644 app/serializers/student_sections_update.py diff --git a/app/serializers/course_member.py b/app/serializers/course_member.py index 0387c8e..24f1d43 100644 --- a/app/serializers/course_member.py +++ b/app/serializers/course_member.py @@ -18,10 +18,12 @@ class CourseMemberSerializer(serializers.ModelSerializer): user = MyUserSerializer(read_only=True) sections = SectionSerializer(many=True, read_only=True) + class Meta: model = CourseMember fields = "__all__" + class UpdateStudentSectionsRequest(serializers.Serializer): sections = serializers.ListField( child=serializers.IntegerField(), @@ -35,9 +37,11 @@ class UpdateStudentSectionsRequest(serializers.Serializer): def validate_sections(self, value): course = self.context.get("course") sections_passed_in = set(value) - course_sections_ids = Section.objects.filter(course=course, id__in = sections_passed_in) + course_sections_ids = Section.objects.filter( + course=course, id__in=sections_passed_in + ) if len(sections_passed_in) != course_sections_ids.count(): raise serializers.ValidationError( "One or more sections do not exist or are not part of the course." ) - return value \ No newline at end of file + return value diff --git a/app/serializers/student_sections_update.py b/app/serializers/student_sections_update.py deleted file mode 100644 index 140f0fb..0000000 --- a/app/serializers/student_sections_update.py +++ /dev/null @@ -1,35 +0,0 @@ -from rest_framework import serializers -from app.models.section import Section -from app.models.course import Course # Assuming you have a Course model - - -class StudentSectionsUpdateSerializer(serializers.Serializer): - sections = serializers.ListField( - child=serializers.IntegerField(), - required=True, - error_messages={ - "required": "Sections is required.", - "invalid": "Sections must be a list of integers.", - }, - ) - - def validate_sections(self, value): - if not all(isinstance(section_id, int) for section_id in value): - raise serializers.ValidationError("Sections must be a list of integers.") - - course = self.context.get("course") - - course_sections_ids = Section.objects.filter(course=course).values_list( - "id", flat=True - ) - if not all(section_id in course_sections_ids for section_id in value): - raise serializers.ValidationError( - "One or more sections do not exist or are not part of the course." - ) - return value - - def update(self, instance, validated_data): - section_ids = validated_data["sections"] - sections = Section.objects.filter(id__in=section_ids) - instance.sections.set(sections) - return instance diff --git a/app/views/course_member.py b/app/views/course_member.py index 7286c2e..1b75812 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -4,7 +4,10 @@ from app.paginators.pagination import ExamplePagination from app.models.section import Section from app.filters.course_member import FilterStudents -from app.serializers.course_member import CourseMemberSerializer, UpdateStudentSectionsRequest +from app.serializers.course_member import ( + CourseMemberSerializer, + UpdateStudentSectionsRequest, +) from rest_framework.response import Response from rest_framework.decorators import action @@ -54,8 +57,12 @@ def update_sections(self, request, *args, **kwargs): context={"course": course_member.course}, ) if StudentSectionsRequestSerializer.is_valid(raise_exception=True): - section_ids = StudentSectionsRequestSerializer._validated_data["sections"] - proposed_sections_update = Section.objects.filter(id__in=section_ids, course=course_member.course) + section_ids = StudentSectionsRequestSerializer._validated_data.get( + "sections" + ) + proposed_sections_update = Section.objects.filter( + id__in=section_ids, course=course_member.course + ) course_member.sections.set(proposed_sections_update) course_member.save() From e08f477bb67af91c70cefebd6399ab1774866918 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Sat, 13 Apr 2024 22:34:33 -0700 Subject: [PATCH 10/14] remove dead import --- app/views/course_member.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index 1b75812..ab87efe 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -13,7 +13,6 @@ from rest_framework.decorators import action from rest_framework import status -from django.shortcuts import get_object_or_404 from django.db import transaction From 391a6c934c0e76fdcff114baaa2add7784a4af68 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Sat, 20 Apr 2024 13:53:00 -0700 Subject: [PATCH 11/14] pushing old commits --- app/views/course_member.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index ab87efe..d0d55d5 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -50,20 +50,19 @@ def update_sections(self, request, *args, **kwargs): status=status.HTTP_400_BAD_REQUEST, ) - StudentSectionsRequestSerializer = UpdateStudentSectionsRequest( + request_body_serializer = UpdateStudentSectionsRequest( instance=course_member, data=request.data, context={"course": course_member.course}, ) - if StudentSectionsRequestSerializer.is_valid(raise_exception=True): - section_ids = StudentSectionsRequestSerializer._validated_data.get( - "sections" - ) + if request_body_serializer.is_valid(raise_exception=True): + section_ids = request_body_serializer._validated_data.get("sections") + print(section_ids) proposed_sections_update = Section.objects.filter( id__in=section_ids, course=course_member.course ) course_member.sections.set(proposed_sections_update) course_member.save() - return_course_member_serializer = self.get_serializer(course_member) - return Response(return_course_member_serializer.data) + response_course_member_serializer = self.get_serializer(course_member) + return Response(response_course_member_serializer.data) From 61a02aa90fbceb6152bf810ba0d1f0e569a8af01 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Mon, 6 May 2024 23:42:02 -0700 Subject: [PATCH 12/14] clean up endpoint as requested --- app/serializers/course_member.py | 1 - app/views/course_member.py | 65 +++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/app/serializers/course_member.py b/app/serializers/course_member.py index 24f1d43..bb962a1 100644 --- a/app/serializers/course_member.py +++ b/app/serializers/course_member.py @@ -30,7 +30,6 @@ class UpdateStudentSectionsRequest(serializers.Serializer): required=True, error_messages={ "required": "Sections is required.", - "invalid": "Sections must be a list of integers.", }, ) diff --git a/app/views/course_member.py b/app/views/course_member.py index d0d55d5..077095e 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -14,6 +14,8 @@ from rest_framework import status from django.db import transaction +from django.core.exceptions import ValidationError +from rest_framework.exceptions import APIException class CourseMemberViewSet(viewsets.ModelViewSet): @@ -39,30 +41,51 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) + def update_sections_exception_handler(self, exc): + errors = [] + if isinstance(exc, APIException): + if isinstance(exc.detail, dict): + for field, error_list in exc.detail.items(): + for error in error_list: + errors.append({"message": str(error)}) + else: + errors.append({"message": exc.detail}) + if isinstance(exc, ValidationError): + for field, error_list in exc.detail.items(): + for error in error_list: + errors.append({"message": str(error)}) + response = Response({"errors": errors}, status=status.HTTP_400_BAD_REQUEST) + return response + @action(detail=True, methods=["put"], url_path="update-sections") @transaction.atomic def update_sections(self, request, *args, **kwargs): - course_member = self.get_object() + try: + course_member = self.get_object() - if course_member.role != UserRole.STUDENT: - return Response( - {"message": "Only students can be assigned to sections."}, - status=status.HTTP_400_BAD_REQUEST, - ) + if course_member.role != UserRole.STUDENT: + return Response( + { + "errors": { + "message": "Only students can be assigned to sections." + } + }, + status=status.HTTP_400_BAD_REQUEST, + ) - request_body_serializer = UpdateStudentSectionsRequest( - instance=course_member, - data=request.data, - context={"course": course_member.course}, - ) - if request_body_serializer.is_valid(raise_exception=True): - section_ids = request_body_serializer._validated_data.get("sections") - print(section_ids) - proposed_sections_update = Section.objects.filter( - id__in=section_ids, course=course_member.course + request_body_serializer = UpdateStudentSectionsRequest( + instance=course_member, + data=request.data, + context={"course": course_member.course}, ) - course_member.sections.set(proposed_sections_update) - course_member.save() - - response_course_member_serializer = self.get_serializer(course_member) - return Response(response_course_member_serializer.data) + if request_body_serializer.is_valid(raise_exception=True): + section_ids = request_body_serializer._validated_data.get("sections") + proposed_sections_update = Section.objects.filter( + id__in=section_ids, course=course_member.course + ) + course_member.sections.set(proposed_sections_update) + course_member.save() + response_course_member_serializer = self.get_serializer(course_member) + return Response(response_course_member_serializer.data) + except Exception as e: + return self.update_sections_exception_handler(e) From 8f8f7c617e2d1736d3829534712bd2e48b00913c Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Fri, 10 May 2024 20:54:20 -0700 Subject: [PATCH 13/14] Removed the unneccessary exception handler function. Logic now in the exception block. --- app/views/course_member.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index 077095e..f05af7f 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -41,22 +41,6 @@ def get_students_by_course(self, request, course=None, *args, **kwargs): serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) - def update_sections_exception_handler(self, exc): - errors = [] - if isinstance(exc, APIException): - if isinstance(exc.detail, dict): - for field, error_list in exc.detail.items(): - for error in error_list: - errors.append({"message": str(error)}) - else: - errors.append({"message": exc.detail}) - if isinstance(exc, ValidationError): - for field, error_list in exc.detail.items(): - for error in error_list: - errors.append({"message": str(error)}) - response = Response({"errors": errors}, status=status.HTTP_400_BAD_REQUEST) - return response - @action(detail=True, methods=["put"], url_path="update-sections") @transaction.atomic def update_sections(self, request, *args, **kwargs): @@ -87,5 +71,19 @@ def update_sections(self, request, *args, **kwargs): course_member.save() response_course_member_serializer = self.get_serializer(course_member) return Response(response_course_member_serializer.data) - except Exception as e: - return self.update_sections_exception_handler(e) + + except Exception as exc: + errors = [] + if isinstance(exc, APIException): + if isinstance(exc.detail, dict): + for field, error_list in exc.detail.items(): + for error in error_list: + errors.append({"message": str(error)}) + else: + errors.append({"message": exc.detail}) + if isinstance(exc, ValidationError): + for field, error_list in exc.detail.items(): + for error in error_list: + errors.append({"message": str(error)}) + response = Response({"errors": errors}, status=status.HTTP_400_BAD_REQUEST) + return response From 44836e8b6bdf3067912952dbdd730ea6eacb14c3 Mon Sep 17 00:00:00 2001 From: Abhinav Thota Date: Fri, 10 May 2024 20:57:33 -0700 Subject: [PATCH 14/14] lint. --- app/views/course_member.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/course_member.py b/app/views/course_member.py index f05af7f..8be2c34 100644 --- a/app/views/course_member.py +++ b/app/views/course_member.py @@ -71,7 +71,7 @@ def update_sections(self, request, *args, **kwargs): course_member.save() response_course_member_serializer = self.get_serializer(course_member) return Response(response_course_member_serializer.data) - + except Exception as exc: errors = [] if isinstance(exc, APIException):