|
17 | 17 | from urllib.parse import urlparse |
18 | 18 | from pydantic import ValidationError |
19 | 19 | from enum import StrEnum |
| 20 | +from django_email_learning.services.command_models.enroll_command import EnrollCommand |
| 21 | +from django_email_learning.services.command_models.verify_enrollment_command import ( |
| 22 | + VerifyEnrollmentCommand, |
| 23 | +) |
| 24 | +from django_email_learning.services.command_models.exceptions.blocked_email_error import ( |
| 25 | + BlockedEmailError, |
| 26 | +) |
| 27 | +from django_email_learning.services.command_models.exceptions.enrollment_already_exists_error import ( |
| 28 | + EnrollmentAlreadyExistsError, |
| 29 | +) |
20 | 30 | from django_email_learning.platform.api import serializers |
21 | 31 | from django_email_learning.platform.api.pagniated_api_mixin import PaginatedApiMixin |
22 | 32 | from django_email_learning.models import ( |
@@ -763,6 +773,50 @@ def get(self, request, *args, **kwargs) -> JsonResponse: # type: ignore[no-unty |
763 | 773 | return JsonResponse({"error": "An internal error occurred."}, status=500) |
764 | 774 |
|
765 | 775 |
|
| 776 | +@method_decorator(accessible_for(roles={"admin"}), name="post") |
| 777 | +class EnrollmentsView(PaginatedApiMixin, View): |
| 778 | + def post(self, request, *args, **kwargs) -> JsonResponse: # type: ignore[no-untyped-def] |
| 779 | + payload = json.loads(request.body) |
| 780 | + try: |
| 781 | + serializer = serializers.CreateEnrollmentRequest.model_validate(payload) |
| 782 | + try: |
| 783 | + course = Course.objects.get( |
| 784 | + id=kwargs["course_id"], organization_id=kwargs["organization_id"] |
| 785 | + ) |
| 786 | + except Course.DoesNotExist: |
| 787 | + return JsonResponse({"error": "Course not found"}, status=404) |
| 788 | + command = EnrollCommand( |
| 789 | + email=serializer.learner_email, |
| 790 | + course_slug=course.slug, |
| 791 | + organization_id=kwargs["organization_id"], |
| 792 | + no_verification=True, # skip verification email for manual enrollments through the API |
| 793 | + ) |
| 794 | + try: |
| 795 | + command.execute() |
| 796 | + except BlockedEmailError as e: |
| 797 | + return JsonResponse({"error": str(e)}, status=403) |
| 798 | + except EnrollmentAlreadyExistsError as e: |
| 799 | + return JsonResponse({"error": str(e)}, status=409) |
| 800 | + |
| 801 | + enrollment = Enrollment.objects.get( |
| 802 | + learner__email=serializer.learner_email, course_id=kwargs["course_id"] |
| 803 | + ) |
| 804 | + verify_command = VerifyEnrollmentCommand( |
| 805 | + enrollment_id=enrollment.id, |
| 806 | + verification_code=enrollment.activation_code, # type: ignore[arg-type] |
| 807 | + ) |
| 808 | + verify_command.execute() |
| 809 | + enrollment.refresh_from_db() |
| 810 | + return JsonResponse( |
| 811 | + serializers.EnrollmentResponse.from_django_model( |
| 812 | + enrollment |
| 813 | + ).model_dump(), |
| 814 | + status=201, |
| 815 | + ) |
| 816 | + except ValidationError as e: |
| 817 | + return JsonResponse({"error": e.json()}, status=400) |
| 818 | + |
| 819 | + |
766 | 820 | @method_decorator(accessible_for(roles={"admin", "editor", "viewer"}), name="get") |
767 | 821 | class EnrollmentView(View): |
768 | 822 | def get(self, request, *args, **kwargs) -> JsonResponse: # type: ignore[no-untyped-def] |
|
0 commit comments