edx-enterprise-data 10.11.1__py3-none-any.whl → 10.12.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-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/METADATA +1 -1
- {edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/RECORD +16 -15
- enterprise_data/__init__.py +1 -1
- enterprise_data/admin_analytics/database/filters/__init__.py +1 -0
- enterprise_data/admin_analytics/database/filters/fact_completion_admin_dash.py +36 -0
- enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +20 -24
- enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +91 -35
- enterprise_data/api/v1/serializers.py +1 -0
- enterprise_data/api/v1/views/analytics_completions.py +11 -5
- enterprise_data/api/v1/views/enterprise_admin.py +2 -1
- enterprise_data/management/commands/pre_warm_analytics_cache.py +6 -0
- enterprise_data/tests/api/v1/views/test_enterprise_admin.py +5 -4
- enterprise_reporting/tests/test_delivery_method.py +1 -1
- {edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/licenses/LICENSE +0 -0
- {edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
|
|
1
|
-
edx_enterprise_data-10.
|
2
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
edx_enterprise_data-10.12.0.dist-info/licenses/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
2
|
+
enterprise_data/__init__.py,sha256=eCPWfovt7oPmCOdH366B9g4bK-v2sL1oI2SGL8UqKx4,125
|
3
3
|
enterprise_data/apps.py,sha256=aF6hZwDfI2oWj95tUTm_2ikHueQj-jLj-u0GrgzpsQI,414
|
4
4
|
enterprise_data/clients.py,sha256=glw-fXu3V7rKEpiUBF056gZEdNK4KnWcP9tNYELimRQ,6566
|
5
5
|
enterprise_data/constants.py,sha256=uCKjfpdlMYFZJsAj3n9RMw4Cmg5_6s3NuwocO-fch3s,238
|
@@ -16,12 +16,13 @@ enterprise_data/admin_analytics/constants.py,sha256=-6uLAq5DUeA_rv5eUb9SeqlG3iVW
|
|
16
16
|
enterprise_data/admin_analytics/data_loaders.py,sha256=b6RjEIxCol8ETQMY7QfwhqN9eEAvrUN_UldIG7rgsSY,736
|
17
17
|
enterprise_data/admin_analytics/database/__init__.py,sha256=vNSWKf2VV5xMegN7htJJtxtQEb0ASLC6frE2w0ZpYpE,104
|
18
18
|
enterprise_data/admin_analytics/database/utils.py,sha256=5u-d6ZQW95mF_r4bH8Xdi7DgpYAuDFOG_q0P-bjKXHU,1712
|
19
|
-
enterprise_data/admin_analytics/database/filters/__init__.py,sha256=
|
19
|
+
enterprise_data/admin_analytics/database/filters/__init__.py,sha256=FIgcEfVQPU0TrJoFhWJMo6WPFz4WnPAzxxkwTLfwtP8,186
|
20
20
|
enterprise_data/admin_analytics/database/filters/base.py,sha256=nOek6XgHEVBKUTGk-K0PZpy0RSZB3D7kc8OD5nlqXcE,71
|
21
|
+
enterprise_data/admin_analytics/database/filters/fact_completion_admin_dash.py,sha256=j50oW-C-N2X3g6RsvnP9PHeiz8Z4qqe-SyjxeCzb6zQ,1208
|
21
22
|
enterprise_data/admin_analytics/database/filters/fact_enrollment_admin_dash.py,sha256=WKRBWRCujiMay2ePdl9vnNN1ux-LO0edyb79W4dm-S4,1808
|
22
23
|
enterprise_data/admin_analytics/database/queries/__init__.py,sha256=IC5TLOr_GnydbrVbl2mWhwO3aUbYeHuDmfPTLmwGhZA,218
|
23
24
|
enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py,sha256=eLy9GT0gFGLbw8yZZdEaeCAw0pTEUsy0-Ud5g2T9T80,10836
|
24
|
-
enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=
|
25
|
+
enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=n_RiqraVzYvCsgLaPmpSBUX3cyNEHjSnkNH7n35gC80,10609
|
25
26
|
enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py,sha256=ZaJPghTrQvBGsFxfpeR8EE45ujtaYI9R_xkoDDqD2So,4269
|
26
27
|
enterprise_data/admin_analytics/database/query_filters/__init__.py,sha256=xW9cf5KGpMs33tTlil5gzKq4RxcZVCJZESsrHo2X0E4,182
|
27
28
|
enterprise_data/admin_analytics/database/query_filters/base.py,sha256=XZUC1AIaDPBq0cwh2Xn5wp_DZfsD3HnMMvqFUt7iM2E,2205
|
@@ -31,7 +32,7 @@ enterprise_data/admin_analytics/database/query_filters/in_.py,sha256=RsqDVTgzJ0v
|
|
31
32
|
enterprise_data/admin_analytics/database/tables/__init__.py,sha256=Z-c3P9hqR-dC9uYKe63qHkQG9Nms8cLE2jRN-4jeMM0,289
|
32
33
|
enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
|
33
34
|
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=VMUGwfrUsYd_NnxEDNBovAmHwhdTCSImGA6JjHzknhk,12959
|
34
|
-
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=
|
35
|
+
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=yDqrt9SWvvBNb-v-7Sh-m2Vef2bsGRSsP-YKeLCAnSA,18411
|
35
36
|
enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py,sha256=3xNwSi0wfCyBHcXPd6-9Ujs1NUm8kmZRg_gPrZzp9nQ,3233
|
36
37
|
enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
38
|
enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
|
@@ -40,15 +41,15 @@ enterprise_data/api/v0/serializers.py,sha256=dngZTk6DhRxApchQKCMp1B_c8aVnQtH0NCq
|
|
40
41
|
enterprise_data/api/v0/urls.py,sha256=vzJjqIo_S3AXWs9Us8XTaJc3FnxLbYzAkmLyuDQqum0,699
|
41
42
|
enterprise_data/api/v0/views.py,sha256=4RslZ4NZOU-844bnebEQ71ji2utRY7jEijqC45oQQD0,14380
|
42
43
|
enterprise_data/api/v1/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
|
43
|
-
enterprise_data/api/v1/serializers.py,sha256=
|
44
|
+
enterprise_data/api/v1/serializers.py,sha256=6yxUe_7UBh80e2ZPZIf1AUzzgtKM8-yS38Q4Katqbj8,13898
|
44
45
|
enterprise_data/api/v1/urls.py,sha256=Wl1xLboPg-Lq1ZvjAWf51JKYkHlmx02Kpq1nwfDyS8s,4372
|
45
46
|
enterprise_data/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
46
|
-
enterprise_data/api/v1/views/analytics_completions.py,sha256=
|
47
|
+
enterprise_data/api/v1/views/analytics_completions.py,sha256=ALkoUTgvaqCxpjnf3rkvwBT7-Hv7eM1RnCdRboCQgR8,6540
|
47
48
|
enterprise_data/api/v1/views/analytics_engagements.py,sha256=Yo-bpA-0xOQHUPTFF0jHWxjm6KpSC-l2nGxhYX0ajBk,6298
|
48
49
|
enterprise_data/api/v1/views/analytics_enrollments.py,sha256=_KBo4RhEmfQXcCOgvowD28WCVJwlc4APuCnRDbAYK9E,6563
|
49
50
|
enterprise_data/api/v1/views/analytics_leaderboard.py,sha256=3dyo7_OhyGEEeibemBrRsUOo0jbM4LbDgV5gw3YnVig,4186
|
50
51
|
enterprise_data/api/v1/views/base.py,sha256=Kkmd5zgEBAhvwS_GoGXSK6lgbDNwSPioYn-QbnizI3w,3416
|
51
|
-
enterprise_data/api/v1/views/enterprise_admin.py,sha256=
|
52
|
+
enterprise_data/api/v1/views/enterprise_admin.py,sha256=uaf8sSp_JS1T5Kgi4xNCjhu6A0HKa3Zwp6JMjY3okJk,9103
|
52
53
|
enterprise_data/api/v1/views/enterprise_learner.py,sha256=vRzfaQCEoeq_tEY7KsNZJVzgn7XEWZ1l-n0oUoSVGyU,20093
|
53
54
|
enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
|
54
55
|
enterprise_data/cache/__init__.py,sha256=fiBUploll1kmDy2vCmnNpeZVTD4ewsgtRF14vVs0Rb4,1850
|
@@ -64,7 +65,7 @@ enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.
|
|
64
65
|
enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py,sha256=bUYmZHA3yK3ZBPhV0wkpRDgH_Q2b5rVQnwSp2hRmh28,1799
|
65
66
|
enterprise_data/management/commands/create_enterprise_offer.py,sha256=0R1eEKWTCGjod4I8qBH2UBD-erqj5mFtM_DG5Vxet_0,1150
|
66
67
|
enterprise_data/management/commands/create_enterprise_user.py,sha256=V_kvOSPZ1DXfAdF1W3AwAtavEYjdYaHBjjfzndZP8lk,1498
|
67
|
-
enterprise_data/management/commands/pre_warm_analytics_cache.py,sha256=
|
68
|
+
enterprise_data/management/commands/pre_warm_analytics_cache.py,sha256=bwqocYMc72AlgXy_SbT0EL5Aa4sLtVLtYkWSLTZmio0,8696
|
68
69
|
enterprise_data/management/commands/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
70
|
enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py,sha256=wt9fqAFKQVTqllpZ42dch-n31JavUifUIB9CKNYcnYM,1086
|
70
71
|
enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py,sha256=5CABLk8qAx8RP8mrFtnbJ4-xVkf9-5Mq6iQcx8jBfFc,1742
|
@@ -144,7 +145,7 @@ enterprise_data/tests/api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
144
145
|
enterprise_data/tests/api/v1/test_serializers.py,sha256=DwgEHcyOP3oqNUPB2O-NkJGeO_cYs9XJiq7791vJLZE,3682
|
145
146
|
enterprise_data/tests/api/v1/test_views.py,sha256=rLqUHfar0HdBNtz33hQxd_0qUUgr7Ku3KwQSQ1B4Ypg,15213
|
146
147
|
enterprise_data/tests/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
147
|
-
enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=
|
148
|
+
enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=6SXw7LcMaE-M2VSX8PHaWmOHDGXlqbI2ahNHqyBuPOk,11161
|
148
149
|
enterprise_data_roles/__init__.py,sha256=toCpbypm2uDoWVw29_em9gPFNly8vNUS__C0b4TCqEg,112
|
149
150
|
enterprise_data_roles/admin.py,sha256=QNP0VeWE092vZzpyxOA5UJK1nNGl5e71B1J0RCwo_nU,998
|
150
151
|
enterprise_data_roles/apps.py,sha256=nKi8TyuQ5Q6WGtKs5QeXvUTc3N-YQjKhyBnm2EM3Bng,260
|
@@ -178,7 +179,7 @@ enterprise_reporting/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
|
|
178
179
|
enterprise_reporting/fixtures/enterprise_customer_reporting.json,sha256=nS6E9KHW0Iqk7ZHtTyyVyrztIXxjn9OtBvMJkn7owxc,3959
|
179
180
|
enterprise_reporting/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
180
181
|
enterprise_reporting/tests/test_clients.py,sha256=h-h7xBJ6wIBKP-QqRxcJJGiQxLfTOLYByCuWfcCeCy0,8474
|
181
|
-
enterprise_reporting/tests/test_delivery_method.py,sha256=
|
182
|
+
enterprise_reporting/tests/test_delivery_method.py,sha256=p7OWkHKzl-iiA8jHXoo7TIRQees-AUryKzIq-t2MtwI,4561
|
182
183
|
enterprise_reporting/tests/test_enterprise_client.py,sha256=lpWm0muvA3alRjmlRAezE5901C9DU3WiySH4D5-U3qE,1058
|
183
184
|
enterprise_reporting/tests/test_external_link_report.py,sha256=zdnVOD1qtAp9c5EbIPnD9jcoLtW4iKs7gSVklgBK328,7029
|
184
185
|
enterprise_reporting/tests/test_reporter.py,sha256=PTmkGvPjGEjxiyizL88LAKnaWdvZDgOBjL4QStfOdyw,4057
|
@@ -186,7 +187,7 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=zBj7sDvRLJQbRs
|
|
186
187
|
enterprise_reporting/tests/test_utils.py,sha256=y4t6w9aKra-ftqtUeHvPwOhje-1npz7auV5o74ya8fE,9523
|
187
188
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
188
189
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
189
|
-
edx_enterprise_data-10.
|
190
|
-
edx_enterprise_data-10.
|
191
|
-
edx_enterprise_data-10.
|
192
|
-
edx_enterprise_data-10.
|
190
|
+
edx_enterprise_data-10.12.0.dist-info/METADATA,sha256=ug0VdbHtFCW6mtrxcaDxw6lYa72hnc6B_gMYHfAg8xA,1707
|
191
|
+
edx_enterprise_data-10.12.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
192
|
+
edx_enterprise_data-10.12.0.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
193
|
+
edx_enterprise_data-10.12.0.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
"""
|
2
|
+
Query filters for enrollments table.
|
3
|
+
"""
|
4
|
+
from enterprise_data.admin_analytics.database.filters.base import BaseFilter
|
5
|
+
from enterprise_data.admin_analytics.database.query_filters import BetweenQueryFilter, EqualQueryFilter
|
6
|
+
|
7
|
+
|
8
|
+
class FactCompletionAdminDashFilters(BaseFilter):
|
9
|
+
"""
|
10
|
+
Query filters for completions data in enrollments table.
|
11
|
+
"""
|
12
|
+
@staticmethod
|
13
|
+
def passed_date_range_filter(
|
14
|
+
start_date_params_key: str, end_date_params_key: str
|
15
|
+
) -> BetweenQueryFilter:
|
16
|
+
"""
|
17
|
+
Filter by passed date to be in the given range.
|
18
|
+
|
19
|
+
Arguments:
|
20
|
+
start_date_params_key (str): The start date key against which value will be passed in the query.
|
21
|
+
end_date_params_key (str): The end date key against which value will be passed in the query.
|
22
|
+
"""
|
23
|
+
return BetweenQueryFilter(
|
24
|
+
column='passed_date',
|
25
|
+
range_placeholders=(start_date_params_key, end_date_params_key),
|
26
|
+
)
|
27
|
+
|
28
|
+
@staticmethod
|
29
|
+
def has_passed_filter() -> EqualQueryFilter:
|
30
|
+
"""
|
31
|
+
Filter by has passed with fixed value 1.
|
32
|
+
"""
|
33
|
+
return EqualQueryFilter(
|
34
|
+
column='has_passed',
|
35
|
+
value=1
|
36
|
+
)
|
@@ -70,17 +70,15 @@ class FactEnrollmentAdminDashQueries:
|
|
70
70
|
"""
|
71
71
|
|
72
72
|
@staticmethod
|
73
|
-
def get_completion_count_query():
|
73
|
+
def get_completion_count_query(query_filters: QueryFilters) -> str:
|
74
74
|
"""
|
75
75
|
Get the query to fetch the completion count.
|
76
76
|
"""
|
77
|
-
return """
|
77
|
+
return f"""
|
78
78
|
SELECT
|
79
79
|
SUM(has_passed) as completions
|
80
80
|
FROM fact_enrollment_admin_dash
|
81
|
-
WHERE
|
82
|
-
has_passed=1 AND
|
83
|
-
passed_date BETWEEN %(start_date)s AND %(end_date)s;
|
81
|
+
WHERE {query_filters.to_sql()};
|
84
82
|
"""
|
85
83
|
|
86
84
|
@staticmethod
|
@@ -94,7 +92,7 @@ class FactEnrollmentAdminDashQueries:
|
|
94
92
|
FROM fact_engagement_admin_dash
|
95
93
|
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
96
94
|
activity_date BETWEEN %(start_date)s AND %(end_date)s;
|
97
|
-
|
95
|
+
"""
|
98
96
|
|
99
97
|
@staticmethod
|
100
98
|
def get_top_courses_by_enrollments_query(query_filters: QueryFilters, record_count: int = 10) -> str:
|
@@ -183,27 +181,28 @@ class FactEnrollmentAdminDashQueries:
|
|
183
181
|
"""
|
184
182
|
|
185
183
|
@staticmethod
|
186
|
-
def get_all_completions_query(
|
184
|
+
def get_all_completions_query(
|
185
|
+
query_filters: QueryFilters,
|
186
|
+
) -> str:
|
187
187
|
"""
|
188
188
|
Get the query to fetch all completions.
|
189
189
|
"""
|
190
|
-
return """
|
190
|
+
return f"""
|
191
191
|
SELECT email, course_title, course_subject, enroll_type, passed_date
|
192
192
|
FROM fact_enrollment_admin_dash
|
193
|
-
WHERE
|
194
|
-
has_passed=1 AND
|
195
|
-
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
193
|
+
WHERE {query_filters.to_sql()}
|
196
194
|
ORDER BY passed_date DESC LIMIT %(limit)s OFFSET %(offset)s
|
197
195
|
"""
|
198
196
|
|
199
197
|
@staticmethod
|
200
|
-
def get_top_courses_by_completions_query(record_count=10):
|
198
|
+
def get_top_courses_by_completions_query(query_filters: QueryFilters, record_count=10) -> str:
|
201
199
|
"""
|
202
200
|
Get the query to fetch the completion count by courses.
|
203
201
|
|
204
202
|
Query should fetch the top N courses by completion count. Where N is the value of record_count.
|
205
203
|
|
206
204
|
Arguments:
|
205
|
+
query_filters (QueryFilters): List of query filters.
|
207
206
|
record_count (int): Number of records to fetch.
|
208
207
|
|
209
208
|
Returns:
|
@@ -217,9 +216,7 @@ class FactEnrollmentAdminDashQueries:
|
|
217
216
|
enroll_type,
|
218
217
|
passed_date
|
219
218
|
FROM fact_enrollment_admin_dash
|
220
|
-
WHERE
|
221
|
-
enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
222
|
-
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
219
|
+
WHERE {query_filters.to_sql()}
|
223
220
|
),
|
224
221
|
top_10_courses AS (
|
225
222
|
SELECT
|
@@ -243,13 +240,14 @@ class FactEnrollmentAdminDashQueries:
|
|
243
240
|
"""
|
244
241
|
|
245
242
|
@staticmethod
|
246
|
-
def get_top_subjects_by_completions_query(record_count=10):
|
243
|
+
def get_top_subjects_by_completions_query(query_filters: QueryFilters, record_count=10) -> str:
|
247
244
|
"""
|
248
245
|
Get the query to fetch the completion count by subjects.
|
249
246
|
|
250
247
|
Query should fetch the top N subjects by completion count. Where N is the value of record_count.
|
251
248
|
|
252
249
|
Arguments:
|
250
|
+
query_filters (QueryFilters): List of query filters.
|
253
251
|
record_count (int): Number of records to fetch.
|
254
252
|
|
255
253
|
Returns:
|
@@ -262,9 +260,7 @@ class FactEnrollmentAdminDashQueries:
|
|
262
260
|
enroll_type,
|
263
261
|
passed_date
|
264
262
|
FROM fact_enrollment_admin_dash
|
265
|
-
WHERE
|
266
|
-
enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
267
|
-
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
263
|
+
WHERE {query_filters.to_sql()}
|
268
264
|
),
|
269
265
|
top_10_subjects AS (
|
270
266
|
SELECT
|
@@ -287,7 +283,9 @@ class FactEnrollmentAdminDashQueries:
|
|
287
283
|
"""
|
288
284
|
|
289
285
|
@staticmethod
|
290
|
-
def get_completions_time_series_data_query(
|
286
|
+
def get_completions_time_series_data_query(
|
287
|
+
query_filters: QueryFilters,
|
288
|
+
) -> str:
|
291
289
|
"""
|
292
290
|
Get the query to fetch the completion time series data.
|
293
291
|
|
@@ -296,12 +294,10 @@ class FactEnrollmentAdminDashQueries:
|
|
296
294
|
Returns:
|
297
295
|
(str): Query to fetch the completion time series data.
|
298
296
|
"""
|
299
|
-
return """
|
297
|
+
return f"""
|
300
298
|
SELECT passed_date, enroll_type, count(course_key) as completion_count
|
301
299
|
FROM fact_enrollment_admin_dash
|
302
|
-
WHERE
|
303
|
-
has_passed=1 AND
|
304
|
-
passed_date BETWEEN %(start_date)s AND %(end_date)s
|
300
|
+
WHERE {query_filters.to_sql()}
|
305
301
|
GROUP BY passed_date, enroll_type
|
306
302
|
ORDER BY passed_date;
|
307
303
|
"""
|
@@ -10,7 +10,7 @@ from enterprise_data.cache.decorators import cache_it
|
|
10
10
|
from enterprise_data.clients import EnterpriseApiClient
|
11
11
|
from enterprise_data.exceptions import EnterpriseApiClientException
|
12
12
|
|
13
|
-
from ..filters import FactEnrollmentAdminDashFilters
|
13
|
+
from ..filters import FactCompletionAdminDashFilters, FactEnrollmentAdminDashFilters
|
14
14
|
from ..queries import FactEnrollmentAdminDashQueries
|
15
15
|
from ..query_filters import INQueryFilter, QueryFilters
|
16
16
|
from ..utils import run_query
|
@@ -25,6 +25,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
25
25
|
"""
|
26
26
|
queries = FactEnrollmentAdminDashQueries()
|
27
27
|
filters = FactEnrollmentAdminDashFilters()
|
28
|
+
completion_filters = FactCompletionAdminDashFilters()
|
28
29
|
|
29
30
|
def __get_enterprise_user_query_filter( # pylint: disable=inconsistent-return-statements
|
30
31
|
self, group_uuid: Optional[UUID],
|
@@ -92,6 +93,45 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
92
93
|
|
93
94
|
return query_filters, params
|
94
95
|
|
96
|
+
def __get_common_query_filters_for_completion(
|
97
|
+
self, enterprise_customer_uuid: UUID,
|
98
|
+
group_uuid: Optional[UUID],
|
99
|
+
start_date: date,
|
100
|
+
end_date: date,
|
101
|
+
) -> Tuple[QueryFilters, dict]:
|
102
|
+
"""
|
103
|
+
Utility method to get query filters common in most usages below.
|
104
|
+
|
105
|
+
This will return a tuple containing the query filters list and the dictionary of query parameters that
|
106
|
+
will be used in the query.
|
107
|
+
|
108
|
+
It will contain the following query filters.
|
109
|
+
1. enterprise_customer_uuid filter to filter records for an enterprise customer.
|
110
|
+
2. enrollment_date range filter to filter records by enrollment date.
|
111
|
+
3. group_uuid filter to filter records for learners who belong to the given group.
|
112
|
+
4. has_passed filter to filter records for successful completions.
|
113
|
+
"""
|
114
|
+
query_filters = QueryFilters([
|
115
|
+
self.filters.enterprise_customer_uuid_filter('enterprise_customer_uuid'),
|
116
|
+
self.completion_filters.passed_date_range_filter('start_date', 'end_date'),
|
117
|
+
self.completion_filters.has_passed_filter(),
|
118
|
+
])
|
119
|
+
params = {
|
120
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
121
|
+
'start_date': start_date,
|
122
|
+
'end_date': end_date,
|
123
|
+
}
|
124
|
+
|
125
|
+
response = self.__get_enterprise_user_query_filter(
|
126
|
+
group_uuid, enterprise_customer_uuid
|
127
|
+
)
|
128
|
+
if response is not None:
|
129
|
+
enterprise_user_id_in_filter, enterprise_user_id_params = response
|
130
|
+
query_filters.append(enterprise_user_id_in_filter)
|
131
|
+
params.update(enterprise_user_id_params)
|
132
|
+
|
133
|
+
return query_filters, params
|
134
|
+
|
95
135
|
def get_top_enterprises(self, count=10):
|
96
136
|
"""
|
97
137
|
Get the top enterprises by enrollments.
|
@@ -232,27 +272,31 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
232
272
|
return tuple(results[0])
|
233
273
|
|
234
274
|
@cache_it()
|
235
|
-
def get_completion_count(
|
275
|
+
def get_completion_count(
|
276
|
+
self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
|
277
|
+
):
|
236
278
|
"""
|
237
279
|
Get the completion count for the given enterprise customer.
|
238
280
|
|
239
281
|
Arguments:
|
240
282
|
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
283
|
+
group_uuid (UUID): The UUID of the group.
|
241
284
|
start_date (date): The start date.
|
242
285
|
end_date (date): The end date.
|
243
286
|
|
244
287
|
Returns:
|
245
288
|
int: The completion count.
|
246
289
|
"""
|
290
|
+
query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
|
291
|
+
enterprise_customer_uuid, group_uuid, start_date, end_date
|
292
|
+
)
|
247
293
|
results = run_query(
|
248
|
-
query=self.queries.get_completion_count_query(),
|
249
|
-
params=
|
250
|
-
|
251
|
-
'start_date': start_date,
|
252
|
-
'end_date': end_date,
|
253
|
-
}
|
294
|
+
query=self.queries.get_completion_count_query(query_filters),
|
295
|
+
params=query_filter_params,
|
296
|
+
as_dict=False,
|
254
297
|
)
|
255
|
-
|
298
|
+
# Handle empty results defensively
|
299
|
+
if not results or not results[0] or len(results[0]) == 0:
|
256
300
|
return 0
|
257
301
|
|
258
302
|
return int(results[0][0] or 0)
|
@@ -347,7 +391,13 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
347
391
|
|
348
392
|
@cache_it()
|
349
393
|
def get_all_completions(
|
350
|
-
|
394
|
+
self,
|
395
|
+
enterprise_customer_uuid: UUID,
|
396
|
+
group_uuid: Optional[UUID],
|
397
|
+
start_date: date,
|
398
|
+
end_date: date,
|
399
|
+
limit: int,
|
400
|
+
offset: int,
|
351
401
|
):
|
352
402
|
"""
|
353
403
|
Get all completions for the given enterprise customer.
|
@@ -355,6 +405,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
355
405
|
Arguments:
|
356
406
|
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
357
407
|
start_date (date): The start date.
|
408
|
+
group_uuid (UUID): The UUID of the group.
|
358
409
|
end_date (date): The end date.
|
359
410
|
limit (int): The maximum number of records to return.
|
360
411
|
offset (int): The number of records to skip.
|
@@ -362,12 +413,13 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
362
413
|
Returns:
|
363
414
|
list<dict>: A list of dictionaries containing the completions data.
|
364
415
|
"""
|
416
|
+
query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
|
417
|
+
enterprise_customer_uuid, group_uuid, start_date, end_date
|
418
|
+
)
|
365
419
|
return run_query(
|
366
|
-
query=self.queries.get_all_completions_query(),
|
420
|
+
query=self.queries.get_all_completions_query(query_filters),
|
367
421
|
params={
|
368
|
-
|
369
|
-
'start_date': start_date,
|
370
|
-
'end_date': end_date,
|
422
|
+
**query_filter_params,
|
371
423
|
'limit': limit,
|
372
424
|
'offset': offset,
|
373
425
|
},
|
@@ -375,7 +427,9 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
375
427
|
)
|
376
428
|
|
377
429
|
@cache_it()
|
378
|
-
def get_top_courses_by_completions(
|
430
|
+
def get_top_courses_by_completions(
|
431
|
+
self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
|
432
|
+
):
|
379
433
|
"""
|
380
434
|
Get the top courses by completion for the given enterprise customer.
|
381
435
|
|
@@ -387,18 +441,19 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
387
441
|
Returns:
|
388
442
|
list<dict>: A list of dictionaries containing the course key, course_title and completion count.
|
389
443
|
"""
|
444
|
+
query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
|
445
|
+
enterprise_customer_uuid, group_uuid, start_date, end_date
|
446
|
+
)
|
390
447
|
return run_query(
|
391
|
-
query=self.queries.get_top_courses_by_completions_query(),
|
392
|
-
params=
|
393
|
-
'enterprise_customer_uuid': enterprise_customer_uuid,
|
394
|
-
'start_date': start_date,
|
395
|
-
'end_date': end_date,
|
396
|
-
},
|
448
|
+
query=self.queries.get_top_courses_by_completions_query(query_filters),
|
449
|
+
params=query_filter_params,
|
397
450
|
as_dict=True,
|
398
451
|
)
|
399
452
|
|
400
453
|
@cache_it()
|
401
|
-
def get_top_subjects_by_completions(
|
454
|
+
def get_top_subjects_by_completions(
|
455
|
+
self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
|
456
|
+
):
|
402
457
|
"""
|
403
458
|
Get the top subjects by completions for the given enterprise customer.
|
404
459
|
|
@@ -410,35 +465,36 @@ class FactEnrollmentAdminDashTable(BaseTable):
|
|
410
465
|
Returns:
|
411
466
|
list<dict>: A list of dictionaries containing the subject and completion count.
|
412
467
|
"""
|
468
|
+
query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
|
469
|
+
enterprise_customer_uuid, group_uuid, start_date, end_date
|
470
|
+
)
|
413
471
|
return run_query(
|
414
|
-
query=self.queries.get_top_subjects_by_completions_query(),
|
415
|
-
params=
|
416
|
-
'enterprise_customer_uuid': enterprise_customer_uuid,
|
417
|
-
'start_date': start_date,
|
418
|
-
'end_date': end_date,
|
419
|
-
},
|
472
|
+
query=self.queries.get_top_subjects_by_completions_query(query_filters),
|
473
|
+
params=query_filter_params,
|
420
474
|
as_dict=True,
|
421
475
|
)
|
422
476
|
|
423
477
|
@cache_it()
|
424
|
-
def get_completions_time_series_data(
|
478
|
+
def get_completions_time_series_data(
|
479
|
+
self, enterprise_customer_uuid: UUID, group_uuid: Optional[UUID], start_date: date, end_date: date
|
480
|
+
):
|
425
481
|
"""
|
426
482
|
Get the completions time series data for the given enterprise customer.
|
427
483
|
|
428
484
|
Arguments:
|
429
485
|
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
486
|
+
group_uuid (UUID): The UUID of the group.
|
430
487
|
start_date (date): The start date.
|
431
488
|
end_date (date): The end date.
|
432
489
|
|
433
490
|
Returns:
|
434
491
|
list<dict>: A list of dictionaries containing the date and completion count.
|
435
492
|
"""
|
493
|
+
query_filters, query_filter_params = self.__get_common_query_filters_for_completion(
|
494
|
+
enterprise_customer_uuid, group_uuid, start_date, end_date
|
495
|
+
)
|
436
496
|
return run_query(
|
437
|
-
query=self.queries.get_completions_time_series_data_query(),
|
438
|
-
params=
|
439
|
-
'enterprise_customer_uuid': enterprise_customer_uuid,
|
440
|
-
'start_date': start_date,
|
441
|
-
'end_date': end_date,
|
442
|
-
},
|
497
|
+
query=self.queries.get_completions_time_series_data_query(query_filters),
|
498
|
+
params=query_filter_params,
|
443
499
|
as_dict=True,
|
444
500
|
)
|
@@ -262,6 +262,7 @@ class AdminAnalyticsAggregatesQueryParamsSerializer(serializers.Serializer): #
|
|
262
262
|
response_type = serializers.CharField(required=False)
|
263
263
|
page = serializers.IntegerField(required=False)
|
264
264
|
chart_type = serializers.CharField(required=False)
|
265
|
+
group_uuid = serializers.UUIDField(required=False)
|
265
266
|
|
266
267
|
def validate(self, attrs):
|
267
268
|
"""
|
@@ -51,10 +51,12 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
51
51
|
# get values from query params or use default values
|
52
52
|
start_date = serializer.data.get('start_date', min_enrollment_date)
|
53
53
|
end_date = serializer.data.get('end_date', date.today())
|
54
|
+
group_uuid = serializer.data.get('group_uuid')
|
54
55
|
page = serializer.data.get('page', 1)
|
55
56
|
page_size = serializer.data.get('page_size', 100)
|
56
57
|
completions = FactEnrollmentAdminDashTable().get_all_completions(
|
57
58
|
enterprise_customer_uuid=enterprise_uuid,
|
59
|
+
group_uuid=group_uuid,
|
58
60
|
start_date=start_date,
|
59
61
|
end_date=end_date,
|
60
62
|
limit=page_size,
|
@@ -62,6 +64,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
62
64
|
)
|
63
65
|
total_count = FactEnrollmentAdminDashTable().get_completion_count(
|
64
66
|
enterprise_customer_uuid=enterprise_uuid,
|
67
|
+
group_uuid=group_uuid,
|
65
68
|
start_date=start_date,
|
66
69
|
end_date=end_date,
|
67
70
|
)
|
@@ -79,7 +82,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
79
82
|
|
80
83
|
return StreamingHttpResponse(
|
81
84
|
IndividualCompletionsCSVRenderer().render(self._stream_serialized_data(
|
82
|
-
enterprise_uuid, start_date, end_date, total_count
|
85
|
+
enterprise_uuid, group_uuid, start_date, end_date, total_count
|
83
86
|
)),
|
84
87
|
content_type="text/csv",
|
85
88
|
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
@@ -94,7 +97,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
94
97
|
)
|
95
98
|
|
96
99
|
@staticmethod
|
97
|
-
def _stream_serialized_data(enterprise_uuid, start_date, end_date, total_count, page_size=50000):
|
100
|
+
def _stream_serialized_data(enterprise_uuid, group_uuid, start_date, end_date, total_count, page_size=50000):
|
98
101
|
"""
|
99
102
|
Stream the serialized data.
|
100
103
|
"""
|
@@ -102,6 +105,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
102
105
|
while offset < total_count:
|
103
106
|
completions = FactEnrollmentAdminDashTable().get_all_completions(
|
104
107
|
enterprise_customer_uuid=enterprise_uuid,
|
108
|
+
group_uuid=group_uuid,
|
105
109
|
start_date=start_date,
|
106
110
|
end_date=end_date,
|
107
111
|
limit=page_size,
|
@@ -133,16 +137,18 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
|
|
133
137
|
# get values from query params or use default
|
134
138
|
start_date = serializer.data.get('start_date', min_enrollment_date)
|
135
139
|
end_date = serializer.data.get('end_date', date.today())
|
140
|
+
group_uuid = serializer.data.get('group_uuid')
|
141
|
+
|
136
142
|
with timer('construct_completion_all_stats'):
|
137
143
|
data = {
|
138
144
|
'completions_over_time': FactEnrollmentAdminDashTable().get_completions_time_series_data(
|
139
|
-
enterprise_uuid, start_date, end_date
|
145
|
+
enterprise_uuid, group_uuid, start_date, end_date
|
140
146
|
),
|
141
147
|
'top_courses_by_completions': FactEnrollmentAdminDashTable().get_top_courses_by_completions(
|
142
|
-
enterprise_uuid, start_date, end_date,
|
148
|
+
enterprise_uuid, group_uuid, start_date, end_date,
|
143
149
|
),
|
144
150
|
'top_subjects_by_completions': FactEnrollmentAdminDashTable().get_top_subjects_by_completions(
|
145
|
-
enterprise_uuid, start_date, end_date,
|
151
|
+
enterprise_uuid, group_uuid, start_date, end_date,
|
146
152
|
),
|
147
153
|
}
|
148
154
|
return Response(data)
|
@@ -108,12 +108,13 @@ class EnterpriseAdminAnalyticsAggregatesView(APIView):
|
|
108
108
|
'start_date', min_enrollment_date
|
109
109
|
)
|
110
110
|
end_date = serializer.data.get('end_date', datetime.today())
|
111
|
+
group_uuid = serializer.data.get('group_uuid', None)
|
111
112
|
|
112
113
|
enrolls, courses = FactEnrollmentAdminDashTable().get_enrollment_and_course_count(
|
113
114
|
enterprise_id, start_date, end_date,
|
114
115
|
)
|
115
116
|
completions = FactEnrollmentAdminDashTable().get_completion_count(
|
116
|
-
enterprise_id, start_date, end_date,
|
117
|
+
enterprise_id, group_uuid, start_date, end_date,
|
117
118
|
)
|
118
119
|
hours, sessions = FactEngagementAdminDashTable().get_learning_hours_and_daily_sessions(
|
119
120
|
enterprise_id, start_date, end_date,
|
@@ -56,6 +56,7 @@ class Command(BaseCommand):
|
|
56
56
|
)
|
57
57
|
enterprise_enrollment_table.get_completion_count(
|
58
58
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
59
|
+
group_uuid=None,
|
59
60
|
start_date=start_date,
|
60
61
|
end_date=end_date,
|
61
62
|
)
|
@@ -95,6 +96,7 @@ class Command(BaseCommand):
|
|
95
96
|
page_size = 100
|
96
97
|
enterprise_enrollment_table.get_all_completions(
|
97
98
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
99
|
+
group_uuid=None,
|
98
100
|
start_date=start_date,
|
99
101
|
end_date=end_date,
|
100
102
|
limit=page_size,
|
@@ -102,21 +104,25 @@ class Command(BaseCommand):
|
|
102
104
|
)
|
103
105
|
enterprise_enrollment_table.get_completion_count(
|
104
106
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
107
|
+
group_uuid=None,
|
105
108
|
start_date=start_date,
|
106
109
|
end_date=end_date,
|
107
110
|
)
|
108
111
|
enterprise_enrollment_table.get_top_courses_by_completions(
|
109
112
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
113
|
+
group_uuid=None,
|
110
114
|
start_date=start_date,
|
111
115
|
end_date=end_date,
|
112
116
|
)
|
113
117
|
enterprise_enrollment_table.get_top_subjects_by_completions(
|
114
118
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
119
|
+
group_uuid=None,
|
115
120
|
start_date=start_date,
|
116
121
|
end_date=end_date,
|
117
122
|
)
|
118
123
|
enterprise_enrollment_table.get_completions_time_series_data(
|
119
124
|
enterprise_customer_uuid=enterprise_customer_uuid,
|
125
|
+
group_uuid=None,
|
120
126
|
start_date=start_date,
|
121
127
|
end_date=end_date,
|
122
128
|
)
|
@@ -62,6 +62,10 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
|
|
62
62
|
"""
|
63
63
|
mock implementation of run_query.
|
64
64
|
"""
|
65
|
+
# Check if this is the completion_count_query being called with query_filters
|
66
|
+
if hasattr(query, '__name__') and query.__name__ == 'get_completion_count_query':
|
67
|
+
return [[50]]
|
68
|
+
|
65
69
|
mock_responses = {
|
66
70
|
self.enrollment_queries.get_enrollment_date_range_query(): [[
|
67
71
|
datetime.strptime('2021-01-01', "%Y-%m-%d"),
|
@@ -70,15 +74,12 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
|
|
70
74
|
self.enrollment_queries.get_enrollment_and_course_count_query(): [[
|
71
75
|
100, 10
|
72
76
|
]],
|
73
|
-
self.enrollment_queries.get_completion_count_query(): [[
|
74
|
-
50
|
75
|
-
]],
|
76
77
|
self.engagement_queries.get_learning_hours_and_daily_sessions_query(): [[
|
77
78
|
100, 10
|
78
79
|
]],
|
79
80
|
'SELECT MAX(created) FROM enterprise_learner_enrollment': [[datetime.strptime('2021-01-01', "%Y-%m-%d")]]
|
80
81
|
}
|
81
|
-
return mock_responses[
|
82
|
+
return mock_responses.get(query, [[]])
|
82
83
|
|
83
84
|
def test_get_admin_analytics_aggregates(self):
|
84
85
|
"""
|
@@ -5,8 +5,8 @@ Test delivery methods.
|
|
5
5
|
import unittest
|
6
6
|
|
7
7
|
import ddt
|
8
|
+
from mock import MagicMock, patch
|
8
9
|
|
9
|
-
from mock import patch, MagicMock
|
10
10
|
from enterprise_reporting.delivery_method import SFTPDeliveryMethod, SMTPDeliveryMethod
|
11
11
|
from enterprise_reporting.utils import encrypt_string
|
12
12
|
|
File without changes
|
{edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{edx_enterprise_data-10.11.1.dist-info → edx_enterprise_data-10.12.0.dist-info}/top_level.txt
RENAMED
File without changes
|