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
@@ -1,29 +1,28 @@
|
|
1
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
enterprise_data/__init__.py,sha256=iLQWwenZSKPK_Ygv_cROjWWAtH0biPa7Cuvdqy3hrbg,123
|
2
2
|
enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
|
3
3
|
enterprise_data/clients.py,sha256=GvQupy5TVYfO_IKC3yzXSAgNP54r-PtIjidM5ws9Iks,3947
|
4
4
|
enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
|
5
5
|
enterprise_data/filters.py,sha256=D2EiK12MMpBoz6eOUmTpoJEhj_sH7bA93NRRAdvkDVo,6163
|
6
6
|
enterprise_data/models.py,sha256=khGcOh7NWP8KGu84t78Y2zAu3knREeXA_prApmU2NX8,24428
|
7
7
|
enterprise_data/paginators.py,sha256=YPrC5TeXFt-ymenT2H8H2nCbDCnAzJQlH9kFPElRxWE,269
|
8
|
-
enterprise_data/renderers.py,sha256=
|
8
|
+
enterprise_data/renderers.py,sha256=94JNmPj6OuOcoqMfwl_ieTwy-fQPJO7IbYpYQhxvHJY,3022
|
9
9
|
enterprise_data/signals.py,sha256=8eqNPnlvmfsKf19lGWv5xTIuBgQIqR8EZSp9UYzC8Rc,1024
|
10
10
|
enterprise_data/urls.py,sha256=bqtKF5OEWEwrNmHG3os-pZNuNsmjlhxEqp7yM4TbPf4,243
|
11
11
|
enterprise_data/utils.py,sha256=_zK3BErjZSIkP_JNzK8m-DR5pRTnxKylP9I-vURaRcE,3009
|
12
12
|
enterprise_data/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
enterprise_data/admin_analytics/
|
14
|
-
enterprise_data/admin_analytics/constants.py,sha256=7WturLuMISekgcHHlgj45PPdPrDTYM-l21lA8-Q_Tfc,1107
|
13
|
+
enterprise_data/admin_analytics/constants.py,sha256=bTU05drUaePj9ZjLVxUwFMq_8hibafXqPnVrmrQt4Og,532
|
15
14
|
enterprise_data/admin_analytics/data_loaders.py,sha256=z5OHCmsjQuu1lBw43mSSCbdSQ40fmL_WtodV_Tcnj5U,4791
|
16
15
|
enterprise_data/admin_analytics/utils.py,sha256=DftyBaSKnf0f6E3adH8yVAvGNeQGROywufqnJxZ0W84,6295
|
17
16
|
enterprise_data/admin_analytics/database/__init__.py,sha256=vNSWKf2VV5xMegN7htJJtxtQEb0ASLC6frE2w0ZpYpE,104
|
18
17
|
enterprise_data/admin_analytics/database/utils.py,sha256=5u-d6ZQW95mF_r4bH8Xdi7DgpYAuDFOG_q0P-bjKXHU,1712
|
19
18
|
enterprise_data/admin_analytics/database/queries/__init__.py,sha256=IC5TLOr_GnydbrVbl2mWhwO3aUbYeHuDmfPTLmwGhZA,218
|
20
|
-
enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=
|
21
|
-
enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=
|
19
|
+
enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=QNoeuUQ2Fg9IWSxayA8mBbrnRYNPaXVBWhA7-dbquNc,4445
|
20
|
+
enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=brRgmgtzPLsOdt1vYrk_EpoQLm2izmOdBapxAxNkXzA,8420
|
22
21
|
enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=PgWwvtVCK5lbiq6z44lH0fwbkdWYukhyXZL9X8lNWCY,4099
|
23
22
|
enterprise_data/admin_analytics/database/tables/__init__.py,sha256=Z-c3P9hqR-dC9uYKe63qHkQG9Nms8cLE2jRN-4jeMM0,289
|
24
23
|
enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
|
25
|
-
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=
|
26
|
-
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=
|
24
|
+
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=VM-5S1ayJuFaWhBoJd1odTqWaFsWDeLZkoaPixAG2dQ,5544
|
25
|
+
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=q1XB7aDwFzllS5lBQNfS2y7drehqiK7o0J1eiYzqFOk,10854
|
27
26
|
enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=9PqLeVqByrz7R0qumRbwJlr5lzIWn7Fl7WEGM0aJVlw,3131
|
28
27
|
enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
28
|
enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
|
@@ -33,15 +32,15 @@ enterprise_data/api/v0/urls.py,sha256=vzJjqIo_S3AXWs9Us8XTaJc3FnxLbYzAkmLyuDQqum
|
|
33
32
|
enterprise_data/api/v0/views.py,sha256=4RslZ4NZOU-844bnebEQ71ji2utRY7jEijqC45oQQD0,14380
|
34
33
|
enterprise_data/api/v1/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
|
35
34
|
enterprise_data/api/v1/paginators.py,sha256=f0xsilLaU94jSBltJk46tR1rLEIt7YrqSzMAAVtPXjA,3592
|
36
|
-
enterprise_data/api/v1/serializers.py,sha256=
|
37
|
-
enterprise_data/api/v1/urls.py,sha256=
|
35
|
+
enterprise_data/api/v1/serializers.py,sha256=leVxK1fVAk_25TDnuMLDHKvOw7GvTmU7zSYXiX0nmZU,11620
|
36
|
+
enterprise_data/api/v1/urls.py,sha256=zoztENyCI_8TcKpE88Q6pkKSHiWCC9DascjC9ul4arc,3975
|
38
37
|
enterprise_data/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
enterprise_data/api/v1/views/
|
40
|
-
enterprise_data/api/v1/views/
|
38
|
+
enterprise_data/api/v1/views/analytics_completions.py,sha256=Px-hwNpkgwZN-Kwrl9MEfpY-TNuVglp1pyJEG9QnPFQ,6391
|
39
|
+
enterprise_data/api/v1/views/analytics_engagements.py,sha256=yvnHALXVkxQHuX7M8Mom1vNEH-2vvPHZMVlm1SUvTTE,6429
|
40
|
+
enterprise_data/api/v1/views/analytics_enrollments.py,sha256=RF-OOSVOPbESIUmrLbSM229lMPQ8RokJ6MqTpWoxIgY,6413
|
41
41
|
enterprise_data/api/v1/views/analytics_leaderboard.py,sha256=2DALqzUIbe4-ZGgHHIkYAKJ5L1ik2ruPtQNYtTdPba4,5974
|
42
42
|
enterprise_data/api/v1/views/base.py,sha256=Kkmd5zgEBAhvwS_GoGXSK6lgbDNwSPioYn-QbnizI3w,3416
|
43
43
|
enterprise_data/api/v1/views/enterprise_admin.py,sha256=DsR1oHFhe6LCIFjIJ4YLLZ7PUChvNlFfdZD-sxHoijY,7388
|
44
|
-
enterprise_data/api/v1/views/enterprise_completions.py,sha256=bJG2ZtTbLyiBrj64iJHQNHEKLrJCzl9OuJ7nDtw-9aY,8377
|
45
44
|
enterprise_data/api/v1/views/enterprise_learner.py,sha256=yABjJje3CT8I8YOhWr1_tTkdKtnGJom8eu3EFz_-0BU,18517
|
46
45
|
enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
|
47
46
|
enterprise_data/fixtures/enterprise_enrollment.json,sha256=6onPXXR29pMdTdbl_mn81sDi3Re5jkLUZz2TPMB_1IY,5786
|
@@ -115,13 +114,13 @@ enterprise_data/tests/test_models.py,sha256=MWBY-LY5TPBjZ4GlvpM-h4W-BvRKr2Rml8Bz
|
|
115
114
|
enterprise_data/tests/test_utils.py,sha256=vbmYM7DMN-lHS2p4yaa0Yd6uSGXd2qoZRDE9X3J4Sec,18385
|
116
115
|
enterprise_data/tests/test_views.py,sha256=UvDRNTxruy5zBK_KgUy2cBMbwlaTW_vkM0-TCXbQZiY,69667
|
117
116
|
enterprise_data/tests/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
118
|
-
enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=
|
119
|
-
enterprise_data/tests/admin_analytics/mock_enrollments.py,sha256=
|
120
|
-
enterprise_data/tests/admin_analytics/test_analytics_engagements.py,sha256=
|
121
|
-
enterprise_data/tests/admin_analytics/test_analytics_enrollments.py,sha256=
|
117
|
+
enterprise_data/tests/admin_analytics/mock_analytics_data.py,sha256=NYmgPKIZrIK7HqbjxQ_PKqhY5zmafoePM4NcqE5zfpc,17401
|
118
|
+
enterprise_data/tests/admin_analytics/mock_enrollments.py,sha256=u61tkqSdVKExURJF7arvBoXvbdkF39CkjxQiTvVMXIE,4467
|
119
|
+
enterprise_data/tests/admin_analytics/test_analytics_engagements.py,sha256=gfO6RI2gbDMhOD4p4h7l6sZpisglBreTPtJRqNxIgo8,10440
|
120
|
+
enterprise_data/tests/admin_analytics/test_analytics_enrollments.py,sha256=uFa6gnlf-CthctdYTWsw-pLLOxkELGiq8YFq5CyWFbs,10826
|
122
121
|
enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py,sha256=VSEyDAHfWBJvqmx9yzd4NnPAqK3TqaKrMBWswMAdzfU,6206
|
123
122
|
enterprise_data/tests/admin_analytics/test_data_loaders.py,sha256=b4BjN88FX9WjE6XJjkJZnoEvWVB_DovBGJ_wh-HgT9I,3514
|
124
|
-
enterprise_data/tests/admin_analytics/test_enterprise_completions.py,sha256=
|
123
|
+
enterprise_data/tests/admin_analytics/test_enterprise_completions.py,sha256=6BsCnaXdTMaQXoqy4SWNxAkGimc75lBCdBHjR2MdOFU,7233
|
125
124
|
enterprise_data/tests/admin_analytics/test_utils.py,sha256=4qL_ZK-sGzbMMqiOrBrPmzdIPno7KohiaIfd7FMehic,5260
|
126
125
|
enterprise_data/tests/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
127
126
|
enterprise_data/tests/api/v0/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -171,8 +170,8 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=WtL-RqGgu2x5PP
|
|
171
170
|
enterprise_reporting/tests/test_utils.py,sha256=Zt_TA0LVb-B6fQGkUkAKKVlUKKnQh8jnw1US1jKe7g8,9493
|
172
171
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
173
172
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
174
|
-
edx_enterprise_data-9.0.
|
175
|
-
edx_enterprise_data-9.0.
|
176
|
-
edx_enterprise_data-9.0.
|
177
|
-
edx_enterprise_data-9.0.
|
178
|
-
edx_enterprise_data-9.0.
|
173
|
+
edx_enterprise_data-9.1.0.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
174
|
+
edx_enterprise_data-9.1.0.dist-info/METADATA,sha256=7nemB4hOP7OfCH-uN87q4YINSbTbnicYsTd_P6CLSPE,1569
|
175
|
+
edx_enterprise_data-9.1.0.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
176
|
+
edx_enterprise_data-9.1.0.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
177
|
+
edx_enterprise_data-9.1.0.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -19,23 +19,7 @@ class Calculation(Enum):
|
|
19
19
|
MOVING_AVERAGE_7_PERIOD = 'Moving Average (7 Period)'
|
20
20
|
|
21
21
|
|
22
|
-
class EnrollmentChart(Enum):
|
23
|
-
"""CSV choices"""
|
24
|
-
ENROLLMENTS_OVER_TIME = 'enrollments_over_time'
|
25
|
-
TOP_COURSES_BY_ENROLLMENTS = 'top_courses_by_enrollments'
|
26
|
-
TOP_SUBJECTS_BY_ENROLLMENTS = 'top_subjects_by_enrollments'
|
27
|
-
INDIVIDUAL_ENROLLMENTS = 'individual_enrollments'
|
28
|
-
|
29
|
-
|
30
22
|
class ResponseType(Enum):
|
31
23
|
"""Response type choices"""
|
32
24
|
JSON = 'json'
|
33
25
|
CSV = 'csv'
|
34
|
-
|
35
|
-
|
36
|
-
class EngagementChart(Enum):
|
37
|
-
"""Response Choices"""
|
38
|
-
ENGAGEMENTS_OVER_TIME = 'engagements_over_time'
|
39
|
-
TOP_COURSES_BY_ENGAGEMENTS = 'top_courses_by_engagements'
|
40
|
-
TOP_SUBJECTS_BY_ENGAGEMENTS = 'top_subjects_by_engagements'
|
41
|
-
INDIVIDUAL_ENGAGEMENTS = 'individual_engagements'
|
@@ -19,3 +19,93 @@ class FactEngagementAdminDashQueries:
|
|
19
19
|
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
20
20
|
activity_date BETWEEN %(start_date)s AND %(end_date)s;
|
21
21
|
"""
|
22
|
+
|
23
|
+
@staticmethod
|
24
|
+
def get_engagement_count_query():
|
25
|
+
"""
|
26
|
+
Get the query to fetch the total number of engagements for an enterprise customer.
|
27
|
+
"""
|
28
|
+
return """
|
29
|
+
SELECT count(*)
|
30
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
31
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
32
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s;
|
33
|
+
"""
|
34
|
+
|
35
|
+
@staticmethod
|
36
|
+
def get_all_engagement_query():
|
37
|
+
"""
|
38
|
+
Get the query to fetch all engagement data.
|
39
|
+
"""
|
40
|
+
return """
|
41
|
+
SELECT
|
42
|
+
email, course_title, course_subject, enroll_type, activity_date,
|
43
|
+
learning_time_seconds/3600 as learning_time_hours
|
44
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
45
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
46
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s
|
47
|
+
ORDER BY activity_date DESC LIMIT %(limit)s OFFSET %(offset)s;
|
48
|
+
"""
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def get_top_courses_by_engagement_query(record_count=20):
|
52
|
+
"""
|
53
|
+
Get the query to fetch the learning time in hours by courses.
|
54
|
+
|
55
|
+
Query should fetch the top N courses by user engagement. Where N is the value of record_count.
|
56
|
+
|
57
|
+
Arguments:
|
58
|
+
record_count (int): Number of records to fetch.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
(str): Query to fetch the learning time in hours by courses for the top courses by user engagement.
|
62
|
+
"""
|
63
|
+
return f"""
|
64
|
+
SELECT course_key, course_title, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
|
65
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
66
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
67
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s
|
68
|
+
GROUP BY course_key, course_title, enroll_type
|
69
|
+
ORDER BY learning_time_hours DESC LIMIT {record_count};
|
70
|
+
"""
|
71
|
+
|
72
|
+
@staticmethod
|
73
|
+
def get_top_subjects_by_engagement_query(record_count=20):
|
74
|
+
"""
|
75
|
+
Get the query to fetch the learning time in hours by subjects.
|
76
|
+
|
77
|
+
Query should fetch the top N subjects by user engagement. Where N is the value of record_count.
|
78
|
+
|
79
|
+
Arguments:
|
80
|
+
record_count (int): Number of records to fetch.
|
81
|
+
|
82
|
+
Returns:
|
83
|
+
(str): Query to fetch the learning time in hours by subjects for the top subjects by user engagement.
|
84
|
+
"""
|
85
|
+
return f"""
|
86
|
+
SELECT course_subject, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
|
87
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
88
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
89
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s
|
90
|
+
GROUP BY course_subject, enroll_type
|
91
|
+
ORDER BY learning_time_hours DESC LIMIT {record_count};
|
92
|
+
"""
|
93
|
+
|
94
|
+
@staticmethod
|
95
|
+
def get_engagement_time_series_data_query():
|
96
|
+
"""
|
97
|
+
Get the query to fetch the completion time series data.
|
98
|
+
|
99
|
+
Query should fetch the time series data with daily granularity.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
(str): Query to fetch the completion time series data.
|
103
|
+
"""
|
104
|
+
return """
|
105
|
+
SELECT activity_date, enroll_type, SUM(learning_time_seconds)/3600 as learning_time_hours
|
106
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
107
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
108
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s
|
109
|
+
GROUP BY activity_date, enroll_type
|
110
|
+
ORDER BY activity_date;
|
111
|
+
"""
|
@@ -68,6 +68,7 @@ class FactEnrollmentAdminDashQueries:
|
|
68
68
|
SUM(has_passed) as completions
|
69
69
|
FROM fact_enrollment_admin_dash
|
70
70
|
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
71
|
+
has_passed=1 AND
|
71
72
|
passed_date BETWEEN %(start_date)s AND %(end_date)s;
|
72
73
|
"""
|
73
74
|
|
@@ -85,7 +86,7 @@ class FactEnrollmentAdminDashQueries:
|
|
85
86
|
"""
|
86
87
|
|
87
88
|
@staticmethod
|
88
|
-
def
|
89
|
+
def get_top_courses_by_enrollments_query(record_count=20):
|
89
90
|
"""
|
90
91
|
Get the query to fetch the enrollment count by courses.
|
91
92
|
|
@@ -94,14 +95,12 @@ class FactEnrollmentAdminDashQueries:
|
|
94
95
|
Arguments:
|
95
96
|
record_count (int): Number of records to fetch.
|
96
97
|
"""
|
97
|
-
# Some local environments raise error when course_title is added in SELECT without GROUP BY.
|
98
|
-
# If you face this issue, you can remove course_title from SELECT.
|
99
98
|
return f"""
|
100
99
|
SELECT course_key, course_title , enroll_type, count(course_key) as enrollment_count
|
101
100
|
FROM fact_enrollment_admin_dash
|
102
101
|
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
103
102
|
enterprise_enrollment_date BETWEEN %(start_date)s AND %(end_date)s
|
104
|
-
GROUP BY course_key, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
|
103
|
+
GROUP BY course_key, course_title, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
|
105
104
|
"""
|
106
105
|
|
107
106
|
@staticmethod
|
@@ -135,3 +134,83 @@ class FactEnrollmentAdminDashQueries:
|
|
135
134
|
GROUP BY enterprise_enrollment_date, enroll_type
|
136
135
|
ORDER BY enterprise_enrollment_date;
|
137
136
|
"""
|
137
|
+
|
138
|
+
@staticmethod
|
139
|
+
def get_all_completions_query():
|
140
|
+
"""
|
141
|
+
Get the query to fetch all completions.
|
142
|
+
"""
|
143
|
+
return """
|
144
|
+
SELECT email, course_title, course_subject, enroll_type, passed_date
|
145
|
+
FROM fact_enrollment_admin_dash
|
146
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
147
|
+
has_passed=1 AND
|
148
|
+
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
149
|
+
ORDER BY passed_date DESC LIMIT %(limit)s OFFSET %(offset)s
|
150
|
+
"""
|
151
|
+
|
152
|
+
@staticmethod
|
153
|
+
def get_top_courses_by_completions_query(record_count=20):
|
154
|
+
"""
|
155
|
+
Get the query to fetch the completion count by courses.
|
156
|
+
|
157
|
+
Query should fetch the top N courses by completion count. Where N is the value of record_count.
|
158
|
+
|
159
|
+
Arguments:
|
160
|
+
record_count (int): Number of records to fetch.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
(str): Query to fetch the enrollment count by courses for the top courses by enrollment count.
|
164
|
+
"""
|
165
|
+
return f"""
|
166
|
+
SELECT course_key, course_title, enroll_type, count(course_key) as completion_count
|
167
|
+
FROM fact_enrollment_admin_dash
|
168
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
169
|
+
has_passed=1 AND
|
170
|
+
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
171
|
+
GROUP BY course_key, course_title, enroll_type
|
172
|
+
ORDER BY completion_count DESC LIMIT {record_count};
|
173
|
+
"""
|
174
|
+
|
175
|
+
@staticmethod
|
176
|
+
def get_top_subjects_by_completions_query(record_count=20):
|
177
|
+
"""
|
178
|
+
Get the query to fetch the completion count by subjects.
|
179
|
+
|
180
|
+
Query should fetch the top N subjects by completion count. Where N is the value of record_count.
|
181
|
+
|
182
|
+
Arguments:
|
183
|
+
record_count (int): Number of records to fetch.
|
184
|
+
|
185
|
+
Returns:
|
186
|
+
(str): Query to fetch the completion count by subjects for the top subjects by completion count.
|
187
|
+
"""
|
188
|
+
return f"""
|
189
|
+
SELECT course_subject, enroll_type, count(course_subject) as completion_count
|
190
|
+
FROM fact_enrollment_admin_dash
|
191
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
192
|
+
has_passed=1 AND
|
193
|
+
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
194
|
+
GROUP BY course_subject, enroll_type
|
195
|
+
ORDER BY completion_count DESC LIMIT {record_count};
|
196
|
+
"""
|
197
|
+
|
198
|
+
@staticmethod
|
199
|
+
def get_completions_time_series_data_query():
|
200
|
+
"""
|
201
|
+
Get the query to fetch the completion time series data.
|
202
|
+
|
203
|
+
Query should fetch the time series data with daily granularity.
|
204
|
+
|
205
|
+
Returns:
|
206
|
+
(str): Query to fetch the completion time series data.
|
207
|
+
"""
|
208
|
+
return """
|
209
|
+
SELECT passed_date, enroll_type, count(course_key) as completion_count
|
210
|
+
FROM fact_enrollment_admin_dash
|
211
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
212
|
+
has_passed=1 AND
|
213
|
+
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
214
|
+
GROUP BY passed_date, enroll_type
|
215
|
+
ORDER BY passed_date;
|
216
|
+
"""
|
@@ -36,3 +36,119 @@ class FactEngagementAdminDashTable(BaseTable):
|
|
36
36
|
}
|
37
37
|
)
|
38
38
|
return tuple(results[0])
|
39
|
+
|
40
|
+
def get_engagement_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
41
|
+
"""
|
42
|
+
Get the total number of engagements for the given enterprise customer.
|
43
|
+
|
44
|
+
Arguments:
|
45
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
46
|
+
start_date (date): The start date.
|
47
|
+
end_date (date): The end date.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
int: The total number of engagements.
|
51
|
+
"""
|
52
|
+
results = run_query(
|
53
|
+
query=self.queries.get_engagement_count_query(),
|
54
|
+
params={
|
55
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
56
|
+
'start_date': start_date,
|
57
|
+
'end_date': end_date,
|
58
|
+
}
|
59
|
+
)
|
60
|
+
return results[0][0]
|
61
|
+
|
62
|
+
def get_all_engagements(
|
63
|
+
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
64
|
+
):
|
65
|
+
"""
|
66
|
+
Get all engagement data for the given enterprise customer.
|
67
|
+
|
68
|
+
Arguments:
|
69
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
70
|
+
start_date (date): The start date.
|
71
|
+
end_date (date): The end date.
|
72
|
+
limit (int): The maximum number of records to return.
|
73
|
+
offset (int): The number of records to skip.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
list<dict>: A list of dictionaries containing the engagement data.
|
77
|
+
"""
|
78
|
+
return run_query(
|
79
|
+
query=self.queries.get_all_engagement_query(),
|
80
|
+
params={
|
81
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
82
|
+
'start_date': start_date,
|
83
|
+
'end_date': end_date,
|
84
|
+
'limit': limit,
|
85
|
+
'offset': offset,
|
86
|
+
},
|
87
|
+
as_dict=True,
|
88
|
+
)
|
89
|
+
|
90
|
+
def get_top_courses_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
91
|
+
"""
|
92
|
+
Get the top courses by user engagement for the given enterprise customer.
|
93
|
+
|
94
|
+
Arguments:
|
95
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
96
|
+
start_date (date): The start date.
|
97
|
+
end_date (date): The end date.
|
98
|
+
|
99
|
+
Returns:
|
100
|
+
list<dict>: A list of dictionaries containing the course data.
|
101
|
+
"""
|
102
|
+
return run_query(
|
103
|
+
query=self.queries.get_top_courses_by_engagement_query(),
|
104
|
+
params={
|
105
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
106
|
+
'start_date': start_date,
|
107
|
+
'end_date': end_date,
|
108
|
+
},
|
109
|
+
as_dict=True,
|
110
|
+
)
|
111
|
+
|
112
|
+
def get_top_subjects_by_engagement(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
113
|
+
"""
|
114
|
+
Get the top subjects by user engagement for the given enterprise customer.
|
115
|
+
|
116
|
+
Arguments:
|
117
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
118
|
+
start_date (date): The start date.
|
119
|
+
end_date (date): The end date.
|
120
|
+
|
121
|
+
Returns:
|
122
|
+
list<dict>: A list of dictionaries containing the subject data.
|
123
|
+
"""
|
124
|
+
return run_query(
|
125
|
+
query=self.queries.get_top_subjects_by_engagement_query(),
|
126
|
+
params={
|
127
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
128
|
+
'start_date': start_date,
|
129
|
+
'end_date': end_date,
|
130
|
+
},
|
131
|
+
as_dict=True,
|
132
|
+
)
|
133
|
+
|
134
|
+
def get_engagement_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
135
|
+
"""
|
136
|
+
Get the engagement time series data.
|
137
|
+
|
138
|
+
Arguments:
|
139
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
140
|
+
start_date (date): The start date.
|
141
|
+
end_date (date): The end date.
|
142
|
+
|
143
|
+
Returns:
|
144
|
+
list<dict>: A list of dictionaries containing the engagement time series data.
|
145
|
+
"""
|
146
|
+
return run_query(
|
147
|
+
query=self.queries.get_engagement_time_series_data_query(),
|
148
|
+
params={
|
149
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
150
|
+
'start_date': start_date,
|
151
|
+
'end_date': end_date,
|
152
|
+
},
|
153
|
+
as_dict=True,
|
154
|
+
)
|
@@ -35,7 +35,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
35
35
|
'end_date': end_date,
|
36
36
|
}
|
37
37
|
)
|
38
|
-
return results[0][0]
|
38
|
+
return int(results[0][0] or 0)
|
39
39
|
|
40
40
|
def get_all_enrollments(
|
41
41
|
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
@@ -132,7 +132,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
132
132
|
'end_date': end_date,
|
133
133
|
}
|
134
134
|
)
|
135
|
-
return results[0][0]
|
135
|
+
return int(results[0][0] or 0)
|
136
136
|
|
137
137
|
def get_top_courses_by_enrollments(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
138
138
|
"""
|
@@ -147,7 +147,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
147
147
|
list<dict>: A list of dictionaries containing the course key, course_title and enrollment count.
|
148
148
|
"""
|
149
149
|
return run_query(
|
150
|
-
query=self.queries.
|
150
|
+
query=self.queries.get_top_courses_by_enrollments_query(),
|
151
151
|
params={
|
152
152
|
'enterprise_customer_uuid': enterprise_customer_uuid,
|
153
153
|
'start_date': start_date,
|
@@ -199,3 +199,97 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
199
199
|
},
|
200
200
|
as_dict=True,
|
201
201
|
)
|
202
|
+
|
203
|
+
def get_all_completions(
|
204
|
+
self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
|
205
|
+
):
|
206
|
+
"""
|
207
|
+
Get all completions for the given enterprise customer.
|
208
|
+
|
209
|
+
Arguments:
|
210
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
211
|
+
start_date (date): The start date.
|
212
|
+
end_date (date): The end date.
|
213
|
+
limit (int): The maximum number of records to return.
|
214
|
+
offset (int): The number of records to skip.
|
215
|
+
|
216
|
+
Returns:
|
217
|
+
list<dict>: A list of dictionaries containing the completions data.
|
218
|
+
"""
|
219
|
+
return run_query(
|
220
|
+
query=self.queries.get_all_completions_query(),
|
221
|
+
params={
|
222
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
223
|
+
'start_date': start_date,
|
224
|
+
'end_date': end_date,
|
225
|
+
'limit': limit,
|
226
|
+
'offset': offset,
|
227
|
+
},
|
228
|
+
as_dict=True,
|
229
|
+
)
|
230
|
+
|
231
|
+
def get_top_courses_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
232
|
+
"""
|
233
|
+
Get the top courses by completion for the given enterprise customer.
|
234
|
+
|
235
|
+
Arguments:
|
236
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
237
|
+
start_date (date): The start date.
|
238
|
+
end_date (date): The end date.
|
239
|
+
|
240
|
+
Returns:
|
241
|
+
list<dict>: A list of dictionaries containing the course key, course_title and completion count.
|
242
|
+
"""
|
243
|
+
return run_query(
|
244
|
+
query=self.queries.get_top_courses_by_completions_query(),
|
245
|
+
params={
|
246
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
247
|
+
'start_date': start_date,
|
248
|
+
'end_date': end_date,
|
249
|
+
},
|
250
|
+
as_dict=True,
|
251
|
+
)
|
252
|
+
|
253
|
+
def get_top_subjects_by_completions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
254
|
+
"""
|
255
|
+
Get the top subjects by completions for the given enterprise customer.
|
256
|
+
|
257
|
+
Arguments:
|
258
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
259
|
+
start_date (date): The start date.
|
260
|
+
end_date (date): The end date.
|
261
|
+
|
262
|
+
Returns:
|
263
|
+
list<dict>: A list of dictionaries containing the subject and completion count.
|
264
|
+
"""
|
265
|
+
return run_query(
|
266
|
+
query=self.queries.get_top_subjects_by_completions_query(),
|
267
|
+
params={
|
268
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
269
|
+
'start_date': start_date,
|
270
|
+
'end_date': end_date,
|
271
|
+
},
|
272
|
+
as_dict=True,
|
273
|
+
)
|
274
|
+
|
275
|
+
def get_completions_time_series_data(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
276
|
+
"""
|
277
|
+
Get the completions time series data for the given enterprise customer.
|
278
|
+
|
279
|
+
Arguments:
|
280
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
281
|
+
start_date (date): The start date.
|
282
|
+
end_date (date): The end date.
|
283
|
+
|
284
|
+
Returns:
|
285
|
+
list<dict>: A list of dictionaries containing the date and completion count.
|
286
|
+
"""
|
287
|
+
return run_query(
|
288
|
+
query=self.queries.get_completions_time_series_data_query(),
|
289
|
+
params={
|
290
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
291
|
+
'start_date': start_date,
|
292
|
+
'end_date': end_date,
|
293
|
+
},
|
294
|
+
as_dict=True,
|
295
|
+
)
|
@@ -5,13 +5,7 @@ from uuid import UUID
|
|
5
5
|
|
6
6
|
from rest_framework import serializers
|
7
7
|
|
8
|
-
from enterprise_data.admin_analytics.constants import
|
9
|
-
Calculation,
|
10
|
-
EngagementChart,
|
11
|
-
EnrollmentChart,
|
12
|
-
Granularity,
|
13
|
-
ResponseType,
|
14
|
-
)
|
8
|
+
from enterprise_data.admin_analytics.constants import Calculation, Granularity, ResponseType
|
15
9
|
from enterprise_data.models import (
|
16
10
|
EnterpriseAdminLearnerProgress,
|
17
11
|
EnterpriseAdminSummarizeInsights,
|
@@ -315,51 +309,3 @@ class AdvanceAnalyticsQueryParamSerializer(serializers.Serializer): # pylint: d
|
|
315
309
|
if value not in self.CALCULATION_CHOICES:
|
316
310
|
raise serializers.ValidationError(f"Calculation must be one of {self.CALCULATION_CHOICES}")
|
317
311
|
return value
|
318
|
-
|
319
|
-
|
320
|
-
class AdvanceAnalyticsEnrollmentStatsSerializer(
|
321
|
-
AdvanceAnalyticsQueryParamSerializer
|
322
|
-
): # pylint: disable=abstract-method
|
323
|
-
"""Serializer for validating Advance Analytics Enrollments Stats API"""
|
324
|
-
CHART_TYPES = [
|
325
|
-
EnrollmentChart.ENROLLMENTS_OVER_TIME.value,
|
326
|
-
EnrollmentChart.TOP_COURSES_BY_ENROLLMENTS.value,
|
327
|
-
EnrollmentChart.TOP_SUBJECTS_BY_ENROLLMENTS.value
|
328
|
-
]
|
329
|
-
|
330
|
-
chart_type = serializers.CharField(required=False)
|
331
|
-
|
332
|
-
def validate_chart_type(self, value):
|
333
|
-
"""
|
334
|
-
Validate the chart_type value.
|
335
|
-
|
336
|
-
Raises:
|
337
|
-
serializers.ValidationError: If chart_type is not one of the valid choices
|
338
|
-
"""
|
339
|
-
if value not in self.CHART_TYPES:
|
340
|
-
raise serializers.ValidationError(f"chart_type must be one of {self.CHART_TYPES}")
|
341
|
-
return value
|
342
|
-
|
343
|
-
|
344
|
-
class AdvanceAnalyticsEngagementStatsSerializer(
|
345
|
-
AdvanceAnalyticsQueryParamSerializer
|
346
|
-
): # pylint: disable=abstract-method
|
347
|
-
"""Serializer for validating Advance Analytics Engagements Stats API"""
|
348
|
-
CHART_TYPES = [
|
349
|
-
EngagementChart.ENGAGEMENTS_OVER_TIME.value,
|
350
|
-
EngagementChart.TOP_COURSES_BY_ENGAGEMENTS.value,
|
351
|
-
EngagementChart.TOP_SUBJECTS_BY_ENGAGEMENTS.value
|
352
|
-
]
|
353
|
-
|
354
|
-
chart_type = serializers.CharField(required=False)
|
355
|
-
|
356
|
-
def validate_chart_type(self, value):
|
357
|
-
"""
|
358
|
-
Validate the chart_type value.
|
359
|
-
|
360
|
-
Raises:
|
361
|
-
serializers.ValidationError: If chart_type is not one of the valid choices
|
362
|
-
"""
|
363
|
-
if value not in self.CHART_TYPES:
|
364
|
-
raise serializers.ValidationError(f"chart_type must be one of {self.CHART_TYPES}")
|
365
|
-
return value
|