feat: [AXM-200] Implement user's enrolments status API (#2530)
* feat: [AXM-24] Update structure for course enrollments API (#2515)
* feat: [AXM-24] Update structure for course enrollments API
* style: [AXM-24] Improve code style
* fix: [AXM-24] Fix student's latest enrollment filter
* feat: [AXM-47] Add course_status field to primary object (#2517)
* feat: [AXM-40] add courses progress to enrollment endpoint (#2519)
* fix: workaround for staticcollection introduced in e40a01c
* feat: [AXM-40] add courses progress to enrollment endpoint
* refactor: [AXM-40] add caching to improve performance
* refactor: [AXM-40] add progress only for primary course
* refactor: [AXM-40] refactor enrollment caching optimization
---------
Co-authored-by: Glib Glugovskiy <glib.glugovskiy@raccoongang.com>
* feat: [AXM-53] add assertions for primary course (#2522)
* feat: [AXM-53] add assertions for primary course
* test: [AXM-53] fix tests
* style: [AXM-53] change future_assignment default value to None
* refactor: [AXM-53] add some optimization for assignments collecting
* feat: [AXM-200] Implement user's enrolments status API
* style: [AXM-200] Improve code style
* refactor: [AXM-200] Divide get method into smaller methods
---------
Co-authored-by: NiedielnitsevIvan <81557788+NiedielnitsevIvan@users.noreply.github.com>
Co-authored-by: Glib Glugovskiy <glib.glugovskiy@raccoongang.com>
This commit is contained in:
@@ -3,9 +3,13 @@ Views for user API
|
||||
"""
|
||||
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import pytz
|
||||
from completion.exceptions import UnavailableCompletionData
|
||||
from completion.models import BlockCompletion
|
||||
from completion.utilities import get_key_to_last_completed_block
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
@@ -410,3 +414,128 @@ def my_user_info(request, api_version):
|
||||
# updating it from the oauth2 related code is too complex
|
||||
user_logged_in.send(sender=User, user=request.user, request=request)
|
||||
return redirect("user-detail", api_version=api_version, username=request.user.username)
|
||||
|
||||
|
||||
class UserCourseEnrollmentsV4Pagination(DefaultPagination):
|
||||
"""
|
||||
Pagination for `UserCourseEnrollments` API v4.
|
||||
"""
|
||||
page_size = 5
|
||||
max_page_size = 50
|
||||
|
||||
|
||||
@mobile_view(is_user=True)
|
||||
class UserEnrollmentsStatus(views.APIView):
|
||||
"""
|
||||
**Use Case**
|
||||
|
||||
Get information about user's enrolments status.
|
||||
|
||||
Returns active enrolment status if user was enrolled for the course
|
||||
less than 30 days ago or has progressed in the course in the last 30 days.
|
||||
Otherwise, the registration is considered inactive.
|
||||
|
||||
**Example Request**
|
||||
|
||||
GET /api/mobile/{api_version}/users/<user_name>/enrollments_status/
|
||||
|
||||
**Response Values**
|
||||
|
||||
If the request for information about the user's enrolments is successful, the
|
||||
request returns an HTTP 200 "OK" response.
|
||||
|
||||
The HTTP 200 response has the following values.
|
||||
|
||||
* course_id (str): The course id associated with the user's enrollment.
|
||||
* course_name (str): The course name associated with the user's enrollment.
|
||||
* is_active (bool): User's course enrolment status.
|
||||
|
||||
|
||||
The HTTP 200 response contains a list of dictionaries that contain info
|
||||
about each user's enrolment status.
|
||||
|
||||
**Example Response**
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"course_id": "course-v1:a+a+a",
|
||||
"course_name": "a",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"course_id": "course-v1:b+b+b",
|
||||
"course_name": "b",
|
||||
"is_active": true
|
||||
},
|
||||
{
|
||||
"course_id": "course-v1:c+c+c",
|
||||
"course_name": "c",
|
||||
"is_active": false
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
"""
|
||||
def get(self, request, *args, **kwargs) -> Response:
|
||||
"""
|
||||
Gets user's enrollments status.
|
||||
"""
|
||||
active_status_date = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=30)
|
||||
username = kwargs.get('username')
|
||||
course_ids_where_user_has_completions = self._get_course_ids_where_user_has_completions(
|
||||
username,
|
||||
active_status_date,
|
||||
)
|
||||
enrollments_status = self._build_enrollments_status_dict(
|
||||
username,
|
||||
active_status_date,
|
||||
course_ids_where_user_has_completions
|
||||
)
|
||||
return Response(enrollments_status)
|
||||
|
||||
def _build_enrollments_status_dict(
|
||||
self,
|
||||
username: str,
|
||||
active_status_date: datetime,
|
||||
course_ids: List[str],
|
||||
) -> List[Dict[str, bool]]:
|
||||
"""
|
||||
Builds list with dictionaries with user's enrolments statuses.
|
||||
"""
|
||||
user_enrollments = CourseEnrollment.objects.filter(
|
||||
user__username=username,
|
||||
is_active=True,
|
||||
)
|
||||
mobile_available = [
|
||||
enrollment for enrollment in user_enrollments
|
||||
if is_mobile_available_for_user(self.request.user, enrollment.course_overview)
|
||||
]
|
||||
enrollments_status = []
|
||||
for user_enrollment in mobile_available:
|
||||
course_id = str(user_enrollment.course_overview.id)
|
||||
enrollments_status.append(
|
||||
{
|
||||
'course_id': course_id,
|
||||
'course_name': user_enrollment.course_overview.display_name,
|
||||
'is_active': bool(
|
||||
course_id in course_ids
|
||||
or user_enrollment.created > active_status_date
|
||||
)
|
||||
}
|
||||
)
|
||||
return enrollments_status
|
||||
|
||||
@staticmethod
|
||||
def _get_course_ids_where_user_has_completions(
|
||||
username: str,
|
||||
active_status_date: datetime,
|
||||
) -> List[str]:
|
||||
"""
|
||||
Gets course ids where user has completions.
|
||||
"""
|
||||
user_completions_last_month = BlockCompletion.objects.filter(
|
||||
user__username=username,
|
||||
created__gte=active_status_date
|
||||
)
|
||||
return [str(completion.block_key.course_key) for completion in user_completions_last_month]
|
||||
|
||||
Reference in New Issue
Block a user