edx-enterprise-data 9.0.1__py3-none-any.whl → 9.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/METADATA +1 -1
- {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/RECORD +22 -23
- enterprise_data/__init__.py +1 -1
- enterprise_data/admin_analytics/constants.py +0 -16
- enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +90 -0
- enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +83 -4
- enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +116 -0
- enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +97 -3
- enterprise_data/api/v1/serializers.py +1 -55
- enterprise_data/api/v1/urls.py +14 -17
- enterprise_data/api/v1/views/analytics_completions.py +150 -0
- enterprise_data/api/v1/views/analytics_engagements.py +106 -351
- enterprise_data/api/v1/views/analytics_enrollments.py +3 -6
- enterprise_data/renderers.py +22 -7
- enterprise_data/tests/admin_analytics/mock_analytics_data.py +12 -90
- enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -66
- enterprise_data/tests/admin_analytics/test_analytics_engagements.py +120 -240
- enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +12 -81
- enterprise_data/tests/admin_analytics/test_enterprise_completions.py +105 -120
- enterprise_data/admin_analytics/completions_utils.py +0 -261
- enterprise_data/api/v1/views/enterprise_completions.py +0 -200
- {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/LICENSE +0 -0
- {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-9.0.1.dist-info → edx_enterprise_data-9.1.0.dist-info}/top_level.txt +0 -0
enterprise_data/api/v1/urls.py
CHANGED
@@ -8,13 +8,10 @@ from rest_framework.routers import DefaultRouter
|
|
8
8
|
from django.urls import re_path
|
9
9
|
|
10
10
|
from enterprise_data.api.v1.views import enterprise_admin as enterprise_admin_views
|
11
|
-
from enterprise_data.api.v1.views import enterprise_completions as enterprise_completions_views
|
12
11
|
from enterprise_data.api.v1.views import enterprise_learner as enterprise_learner_views
|
13
12
|
from enterprise_data.api.v1.views import enterprise_offers as enterprise_offers_views
|
14
|
-
from enterprise_data.api.v1.views.
|
15
|
-
|
16
|
-
AdvanceAnalyticsIndividualEngagementsView,
|
17
|
-
)
|
13
|
+
from enterprise_data.api.v1.views.analytics_completions import AdvanceAnalyticsCompletionsView
|
14
|
+
from enterprise_data.api.v1.views.analytics_engagements import AdvanceAnalyticsEngagementView
|
18
15
|
from enterprise_data.api.v1.views.analytics_enrollments import AdvanceAnalyticsEnrollmentsView
|
19
16
|
from enterprise_data.api.v1.views.analytics_leaderboard import AdvanceAnalyticsLeaderboardView
|
20
17
|
from enterprise_data.constants import UUID4_REGEX
|
@@ -74,14 +71,24 @@ urlpatterns = [
|
|
74
71
|
AdvanceAnalyticsEnrollmentsView.as_view({'get': 'list'}),
|
75
72
|
name='enterprise-admin-analytics-enrollments'
|
76
73
|
),
|
74
|
+
re_path(
|
75
|
+
fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/completions/stats$',
|
76
|
+
AdvanceAnalyticsCompletionsView.as_view({'get': 'stats'}),
|
77
|
+
name='enterprise-admin-analytics-completions-stats'
|
78
|
+
),
|
79
|
+
re_path(
|
80
|
+
fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/completions$',
|
81
|
+
AdvanceAnalyticsCompletionsView.as_view({'get': 'list'}),
|
82
|
+
name='enterprise-admin-analytics-completions'
|
83
|
+
),
|
77
84
|
re_path(
|
78
85
|
fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/engagements/stats$',
|
79
|
-
|
86
|
+
AdvanceAnalyticsEngagementView.as_view({'get': 'stats'}),
|
80
87
|
name='enterprise-admin-analytics-engagements-stats'
|
81
88
|
),
|
82
89
|
re_path(
|
83
90
|
fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/engagements$',
|
84
|
-
|
91
|
+
AdvanceAnalyticsEngagementView.as_view({'get': 'list'}),
|
85
92
|
name='enterprise-admin-analytics-engagements'
|
86
93
|
),
|
87
94
|
re_path(
|
@@ -89,16 +96,6 @@ urlpatterns = [
|
|
89
96
|
enterprise_admin_views.EnterpriseAdminAnalyticsSkillsView.as_view(),
|
90
97
|
name='enterprise-admin-analytics-skills'
|
91
98
|
),
|
92
|
-
re_path(
|
93
|
-
fr'^admin/analytics/(?P<enterprise_id>{UUID4_REGEX})/completions/stats$',
|
94
|
-
enterprise_completions_views.EnterrpiseAdminCompletionsStatsView.as_view(),
|
95
|
-
name='enterprise-admin-analytics-completions-stats'
|
96
|
-
),
|
97
|
-
re_path(
|
98
|
-
fr'^admin/analytics/(?P<enterprise_id>{UUID4_REGEX})/completions$',
|
99
|
-
enterprise_completions_views.EnterrpiseAdminCompletionsView.as_view(),
|
100
|
-
name='enterprise-admin-analytics-completions'
|
101
|
-
),
|
102
99
|
]
|
103
100
|
|
104
101
|
urlpatterns += router.urls
|
@@ -0,0 +1,150 @@
|
|
1
|
+
"""
|
2
|
+
Views for enterprise admin completions analytics.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from datetime import datetime
|
6
|
+
from logging import getLogger
|
7
|
+
|
8
|
+
from edx_rbac.decorators import permission_required
|
9
|
+
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
10
|
+
from rest_framework.decorators import action
|
11
|
+
from rest_framework.response import Response
|
12
|
+
from rest_framework.viewsets import ViewSet
|
13
|
+
|
14
|
+
from django.http import StreamingHttpResponse
|
15
|
+
|
16
|
+
from enterprise_data.admin_analytics.constants import ResponseType
|
17
|
+
from enterprise_data.admin_analytics.database.tables import FactEnrollmentAdminDashTable
|
18
|
+
from enterprise_data.api.v1.paginators import AdvanceAnalyticsPagination
|
19
|
+
from enterprise_data.api.v1.serializers import AdvanceAnalyticsQueryParamSerializer
|
20
|
+
from enterprise_data.api.v1.views.base import AnalyticsPaginationMixin
|
21
|
+
from enterprise_data.renderers import IndividualCompletionsCSVRenderer
|
22
|
+
from enterprise_data.utils import timer
|
23
|
+
|
24
|
+
LOGGER = getLogger(__name__)
|
25
|
+
|
26
|
+
|
27
|
+
class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
28
|
+
"""
|
29
|
+
View to handle requests for enterprise completion data.
|
30
|
+
|
31
|
+
Here is the list of URLs that are handled by this view:
|
32
|
+
1. `enterprise_data_api_v1.enterprise-learner-completion-list`: Get individual completion data.
|
33
|
+
2. `enterprise_data_api_v1.enterprise-learner-completion-stats`: Get completion stats data.
|
34
|
+
"""
|
35
|
+
authentication_classes = (JwtAuthentication,)
|
36
|
+
pagination_class = AdvanceAnalyticsPagination
|
37
|
+
http_method_names = ('get', )
|
38
|
+
|
39
|
+
@permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
|
40
|
+
def list(self, request, enterprise_uuid):
|
41
|
+
"""
|
42
|
+
Get individual completions data for the enterprise.
|
43
|
+
"""
|
44
|
+
# Remove hyphens from the UUID
|
45
|
+
enterprise_uuid = enterprise_uuid.replace('-', '')
|
46
|
+
|
47
|
+
serializer = AdvanceAnalyticsQueryParamSerializer(data=request.GET)
|
48
|
+
serializer.is_valid(raise_exception=True)
|
49
|
+
min_enrollment_date, _ = FactEnrollmentAdminDashTable().get_enrollment_date_range(
|
50
|
+
enterprise_uuid,
|
51
|
+
)
|
52
|
+
|
53
|
+
# get values from query params or use default values
|
54
|
+
start_date = serializer.data.get('start_date', min_enrollment_date)
|
55
|
+
end_date = serializer.data.get('end_date', datetime.now())
|
56
|
+
page = serializer.data.get('page', 1)
|
57
|
+
page_size = serializer.data.get('page_size', 100)
|
58
|
+
completions = FactEnrollmentAdminDashTable().get_all_completions(
|
59
|
+
enterprise_customer_uuid=enterprise_uuid,
|
60
|
+
start_date=start_date,
|
61
|
+
end_date=end_date,
|
62
|
+
limit=page_size,
|
63
|
+
offset=(page - 1) * page_size,
|
64
|
+
)
|
65
|
+
total_count = FactEnrollmentAdminDashTable().get_completion_count(
|
66
|
+
enterprise_customer_uuid=enterprise_uuid,
|
67
|
+
start_date=start_date,
|
68
|
+
end_date=end_date,
|
69
|
+
)
|
70
|
+
response_type = request.query_params.get('response_type', ResponseType.JSON.value)
|
71
|
+
|
72
|
+
LOGGER.info(
|
73
|
+
"Individual completions data requested for enterprise [%s] from [%s] to [%s]",
|
74
|
+
enterprise_uuid,
|
75
|
+
start_date,
|
76
|
+
end_date,
|
77
|
+
)
|
78
|
+
|
79
|
+
if response_type == ResponseType.CSV.value:
|
80
|
+
filename = f"""individual_completions, {start_date} - {end_date}.csv"""
|
81
|
+
|
82
|
+
return StreamingHttpResponse(
|
83
|
+
IndividualCompletionsCSVRenderer().render(self._stream_serialized_data(
|
84
|
+
enterprise_uuid, start_date, end_date, total_count
|
85
|
+
)),
|
86
|
+
content_type="text/csv",
|
87
|
+
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
88
|
+
)
|
89
|
+
|
90
|
+
return self.get_paginated_response(
|
91
|
+
request=request,
|
92
|
+
records=completions,
|
93
|
+
page=page,
|
94
|
+
page_size=page_size,
|
95
|
+
total_count=total_count,
|
96
|
+
)
|
97
|
+
|
98
|
+
@staticmethod
|
99
|
+
def _stream_serialized_data(enterprise_uuid, start_date, end_date, total_count, page_size=50000):
|
100
|
+
"""
|
101
|
+
Stream the serialized data.
|
102
|
+
"""
|
103
|
+
offset = 0
|
104
|
+
while offset < total_count:
|
105
|
+
completions = FactEnrollmentAdminDashTable().get_all_completions(
|
106
|
+
enterprise_customer_uuid=enterprise_uuid,
|
107
|
+
start_date=start_date,
|
108
|
+
end_date=end_date,
|
109
|
+
limit=page_size,
|
110
|
+
offset=offset,
|
111
|
+
)
|
112
|
+
yield from completions
|
113
|
+
offset += page_size
|
114
|
+
|
115
|
+
@permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
|
116
|
+
@action(detail=False, methods=['get'], name='Enterprise completions data for charts', url_path='stats')
|
117
|
+
def stats(self, request, enterprise_uuid):
|
118
|
+
"""
|
119
|
+
Get data to populate enterprise completion charts.
|
120
|
+
|
121
|
+
Here is the list of the charts and their corresponding data:
|
122
|
+
1. `completions_over_time`: This will show time series data of completions over time.
|
123
|
+
2. `top_courses_by_completions`: This will show the top courses by completions.
|
124
|
+
3. `top_subjects_by_completions`: This will show the top subjects by completions.
|
125
|
+
"""
|
126
|
+
# Remove hyphens from the UUID
|
127
|
+
enterprise_uuid = enterprise_uuid.replace('-', '')
|
128
|
+
|
129
|
+
serializer = AdvanceAnalyticsQueryParamSerializer(data=request.GET)
|
130
|
+
serializer.is_valid(raise_exception=True)
|
131
|
+
|
132
|
+
min_enrollment_date, _ = FactEnrollmentAdminDashTable().get_enrollment_date_range(
|
133
|
+
enterprise_uuid,
|
134
|
+
)
|
135
|
+
# get values from query params or use default
|
136
|
+
start_date = serializer.data.get('start_date', min_enrollment_date)
|
137
|
+
end_date = serializer.data.get('end_date', datetime.now())
|
138
|
+
with timer('construct_completion_all_stats'):
|
139
|
+
data = {
|
140
|
+
'completions_over_time': FactEnrollmentAdminDashTable().get_completions_time_series_data(
|
141
|
+
enterprise_uuid, start_date, end_date
|
142
|
+
),
|
143
|
+
'top_courses_by_completions': FactEnrollmentAdminDashTable().get_top_courses_by_completions(
|
144
|
+
enterprise_uuid, start_date, end_date,
|
145
|
+
),
|
146
|
+
'top_subjects_by_completions': FactEnrollmentAdminDashTable().get_top_subjects_by_completions(
|
147
|
+
enterprise_uuid, start_date, end_date,
|
148
|
+
),
|
149
|
+
}
|
150
|
+
return Response(data)
|