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

✨(backend) add admin Enrollment api endpoint #700

Merged
merged 8 commits into from
Mar 25, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to

## Added

- Add admin Enrollment endpoint
- Add tabs layout on back offices forms
- Filter admin resources list through their pk
- Allow backoffice to generate certificate if order is eligible
Expand Down
3 changes: 3 additions & 0 deletions src/backend/joanie/admin_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
)
admin_router.register("users", api_admin.UserViewSet, basename="admin_user")
admin_router.register("orders", api_admin.OrderViewSet, basename="admin_orders")
admin_router.register(
"enrollments", api_admin.EnrollmentViewSet, basename="admin_enrollments"
)

# Admin API routes nested under a course
admin_course_related_router = DefaultRouter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from joanie.core.authentication import SessionAuthenticationWithAuthenticateHeader
from joanie.core.exceptions import CertificateGenerationError

from .enrollment import EnrollmentViewSet


# pylint: disable=too-many-ancestors
class OrganizationViewSet(viewsets.ModelViewSet):
Expand Down
41 changes: 41 additions & 0 deletions src/backend/joanie/core/api/admin/enrollment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
Admin API Enrollment Endpoints
"""

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import (
mixins,
permissions,
viewsets,
)
from rest_framework.filters import OrderingFilter

from joanie.core import filters, models, serializers
from joanie.core.api.base import SerializerPerActionMixin
from joanie.core.authentication import SessionAuthenticationWithAuthenticateHeader


# pylint: disable=too-many-ancestors
class EnrollmentViewSet(
SerializerPerActionMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
viewsets.GenericViewSet,
):
"""
Admin Enrollment ViewSet
"""

authentication_classes = [SessionAuthenticationWithAuthenticateHeader]
permission_classes = [permissions.IsAdminUser & permissions.DjangoModelPermissions]
serializer_classes = {
"list": serializers.AdminEnrollmentLightSerializer,
}
default_serializer_class = serializers.AdminEnrollmentSerializer
queryset = models.Enrollment.objects.all().select_related(
"course_run", "course_run__course", "user", "certificate"
)
filterset_class = filters.EnrollmentAdminFilterSet
filter_backends = [DjangoFilterBackend, OrderingFilter]
ordering_fields = ["created_on"]
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
from joanie.core import enums, models
from joanie.core.filters.base import MultipleValueFilter

from .enrollment import EnrollmentAdminFilterSet


class OrganizationAdminFilterSet(filters.FilterSet):
"""
Expand Down
51 changes: 51 additions & 0 deletions src/backend/joanie/core/filters/admin/enrollment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""
Admin Enrollment API Resource Filters
"""

from typing import List

from django.db.models import Q
from django.forms import fields

from django_filters import rest_framework as filters

from joanie.core import enums, models
from joanie.core.filters.base import MultipleValueFilter


class EnrollmentAdminFilterSet(filters.FilterSet):
"""
EnrollmentAdminFilterSet allows to filter this resource
through a full search text query, course_run_ids, user_ids, ids, active state
and state.
"""

class Meta:
model = models.Enrollment
fields: List[str] = ["query"]

query = filters.CharFilter(method="filter_by_query")
course_run_ids = filters.ModelMultipleChoiceFilter(
queryset=models.CourseRun.objects.all().only("pk"),
field_name="course_run",
distinct=True,
)
user_ids = filters.ModelMultipleChoiceFilter(
queryset=models.User.objects.all().only("pk"),
field_name="user",
distinct=True,
)
ids = MultipleValueFilter(field_class=fields.UUIDField, field_name="id")
is_active = filters.BooleanFilter()
state = filters.ChoiceFilter(choices=enums.ENROLLMENT_STATE_CHOICES)

def filter_by_query(self, queryset, _name, value):
"""
Filter resource by looking for title which contains provided value in
"query" query parameter.
"""
return queryset.filter(
Q(course_run__translations__title__icontains=value)
| Q(course_run__resource_link__icontains=value)
| Q(course_run__course__code__icontains=value)
).distinct()
61 changes: 61 additions & 0 deletions src/backend/joanie/core/serializers/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -1094,3 +1094,64 @@ def get_owner_name(self, instance) -> str:
otherwise fallback to the username
"""
return instance.owner.get_full_name() or instance.owner.username


class AdminEnrollmentLightSerializer(serializers.ModelSerializer):
jbpenrath marked this conversation as resolved.
Show resolved Hide resolved
"""
Light Serializer for Enrollment model
"""

course_run = AdminCourseRunLightSerializer(read_only=True)
user_name = serializers.SerializerMethodField(read_only=True)

class Meta:
model = models.Enrollment
fields = [
"id",
"course_run",
"user_name",
"state",
"is_active",
]
read_only_fields = fields

def get_user_name(self, instance) -> str:
"""
Return the full name of the enrollment's user if available,
otherwise fallback to the username
"""
return instance.user.get_full_name() or instance.user.username


class AdminEnrollmentSerializer(serializers.ModelSerializer):
jbpenrath marked this conversation as resolved.
Show resolved Hide resolved
"""
Serializer for Enrollment model
"""

course_run = AdminCourseRunLightSerializer(read_only=True)
user = AdminUserSerializer(read_only=True)
certificate = AdminCertificateSerializer(read_only=True)

class Meta:
model = models.Enrollment
fields = [
"course_run",
"created_on",
"certificate",
"id",
"is_active",
"state",
"updated_on",
"user",
"was_created_by_order",
]
read_only_fields = [
"course_run",
"created_on",
"certificate",
"id",
"state",
"updated_on",
"user",
"was_created_by_order",
]
Loading