Thursday, January 11, 2024

Changes to student registration and database change

Testing the register-student API endpoint brought out a few changes and also made me think about how this registration needs to be handled to include a few more details.

To begin with, only a student logged in with an active account should be able to register for courses. So this means any API requests without credentials or with credentials of an inactive user should not be allowed. 

user = self.authenticate(request, check_admin=False)
if user is not None:
    course_obj = self.get_object()
    course_obj.add_students(user)
    return Response(
        data=CourseSerializer(
            user.course_set.all(),
            many=True
        ).data
    )
else:
    return Response(
        data='Must be logged in to register for course',
        status=status.HTTP_403_FORBIDDEN
    )

Before, the response was outside the if check whether user is not None. This would throw a 400 error as then I was accessing course_set of user which is None. The else condition handles this case specifically.

In the case of an inactive account, it is handled by the authenticate function which is an extension of the authenticate method provided by JWTAuthentication. If the user is inactive, it raises an exception. This exception seems generic and is difficult to catch in a specific except block. Rather than let the authenticate method raise an exception, for now, it seems better to let it return None if a valid user is not found.

def authenticate(self, request,
                check_admin=True,
                *args, **kwargs
    ):
    try:
        user = super().authenticate(
            request,
            *args,
            **kwargs
        )
        if user is not None:
            if check_admin and not user[0].is_staff:
                return None
            request.user = user[0]
            return user[0]
    except Exception as e:
        pass
    return None

For now, an exception is not thrown, but I could later throw a UserForbiddenException if necessary - something that can be explicitly caught in the view method.

Coming to the next topic - how should additional details be handled in student registration? These details include the time and date of registration, the price paid, the actual price (in case of discount applied) and also any association (such as a group in the case of group study). Django handles ManyToMany fields using a through table. Found a nice blog post on this:

https://www.sankalpjonna.com/learn-django/the-right-way-to-use-a-manytomanyfield-in-django 

All that needs to be done is to specify this through table explicitly with the additional fields. For now it will only be the time of registration and the price.

No comments:

Post a Comment