edx-enterprise-data 8.10.0__py3-none-any.whl → 8.11.1__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-8.10.0.dist-info → edx_enterprise_data-8.11.1.dist-info}/METADATA +1 -1
- {edx_enterprise_data-8.10.0.dist-info → edx_enterprise_data-8.11.1.dist-info}/RECORD +17 -9
- enterprise_data/__init__.py +1 -1
- enterprise_data/admin_analytics/database/__init__.py +4 -0
- enterprise_data/admin_analytics/database/queries/__init__.py +5 -0
- enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +21 -0
- enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +61 -0
- enterprise_data/admin_analytics/database/tables/__init__.py +5 -0
- enterprise_data/admin_analytics/database/tables/base.py +18 -0
- enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +38 -0
- enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +85 -0
- enterprise_data/admin_analytics/{database.py → database/utils.py} +3 -2
- enterprise_data/api/v1/views/enterprise_admin.py +16 -44
- enterprise_data/tests/api/v1/views/test_enterprise_admin.py +43 -20
- {edx_enterprise_data-8.10.0.dist-info → edx_enterprise_data-8.11.1.dist-info}/LICENSE +0 -0
- {edx_enterprise_data-8.10.0.dist-info → edx_enterprise_data-8.11.1.dist-info}/WHEEL +0 -0
- {edx_enterprise_data-8.10.0.dist-info → edx_enterprise_data-8.11.1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
enterprise_data/__init__.py,sha256=
|
1
|
+
enterprise_data/__init__.py,sha256=XT15XKKqKMAKtb0mKrGHjwWzDy3Y_AMCd_U5UKSh5Rc,124
|
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
|
@@ -13,8 +13,16 @@ enterprise_data/admin_analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
13
13
|
enterprise_data/admin_analytics/completions_utils.py,sha256=kGmLy7x6aD0coNYgzLa5XzJypLkGTT5clDHLSH_QFDE,9442
|
14
14
|
enterprise_data/admin_analytics/constants.py,sha256=7WturLuMISekgcHHlgj45PPdPrDTYM-l21lA8-Q_Tfc,1107
|
15
15
|
enterprise_data/admin_analytics/data_loaders.py,sha256=4PSsIveNBtpFqwrLUjTl5oywHVYFAMdZrNRHRGMk4XY,6116
|
16
|
-
enterprise_data/admin_analytics/database.py,sha256=mNS_9xE5h6O7oMMzr6kr6LDTTSNvKzo8vaM-YG8tOd8,1312
|
17
16
|
enterprise_data/admin_analytics/utils.py,sha256=CQuTlg36AALJiopp4us-JN8oTXsw-jDXSJenbphLDME,12270
|
17
|
+
enterprise_data/admin_analytics/database/__init__.py,sha256=vNSWKf2VV5xMegN7htJJtxtQEb0ASLC6frE2w0ZpYpE,104
|
18
|
+
enterprise_data/admin_analytics/database/utils.py,sha256=Zl-W_w5SVb-QpIwWxbHr0w7z4L2ZFeruJSygWh8g7II,1408
|
19
|
+
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=fq01Ni_sKnvSRoiPQfTnJ8TtRePQe5MBLmI5CpVy36o,747
|
21
|
+
enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py,sha256=X1muOEhEvqD-tyhrVEQkPrf8_7g7SPaJuMwriUPo3jw,2062
|
22
|
+
enterprise_data/admin_analytics/database/tables/__init__.py,sha256=3ECKlKlz1wuTER5M57CMFvmLFp0oCnVQXAUeTN96Bs0,213
|
23
|
+
enterprise_data/admin_analytics/database/tables/base.py,sha256=1KyKsC18pW3m-5U-T6pdt5rIwsz6Wp3QFFbD3r6L6YQ,395
|
24
|
+
enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py,sha256=EsG8KgRW84wtA_nJuUknjLYlDtaPSJf_9mWdkO2Bj2I,1293
|
25
|
+
enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py,sha256=WiFWVF4TsDhLlDQr-3FuqTrzFy7Qv1Y5EnwZXYhdTrM,2962
|
18
26
|
enterprise_data/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
27
|
enterprise_data/api/urls.py,sha256=POqc_KATHdnpMf9zHtpO46pKD5KAlAExtx7G6iylLcU,273
|
20
28
|
enterprise_data/api/v0/__init__.py,sha256=1aAzAYU5hk-RW6cKUxa1645cbZMxn7GIZ7OMjWc9MKI,46
|
@@ -30,7 +38,7 @@ enterprise_data/api/v1/views/analytics_engagements.py,sha256=8H3Fk-hTqJaU3H5Lpu1
|
|
30
38
|
enterprise_data/api/v1/views/analytics_enrollments.py,sha256=trC92GOej6vUoju53KT3dPEDnoPHdukfXEIXPThz76A,16886
|
31
39
|
enterprise_data/api/v1/views/analytics_leaderboard.py,sha256=2DALqzUIbe4-ZGgHHIkYAKJ5L1ik2ruPtQNYtTdPba4,5974
|
32
40
|
enterprise_data/api/v1/views/base.py,sha256=FTAxlz5EzvAY657wzVgzhJPFSCHHzct7IDcvm71Smt8,866
|
33
|
-
enterprise_data/api/v1/views/enterprise_admin.py,sha256=
|
41
|
+
enterprise_data/api/v1/views/enterprise_admin.py,sha256=d79WkyBbqLk6pKGWWrnbYdrbOgQztP03Q7NKRA5tZB4,8639
|
34
42
|
enterprise_data/api/v1/views/enterprise_completions.py,sha256=bJG2ZtTbLyiBrj64iJHQNHEKLrJCzl9OuJ7nDtw-9aY,8377
|
35
43
|
enterprise_data/api/v1/views/enterprise_learner.py,sha256=yABjJje3CT8I8YOhWr1_tTkdKtnGJom8eu3EFz_-0BU,18517
|
36
44
|
enterprise_data/api/v1/views/enterprise_offers.py,sha256=VifxgqTLFLVw4extYPlHcN1N_yjXcsYsAlYEnAbpb10,1266
|
@@ -120,7 +128,7 @@ enterprise_data/tests/api/v1/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
120
128
|
enterprise_data/tests/api/v1/test_serializers.py,sha256=DwgEHcyOP3oqNUPB2O-NkJGeO_cYs9XJiq7791vJLZE,3682
|
121
129
|
enterprise_data/tests/api/v1/test_views.py,sha256=rLqUHfar0HdBNtz33hQxd_0qUUgr7Ku3KwQSQ1B4Ypg,15213
|
122
130
|
enterprise_data/tests/api/v1/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
123
|
-
enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=
|
131
|
+
enterprise_data/tests/api/v1/views/test_enterprise_admin.py,sha256=i0A1JqG1YQTVRiXviFPbx385p7YhMxew72lgTZ7YNEg,6173
|
124
132
|
enterprise_data_roles/__init__.py,sha256=toCpbypm2uDoWVw29_em9gPFNly8vNUS__C0b4TCqEg,112
|
125
133
|
enterprise_data_roles/admin.py,sha256=QNP0VeWE092vZzpyxOA5UJK1nNGl5e71B1J0RCwo_nU,998
|
126
134
|
enterprise_data_roles/apps.py,sha256=nKi8TyuQ5Q6WGtKs5QeXvUTc3N-YQjKhyBnm2EM3Bng,260
|
@@ -161,8 +169,8 @@ enterprise_reporting/tests/test_send_enterprise_reports.py,sha256=WtL-RqGgu2x5PP
|
|
161
169
|
enterprise_reporting/tests/test_utils.py,sha256=Zt_TA0LVb-B6fQGkUkAKKVlUKKnQh8jnw1US1jKe7g8,9493
|
162
170
|
enterprise_reporting/tests/test_vertica_client.py,sha256=-R2yNCGUjRtoXwLMBloVFQkFYrJoo613VCr61gwI3kQ,140
|
163
171
|
enterprise_reporting/tests/utils.py,sha256=xms2LM7DV3wczXEfctOK1ddel1EE0J_YSr17UzbCDy4,1401
|
164
|
-
edx_enterprise_data-8.
|
165
|
-
edx_enterprise_data-8.
|
166
|
-
edx_enterprise_data-8.
|
167
|
-
edx_enterprise_data-8.
|
168
|
-
edx_enterprise_data-8.
|
172
|
+
edx_enterprise_data-8.11.1.dist-info/LICENSE,sha256=dql8h4yceoMhuzlcK0TT_i-NgTFNIZsgE47Q4t3dUYI,34520
|
173
|
+
edx_enterprise_data-8.11.1.dist-info/METADATA,sha256=27UVJwZuQylIJzEZ-R-VWbzisk0jOxS04oHJNrjLQTw,1570
|
174
|
+
edx_enterprise_data-8.11.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
175
|
+
edx_enterprise_data-8.11.1.dist-info/top_level.txt,sha256=f5F2kU-dob6MqiHJpgZkFzoCD5VMhsdpkTV5n9Tvq3I,59
|
176
|
+
edx_enterprise_data-8.11.1.dist-info/RECORD,,
|
enterprise_data/__init__.py
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
"""
|
2
|
+
Module containing queries for the fact_enrollment_engagement_day_admin_dash table.
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
class FactEngagementAdminDashQueries:
|
7
|
+
"""
|
8
|
+
Queries related to the fact_enrollment_engagement_day_admin_dash table.
|
9
|
+
"""
|
10
|
+
@staticmethod
|
11
|
+
def get_learning_hours_and_daily_sessions_query():
|
12
|
+
"""
|
13
|
+
Get the query to fetch the learning hours and daily sessions.
|
14
|
+
"""
|
15
|
+
return """
|
16
|
+
SELECT
|
17
|
+
ROUND(SUM(learning_time_seconds) / 60 / 60, 1) as hours, SUM(is_engaged) as sessions
|
18
|
+
FROM fact_enrollment_engagement_day_admin_dash
|
19
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
20
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s;
|
21
|
+
"""
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"""
|
2
|
+
Module containing queries for the fact_enrollment_admin_dash table.
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
class FactEnrollmentAdminDashQueries:
|
7
|
+
"""
|
8
|
+
Queries related to the fact_enrollment_admin_dash table.
|
9
|
+
"""
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def get_enrollment_date_range_query():
|
13
|
+
"""
|
14
|
+
Get the query to fetch the enrollment date range.
|
15
|
+
"""
|
16
|
+
return """
|
17
|
+
SELECT
|
18
|
+
MIN(enterprise_enrollment_date) AS min_enrollment_date,
|
19
|
+
MAX(enterprise_enrollment_date) AS max_enrollment_date
|
20
|
+
FROM fact_enrollment_admin_dash
|
21
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s;
|
22
|
+
"""
|
23
|
+
|
24
|
+
@staticmethod
|
25
|
+
def get_enrollment_and_course_count_query():
|
26
|
+
"""
|
27
|
+
Get the query to fetch the enrollment and course count.
|
28
|
+
"""
|
29
|
+
return """
|
30
|
+
SELECT
|
31
|
+
count(*) as enrolls, count(DISTINCT course_key) as courses
|
32
|
+
FROM fact_enrollment_admin_dash
|
33
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
34
|
+
enterprise_enrollment_date BETWEEN %(start_date)s AND %(end_date)s;
|
35
|
+
"""
|
36
|
+
|
37
|
+
@staticmethod
|
38
|
+
def get_completion_count_query():
|
39
|
+
"""
|
40
|
+
Get the query to fetch the completion count.
|
41
|
+
"""
|
42
|
+
return """
|
43
|
+
SELECT
|
44
|
+
SUM(has_passed) as completions
|
45
|
+
FROM fact_enrollment_admin_dash
|
46
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
47
|
+
passed_date BETWEEN %(start_date)s AND %(end_date)s;
|
48
|
+
"""
|
49
|
+
|
50
|
+
@staticmethod
|
51
|
+
def get_learning_hours_and_daily_sessions_query():
|
52
|
+
"""
|
53
|
+
Get the query to fetch the learning hours and daily sessions.
|
54
|
+
"""
|
55
|
+
return """
|
56
|
+
SELECT
|
57
|
+
ROUND(SUM(learning_time_seconds) / 60 / 60, 1) as hours, SUM(is_engaged) as sessions
|
58
|
+
FROM fact_engagement_admin_dash
|
59
|
+
WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
|
60
|
+
activity_date BETWEEN %(start_date)s AND %(end_date)s;
|
61
|
+
"""
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"""
|
2
|
+
Base class to store the table information.
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
class BaseTable:
|
7
|
+
"""
|
8
|
+
Singleton class to store the table information.
|
9
|
+
"""
|
10
|
+
instance = None
|
11
|
+
|
12
|
+
def __new__(cls):
|
13
|
+
"""
|
14
|
+
Singleton method to create a single instance of the table.
|
15
|
+
"""
|
16
|
+
if cls.instance is None:
|
17
|
+
cls.instance = super(BaseTable, cls).__new__(cls)
|
18
|
+
return cls.instance
|
@@ -0,0 +1,38 @@
|
|
1
|
+
"""
|
2
|
+
Module for interacting with the fact_enrollment_engagement_day_admin_dash table.
|
3
|
+
"""
|
4
|
+
from datetime import date
|
5
|
+
from uuid import UUID
|
6
|
+
|
7
|
+
from ..queries import FactEngagementAdminDashQueries
|
8
|
+
from ..utils import run_query
|
9
|
+
from .base import BaseTable
|
10
|
+
|
11
|
+
|
12
|
+
class FactEngagementAdminDashTable(BaseTable):
|
13
|
+
"""
|
14
|
+
Class for communicating with the fact_enrollment_engagement_day_admin_dash table.
|
15
|
+
"""
|
16
|
+
queries = FactEngagementAdminDashQueries()
|
17
|
+
|
18
|
+
def get_learning_hours_and_daily_sessions(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
19
|
+
"""
|
20
|
+
Get the learning hours and daily sessions for the given enterprise customer.
|
21
|
+
|
22
|
+
Arguments:
|
23
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
24
|
+
start_date (date): The start date.
|
25
|
+
end_date (date): The end date.
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
(tuple<float, int>): The learning hours and daily sessions.
|
29
|
+
"""
|
30
|
+
results = run_query(
|
31
|
+
query=self.queries.get_learning_hours_and_daily_sessions_query(),
|
32
|
+
params={
|
33
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
34
|
+
'start_date': start_date,
|
35
|
+
'end_date': end_date,
|
36
|
+
}
|
37
|
+
)
|
38
|
+
return tuple(results[0])
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"""
|
2
|
+
Module for interacting with the fact_enrollment_admin_dash table.
|
3
|
+
"""
|
4
|
+
from datetime import date, datetime
|
5
|
+
from uuid import UUID
|
6
|
+
|
7
|
+
from ..queries import FactEnrollmentAdminDashQueries
|
8
|
+
from ..utils import run_query
|
9
|
+
from .base import BaseTable
|
10
|
+
|
11
|
+
|
12
|
+
class FactEnrollmentAdminDashTable(BaseTable):
|
13
|
+
"""
|
14
|
+
Class for communicating with the fact_enrollment_admin_dash table.
|
15
|
+
"""
|
16
|
+
queries = FactEnrollmentAdminDashQueries()
|
17
|
+
|
18
|
+
def get_enrollment_date_range(self, enterprise_customer_uuid: UUID):
|
19
|
+
"""
|
20
|
+
Get the enrollment date range for the given enterprise customer.
|
21
|
+
|
22
|
+
Arguments:
|
23
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
(tuple<date, date>): The minimum and maximum enrollment dates.
|
27
|
+
"""
|
28
|
+
results = run_query(
|
29
|
+
query=self.queries.get_enrollment_date_range_query(),
|
30
|
+
params={'enterprise_customer_uuid': enterprise_customer_uuid}
|
31
|
+
)
|
32
|
+
min_date, max_date = results[0]
|
33
|
+
|
34
|
+
# We should return date objects, not datetime objects
|
35
|
+
# This is done to counter cases where database values are datetime objects.
|
36
|
+
if min_date and isinstance(min_date, datetime):
|
37
|
+
min_date = min_date.date()
|
38
|
+
if max_date and isinstance(max_date, datetime):
|
39
|
+
max_date = max_date.date()
|
40
|
+
|
41
|
+
return min_date, max_date
|
42
|
+
|
43
|
+
def get_enrollment_and_course_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
44
|
+
"""
|
45
|
+
Get the enrollment and course count for the given enterprise customer.
|
46
|
+
|
47
|
+
Arguments:
|
48
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
49
|
+
start_date (date): The start date.
|
50
|
+
end_date (date): The end date.
|
51
|
+
|
52
|
+
Returns:
|
53
|
+
(tuple<int, int>): The enrollment and course count.
|
54
|
+
"""
|
55
|
+
results = run_query(
|
56
|
+
query=self.queries.get_enrollment_and_course_count_query(),
|
57
|
+
params={
|
58
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
59
|
+
'start_date': start_date,
|
60
|
+
'end_date': end_date,
|
61
|
+
}
|
62
|
+
)
|
63
|
+
return tuple(results[0])
|
64
|
+
|
65
|
+
def get_completion_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
|
66
|
+
"""
|
67
|
+
Get the completion count for the given enterprise customer.
|
68
|
+
|
69
|
+
Arguments:
|
70
|
+
enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
|
71
|
+
start_date (date): The start date.
|
72
|
+
end_date (date): The end date.
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
int: The completion count.
|
76
|
+
"""
|
77
|
+
results = run_query(
|
78
|
+
query=self.queries.get_completion_count_query(),
|
79
|
+
params={
|
80
|
+
'enterprise_customer_uuid': enterprise_customer_uuid,
|
81
|
+
'start_date': start_date,
|
82
|
+
'end_date': end_date,
|
83
|
+
}
|
84
|
+
)
|
85
|
+
return results[0][0]
|
@@ -30,12 +30,13 @@ def get_db_connection(database=settings.ENTERPRISE_REPORTING_DB_ALIAS):
|
|
30
30
|
|
31
31
|
|
32
32
|
@timeit
|
33
|
-
def run_query(query):
|
33
|
+
def run_query(query, params: dict = None):
|
34
34
|
"""
|
35
35
|
Run a query on the database and return the results.
|
36
36
|
|
37
37
|
Arguments:
|
38
38
|
query (str): The query to run.
|
39
|
+
params (dict): The parameters to pass to the query.
|
39
40
|
|
40
41
|
Returns:
|
41
42
|
(list): The results of the query.
|
@@ -43,7 +44,7 @@ def run_query(query):
|
|
43
44
|
try:
|
44
45
|
with closing(get_db_connection()) as connection:
|
45
46
|
with closing(connection.cursor()) as cursor:
|
46
|
-
cursor.execute(query)
|
47
|
+
cursor.execute(query, params=params)
|
47
48
|
return cursor.fetchall()
|
48
49
|
except Exception:
|
49
50
|
LOGGER.exception(f'[run_query]: run_query failed for query "{query}".')
|
@@ -13,9 +13,9 @@ from rest_framework.views import APIView
|
|
13
13
|
from django.http import HttpResponse
|
14
14
|
|
15
15
|
from enterprise_data.admin_analytics.data_loaders import fetch_max_enrollment_datetime
|
16
|
+
from enterprise_data.admin_analytics.database.tables import FactEngagementAdminDashTable, FactEnrollmentAdminDashTable
|
16
17
|
from enterprise_data.admin_analytics.utils import (
|
17
18
|
ChartType,
|
18
|
-
fetch_and_cache_engagements_data,
|
19
19
|
fetch_and_cache_enrollments_data,
|
20
20
|
fetch_and_cache_skills_data,
|
21
21
|
get_skills_chart_data,
|
@@ -27,7 +27,7 @@ from enterprise_data.models import (
|
|
27
27
|
EnterpriseAdminSummarizeInsights,
|
28
28
|
EnterpriseExecEdLCModulePerformance,
|
29
29
|
)
|
30
|
-
from enterprise_data.utils import
|
30
|
+
from enterprise_data.utils import timer
|
31
31
|
|
32
32
|
from .base import EnterpriseViewSetMixin
|
33
33
|
|
@@ -95,61 +95,33 @@ class EnterpriseAdminAnalyticsAggregatesView(APIView):
|
|
95
95
|
"""
|
96
96
|
HTTP GET endpoint to retrieve the enterprise admin aggregate data.
|
97
97
|
"""
|
98
|
+
# Validate the enterprise_id
|
99
|
+
enterprise_id = enterprise_id.replace('-', '')
|
98
100
|
serializer = serializers.AdminAnalyticsAggregatesQueryParamsSerializer(
|
99
101
|
data=request.GET
|
100
102
|
)
|
101
103
|
serializer.is_valid(raise_exception=True)
|
102
104
|
|
103
105
|
last_updated_at = fetch_max_enrollment_datetime()
|
104
|
-
|
105
|
-
|
106
|
+
min_enrollment_date, max_enrollment_date = FactEnrollmentAdminDashTable().get_enrollment_date_range(
|
107
|
+
enterprise_id,
|
106
108
|
)
|
107
109
|
|
108
|
-
enrollment = fetch_and_cache_enrollments_data(
|
109
|
-
enterprise_id, cache_expiry
|
110
|
-
).copy()
|
111
|
-
engagement = fetch_and_cache_engagements_data(
|
112
|
-
enterprise_id, cache_expiry
|
113
|
-
).copy()
|
114
|
-
# Use start and end date if provided by the client, if client has not provided then use
|
115
|
-
# 1. minimum enrollment date from the data as the start_date
|
116
|
-
# 2. today's date as the end_date
|
117
110
|
start_date = serializer.data.get(
|
118
|
-
'start_date',
|
111
|
+
'start_date', min_enrollment_date
|
119
112
|
)
|
120
|
-
end_date = serializer.data.get('end_date', datetime.
|
113
|
+
end_date = serializer.data.get('end_date', datetime.today())
|
121
114
|
|
122
|
-
|
123
|
-
|
124
|
-
start=start_date,
|
125
|
-
end=end_date,
|
126
|
-
data_frame=enrollment.copy(),
|
127
|
-
date_column='enterprise_enrollment_date',
|
115
|
+
enrolls, courses = FactEnrollmentAdminDashTable().get_enrollment_and_course_count(
|
116
|
+
enterprise_id, start_date, end_date,
|
128
117
|
)
|
129
|
-
|
130
|
-
|
131
|
-
courses = len(dff.course_key.unique())
|
132
|
-
|
133
|
-
dff = date_filter(
|
134
|
-
start=start_date,
|
135
|
-
end=end_date,
|
136
|
-
data_frame=enrollment.copy(),
|
137
|
-
date_column='passed_date',
|
118
|
+
completions = FactEnrollmentAdminDashTable().get_completion_count(
|
119
|
+
enterprise_id, start_date, end_date,
|
138
120
|
)
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
# Date filtering.
|
143
|
-
dff = date_filter(
|
144
|
-
start=start_date,
|
145
|
-
end=end_date,
|
146
|
-
data_frame=engagement.copy(),
|
147
|
-
date_column='activity_date',
|
121
|
+
hours, sessions = FactEngagementAdminDashTable().get_learning_hours_and_daily_sessions(
|
122
|
+
enterprise_id, start_date, end_date,
|
148
123
|
)
|
149
124
|
|
150
|
-
hours = round(dff.learning_time_seconds.sum() / 60 / 60, 1)
|
151
|
-
sessions = dff.is_engaged.sum()
|
152
|
-
|
153
125
|
return Response(
|
154
126
|
data={
|
155
127
|
'enrolls': enrolls,
|
@@ -158,8 +130,8 @@ class EnterpriseAdminAnalyticsAggregatesView(APIView):
|
|
158
130
|
'hours': hours,
|
159
131
|
'sessions': sessions,
|
160
132
|
'last_updated_at': last_updated_at.date() if last_updated_at else None,
|
161
|
-
'min_enrollment_date':
|
162
|
-
'max_enrollment_date':
|
133
|
+
'min_enrollment_date': min_enrollment_date,
|
134
|
+
'max_enrollment_date': max_enrollment_date,
|
163
135
|
},
|
164
136
|
status=HTTP_200_OK,
|
165
137
|
)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
Test cases for enterprise_admin views
|
3
3
|
"""
|
4
|
+
from datetime import datetime
|
4
5
|
from unittest import mock
|
5
6
|
from uuid import uuid4
|
6
7
|
|
@@ -11,10 +12,13 @@ from rest_framework import status
|
|
11
12
|
from rest_framework.reverse import reverse
|
12
13
|
from rest_framework.test import APITransactionTestCase
|
13
14
|
|
15
|
+
from enterprise_data.admin_analytics.database.queries import (
|
16
|
+
FactEngagementAdminDashQueries,
|
17
|
+
FactEnrollmentAdminDashQueries,
|
18
|
+
)
|
14
19
|
from enterprise_data.tests.mixins import JWTTestMixin
|
15
20
|
from enterprise_data.tests.test_utils import (
|
16
21
|
UserFactory,
|
17
|
-
get_dummy_engagements_data,
|
18
22
|
get_dummy_enrollments_data,
|
19
23
|
get_dummy_enterprise_api_data,
|
20
24
|
get_dummy_skills_data,
|
@@ -52,19 +56,30 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
|
|
52
56
|
self.addCleanup(mocked_get_enterprise_customer.stop)
|
53
57
|
self.enterprise_id = 'ee5e6b3a-069a-4947-bb8d-d2dbc323396c'
|
54
58
|
self.set_jwt_cookie()
|
59
|
+
self.enrollment_queries = FactEnrollmentAdminDashQueries()
|
60
|
+
self.engagement_queries = FactEngagementAdminDashQueries()
|
55
61
|
|
56
|
-
def _mock_run_query(self, query):
|
62
|
+
def _mock_run_query(self, query, *args, **kwargs):
|
57
63
|
"""
|
58
64
|
mock implementation of run_query.
|
59
65
|
"""
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
]
|
66
|
+
mock_responses = {
|
67
|
+
self.enrollment_queries.get_enrollment_date_range_query(): [[
|
68
|
+
datetime.strptime('2021-01-01', "%Y-%m-%d"),
|
69
|
+
datetime.strptime('2021-12-31', "%Y-%m-%d"),
|
70
|
+
]],
|
71
|
+
self.enrollment_queries.get_enrollment_and_course_count_query(): [[
|
72
|
+
100, 10
|
73
|
+
]],
|
74
|
+
self.enrollment_queries.get_completion_count_query(): [[
|
75
|
+
50
|
76
|
+
]],
|
77
|
+
self.engagement_queries.get_learning_hours_and_daily_sessions_query(): [[
|
78
|
+
100, 10
|
79
|
+
]],
|
80
|
+
'SELECT MAX(created) FROM enterprise_learner_enrollment': [[datetime.strptime('2021-01-01', "%Y-%m-%d")]]
|
81
|
+
}
|
82
|
+
return mock_responses[query]
|
68
83
|
|
69
84
|
def test_get_admin_analytics_aggregates(self):
|
70
85
|
"""
|
@@ -72,16 +87,24 @@ class TestEnterpriseAdminAnalyticsAggregatesView(JWTTestMixin, APITransactionTes
|
|
72
87
|
"""
|
73
88
|
url = reverse('v1:enterprise-admin-analytics-aggregates', kwargs={'enterprise_id': self.enterprise_id})
|
74
89
|
with patch('enterprise_data.admin_analytics.data_loaders.run_query', side_effect=self._mock_run_query):
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
90
|
+
with patch(
|
91
|
+
'enterprise_data.admin_analytics.database.tables.fact_engagement_admin_dash.run_query',
|
92
|
+
side_effect=self._mock_run_query
|
93
|
+
):
|
94
|
+
with patch(
|
95
|
+
'enterprise_data.admin_analytics.database.tables.fact_enrollment_admin_dash.run_query',
|
96
|
+
side_effect=self._mock_run_query
|
97
|
+
):
|
98
|
+
response = self.client.get(url)
|
99
|
+
assert response.status_code == status.HTTP_200_OK
|
100
|
+
assert 'enrolls' in response.json()
|
101
|
+
assert 'courses' in response.json()
|
102
|
+
assert 'completions' in response.json()
|
103
|
+
assert 'hours' in response.json()
|
104
|
+
assert 'sessions' in response.json()
|
105
|
+
assert 'last_updated_at' in response.json()
|
106
|
+
assert 'min_enrollment_date' in response.json()
|
107
|
+
assert 'max_enrollment_date' in response.json()
|
85
108
|
|
86
109
|
|
87
110
|
@ddt.ddt
|
File without changes
|
File without changes
|
File without changes
|