|
10 | 10 | from opaque_keys.edx.keys import CourseKey |
11 | 11 | from requests.exceptions import HTTPError |
12 | 12 | from rest_framework.permissions import IsAuthenticated |
13 | | -from rest_framework.status import HTTP_406_NOT_ACCEPTABLE, HTTP_409_CONFLICT |
| 13 | +from rest_framework.status import HTTP_406_NOT_ACCEPTABLE, HTTP_409_CONFLICT, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN |
14 | 14 | from rest_framework.views import APIView |
15 | 15 |
|
16 | 16 | from common.djangoapps.course_modes.models import CourseMode |
17 | 17 | from common.djangoapps.entitlements.models import CourseEntitlement |
18 | | -from common.djangoapps.student.models import CourseEnrollment |
| 18 | +from common.djangoapps.student.models import CourseEnrollment, EnrollmentNotAllowed |
19 | 19 | from common.djangoapps.util.json_request import JsonResponse |
20 | 20 | from lms.djangoapps.courseware import courses |
21 | 21 | from openedx.core.djangoapps.commerce.utils import get_ecommerce_api_base_url, get_ecommerce_api_client |
22 | 22 | from openedx.core.djangoapps.embargo import api as embargo_api |
23 | 23 | from openedx.core.djangoapps.enrollments.api import add_enrollment |
| 24 | +from openedx.core.djangoapps.enrollments.errors import InvalidEnrollmentAttribute |
24 | 25 | from openedx.core.djangoapps.enrollments.views import EnrollmentCrossDomainSessionAuth |
25 | 26 | from openedx.core.djangoapps.user_api.preferences.api import update_email_opt_in |
26 | 27 | from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser |
@@ -149,14 +150,53 @@ def post(self, request, *args, **kwargs): # lint-amnesty, pylint: disable=unuse |
149 | 150 | announcement=course_announcement |
150 | 151 | ) |
151 | 152 | log.info(msg) |
152 | | - self._enroll(course_key, user, default_enrollment_mode.slug) |
| 153 | + |
| 154 | + try: |
| 155 | + self._enroll(course_key, user, default_enrollment_mode.slug) |
| 156 | + except InvalidEnrollmentAttribute as e: |
| 157 | + # Exception handling for InvalidEnrollmentAttribute |
| 158 | + return self._handle_enrollment_error( |
| 159 | + e, |
| 160 | + user, |
| 161 | + course_id, |
| 162 | + "Invalid enrollment attribute ", |
| 163 | + HTTP_400_BAD_REQUEST |
| 164 | + ) |
| 165 | + except EnrollmentNotAllowed as e: |
| 166 | + # Exception handling for EnrollmentNotAllowed |
| 167 | + return self._handle_enrollment_error( |
| 168 | + e, |
| 169 | + user, |
| 170 | + course_id, |
| 171 | + "Enrollment not allowed ", |
| 172 | + HTTP_403_FORBIDDEN |
| 173 | + ) |
| 174 | + |
153 | 175 | mode = CourseMode.AUDIT if audit_mode else CourseMode.HONOR # lint-amnesty, pylint: disable=unused-variable |
154 | 176 | self._handle_marketing_opt_in(request, course_key, user) |
155 | 177 | return DetailResponse(msg) |
156 | 178 | else: |
157 | 179 | msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=course_id) |
158 | 180 | return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE) |
159 | 181 |
|
| 182 | + def _handle_enrollment_error(self, exception, user, course_id, log_message, status_code): |
| 183 | + """ |
| 184 | + Helper function to handle enrollment exceptions. |
| 185 | +
|
| 186 | + Args: |
| 187 | + exception (Exception): The exception raised. |
| 188 | + user (User): The user attempting to enroll. |
| 189 | + course_id (str): The course ID. |
| 190 | + log_message (str): The log message template. |
| 191 | + status_code (int): The HTTP status code to return. |
| 192 | +
|
| 193 | + Returns: |
| 194 | + DetailResponse: The response with the error message and status code. |
| 195 | + """ |
| 196 | + log.exception(log_message, str(exception)) |
| 197 | + error_msg = f"{log_message.format(str(exception))} for user {user.username} in course {course_id}: {str(exception)}" # lint-amnesty, pylint: disable=line-too-long |
| 198 | + return DetailResponse(error_msg, status=status_code) |
| 199 | + |
160 | 200 |
|
161 | 201 | class BasketOrderView(APIView): |
162 | 202 | """ |
|
0 commit comments