edx-enterprise-data 10.0.1__tar.gz → 10.3.0__tar.gz

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.
Files changed (200) hide show
  1. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/CHANGELOG.rst +13 -0
  2. {edx_enterprise_data-10.0.1/edx_enterprise_data.egg-info → edx_enterprise_data-10.3.0}/PKG-INFO +1 -1
  3. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0/edx_enterprise_data.egg-info}/PKG-INFO +1 -1
  4. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/edx_enterprise_data.egg-info/SOURCES.txt +2 -0
  5. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/__init__.py +1 -1
  6. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +107 -12
  7. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +113 -24
  8. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +71 -6
  9. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +17 -1
  10. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/analytics_completions.py +3 -3
  11. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/analytics_engagements.py +3 -3
  12. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/analytics_enrollments.py +3 -3
  13. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/analytics_leaderboard.py +8 -6
  14. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/enterprise_admin.py +2 -2
  15. edx_enterprise_data-10.3.0/enterprise_data/management/commands/pre_warm_analytics_cache.py +219 -0
  16. edx_enterprise_data-10.3.0/enterprise_data/management/commands/tests/test_pre_warm_analytics_cache.py +60 -0
  17. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/utils.py +17 -0
  18. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/rules.py +1 -1
  19. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/base.txt +8 -7
  20. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/ci.txt +1 -1
  21. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/common_constraints.txt +4 -0
  22. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/dev.txt +19 -11
  23. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/pip.txt +4 -2
  24. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/quality.txt +20 -12
  25. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/test-master.txt +9 -8
  26. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/test-reporting.txt +7 -6
  27. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/test.txt +9 -8
  28. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/LICENSE +0 -0
  29. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/MANIFEST.in +0 -0
  30. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/README.md +0 -0
  31. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/edx_enterprise_data.egg-info/dependency_links.txt +0 -0
  32. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/edx_enterprise_data.egg-info/not-zip-safe +0 -0
  33. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/edx_enterprise_data.egg-info/requires.txt +0 -0
  34. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/edx_enterprise_data.egg-info/top_level.txt +0 -0
  35. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/__init__.py +0 -0
  36. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/constants.py +0 -0
  37. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/data_loaders.py +0 -0
  38. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/__init__.py +0 -0
  39. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/queries/__init__.py +0 -0
  40. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py +0 -0
  41. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/tables/__init__.py +0 -0
  42. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/tables/base.py +0 -0
  43. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py +0 -0
  44. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/admin_analytics/database/utils.py +0 -0
  45. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/__init__.py +0 -0
  46. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/urls.py +0 -0
  47. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v0/__init__.py +0 -0
  48. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v0/serializers.py +0 -0
  49. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v0/urls.py +0 -0
  50. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v0/views.py +0 -0
  51. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/__init__.py +0 -0
  52. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/serializers.py +0 -0
  53. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/urls.py +0 -0
  54. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/__init__.py +0 -0
  55. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/base.py +0 -0
  56. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/enterprise_learner.py +0 -0
  57. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/api/v1/views/enterprise_offers.py +0 -0
  58. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/apps.py +0 -0
  59. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/cache/__init__.py +0 -0
  60. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/cache/decorators.py +0 -0
  61. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/clients.py +0 -0
  62. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/constants.py +0 -0
  63. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/filters.py +0 -0
  64. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/fixtures/enterprise_enrollment.json +0 -0
  65. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/fixtures/enterprise_user.json +0 -0
  66. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/__init__.py +0 -0
  67. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/__init__.py +0 -0
  68. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_dummy_data.py +0 -0
  69. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_dummy_data_lpr_v1.py +0 -0
  70. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_enterprise_enrollment.py +0 -0
  71. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  72. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py +0 -0
  73. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_enterprise_offer.py +0 -0
  74. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/create_enterprise_user.py +0 -0
  75. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/__init__.py +0 -0
  76. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py +0 -0
  77. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py +0 -0
  78. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/test_create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  79. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/test_create_enterprise_learner_lpr_v1.py +0 -0
  80. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/management/commands/tests/test_create_enterprise_user.py +0 -0
  81. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0001_initial.py +0 -0
  82. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0002_auto_20180430_1358.py +0 -0
  83. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0003_auto_20180501_0603.py +0 -0
  84. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0004_auto_20180501_0928.py +0 -0
  85. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0004_auto_20180508_1652.py +0 -0
  86. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0005_auto_20180524_2204.py +0 -0
  87. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0006_auto_20180612_0336.py +0 -0
  88. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0007_auto_20180612_0534.py +0 -0
  89. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0008_auto_20180614_0108.py +0 -0
  90. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0009_auto_20180628_1152.py +0 -0
  91. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0010_enterpriseenrollment_created.py +0 -0
  92. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0011_enterpriseuser.py +0 -0
  93. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0012_auto_20180831_1930.py +0 -0
  94. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0013_auto_20180831_1931.py +0 -0
  95. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0014_enterpriseuser_created.py +0 -0
  96. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0015_auto_20180907_1757.py +0 -0
  97. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0016_auto_20180924_2138.py +0 -0
  98. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0017_enterpriseenrollment_unenrollment_timestamp.py +0 -0
  99. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0018_enterprisedatafeaturerole_enterprisedataroleassignment.py +0 -0
  100. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0019_add_enterprise_data_feature_roles.py +0 -0
  101. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0020_add_role_based_access_control_switch.py +0 -0
  102. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0021_auto_20190329_1241.py +0 -0
  103. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0022_remove_role_based_access_control_switch.py +0 -0
  104. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0023_enterpriselearner_enterpriselearnerenrollment.py +0 -0
  105. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0024_auto_20210602_1811.py +0 -0
  106. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0025_auto_20210703_1854.py +0 -0
  107. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0026_auto_20210916_0414.py +0 -0
  108. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0027_enterpriselearnerenrollment_total_learning_time_seconds.py +0 -0
  109. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0028_enterpriselearnerenrollment_offer_id.py +0 -0
  110. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0029_enterpriseoffer.py +0 -0
  111. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0030_auto_20230609_1353.py +0 -0
  112. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0031_auto_20230615_0705.py +0 -0
  113. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0032_auto_20230704_0818.py +0 -0
  114. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0033_enterpriseadminlearnerprogress_enterpriseadminsummarizeinsights.py +0 -0
  115. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0034_auto_20230907_0834.py +0 -0
  116. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0035_auto_20230907_1154.py +0 -0
  117. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0036_enterprisesubsidybudget_subsidy_access_policy_display_name.py +0 -0
  118. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0037_alter_enterpriseenrollment_consent_granted.py +0 -0
  119. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0038_enterpriseoffer_export_timestamp.py +0 -0
  120. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0039_auto_20240212_1403.py +0 -0
  121. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpriselearnerenrollment_enterprise_enrollment_id.py +0 -0
  122. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py +0 -0
  123. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/migrations/__init__.py +0 -0
  124. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/models.py +0 -0
  125. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/paginators.py +0 -0
  126. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/renderers.py +0 -0
  127. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/settings/__init__.py +0 -0
  128. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/settings/test.py +0 -0
  129. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/signals.py +0 -0
  130. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/__init__.py +0 -0
  131. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/__init__.py +0 -0
  132. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/mock_analytics_data.py +0 -0
  133. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -0
  134. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/test_analytics_engagements.py +0 -0
  135. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +0 -0
  136. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py +0 -0
  137. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/test_data_loaders.py +0 -0
  138. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/admin_analytics/test_enterprise_completions.py +0 -0
  139. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/__init__.py +0 -0
  140. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v0/__init__.py +0 -0
  141. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v0/test_serializers.py +0 -0
  142. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v1/__init__.py +0 -0
  143. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v1/test_serializers.py +0 -0
  144. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v1/test_views.py +0 -0
  145. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v1/views/__init__.py +0 -0
  146. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/api/v1/views/test_enterprise_admin.py +0 -0
  147. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/factories.py +0 -0
  148. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/mixins.py +0 -0
  149. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/test_clients.py +0 -0
  150. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/test_filters.py +0 -0
  151. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/test_models.py +0 -0
  152. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/test_utils.py +0 -0
  153. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/tests/test_views.py +0 -0
  154. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data/urls.py +0 -0
  155. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/__init__.py +0 -0
  156. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/admin.py +0 -0
  157. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/apps.py +0 -0
  158. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/constants.py +0 -0
  159. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0001_initial.py +0 -0
  160. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0002_add_enterprise_data_feature_roles.py +0 -0
  161. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0003_add_role_based_access_control_switch.py +0 -0
  162. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0004_enterprisedataroleassignment_enterprise_id.py +0 -0
  163. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0005_turn_on_role_based_access_control_switch.py +0 -0
  164. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0006_remove_role_based_access_control_switch.py +0 -0
  165. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/0007_enterprisedataroleassignment_applies_to_all_contexts.py +0 -0
  166. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/migrations/__init__.py +0 -0
  167. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/models.py +0 -0
  168. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/tests/__init__.py +0 -0
  169. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/tests/factories.py +0 -0
  170. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_data_roles/tests/test_models.py +0 -0
  171. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/__init__.py +0 -0
  172. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/clients/__init__.py +0 -0
  173. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/clients/enterprise.py +0 -0
  174. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/clients/s3.py +0 -0
  175. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/clients/snowflake.py +0 -0
  176. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/clients/vertica.py +0 -0
  177. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/delivery_method.py +0 -0
  178. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/external_resource_link_report.py +0 -0
  179. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/fixtures/__init__.py +0 -0
  180. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/fixtures/enterprise_customer_reporting.json +0 -0
  181. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/reporter.py +0 -0
  182. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/send_enterprise_reports.py +0 -0
  183. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/__init__.py +0 -0
  184. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_clients.py +0 -0
  185. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_delivery_method.py +0 -0
  186. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_enterprise_client.py +0 -0
  187. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_external_link_report.py +0 -0
  188. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_reporter.py +0 -0
  189. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_send_enterprise_reports.py +0 -0
  190. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_utils.py +0 -0
  191. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/test_vertica_client.py +0 -0
  192. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/tests/utils.py +0 -0
  193. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/enterprise_reporting/utils.py +0 -0
  194. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/base.in +0 -0
  195. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/constraints.txt +0 -0
  196. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/django.txt +0 -0
  197. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/pip_tools.txt +0 -0
  198. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/requirements/reporting.in +0 -0
  199. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/setup.cfg +0 -0
  200. {edx_enterprise_data-10.0.1 → edx_enterprise_data-10.3.0}/setup.py +0 -0
@@ -16,6 +16,19 @@ Unreleased
16
16
 
17
17
  =========================
18
18
 
19
+ [10.3.0] - 2024-11-13
20
+ ---------------------
21
+ * Re-write top 10 charts queries for Enrollments, Engagements and Completions
22
+
23
+ [10.2.0] - 2024-11-12
24
+ ---------------------
25
+ * Fixed null email issue for leaderboard.
26
+
27
+
28
+ [10.1.0] - 2024-10-29
29
+ ---------------------
30
+ * Added management command to pre-warm analytics data.
31
+
19
32
  [10.0.1] - 2024-10-25
20
33
  ---------------------
21
34
  * Same as ``10.0.0``
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edx-enterprise-data
3
- Version: 10.0.1
3
+ Version: 10.3.0
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edx-enterprise-data
3
- Version: 10.0.1
3
+ Version: 10.3.0
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -65,12 +65,14 @@ enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.
65
65
  enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py
66
66
  enterprise_data/management/commands/create_enterprise_offer.py
67
67
  enterprise_data/management/commands/create_enterprise_user.py
68
+ enterprise_data/management/commands/pre_warm_analytics_cache.py
68
69
  enterprise_data/management/commands/tests/__init__.py
69
70
  enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py
70
71
  enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py
71
72
  enterprise_data/management/commands/tests/test_create_enterprise_learner_enrollment_lpr_v1.py
72
73
  enterprise_data/management/commands/tests/test_create_enterprise_learner_lpr_v1.py
73
74
  enterprise_data/management/commands/tests/test_create_enterprise_user.py
75
+ enterprise_data/management/commands/tests/test_pre_warm_analytics_cache.py
74
76
  enterprise_data/migrations/0001_initial.py
75
77
  enterprise_data/migrations/0002_auto_20180430_1358.py
76
78
  enterprise_data/migrations/0003_auto_20180501_0603.py
@@ -2,4 +2,4 @@
2
2
  Enterprise data api application. This Django app exposes API endpoints used by enterprises.
3
3
  """
4
4
 
5
- __version__ = "10.0.1"
5
+ __version__ = "10.3.0"
@@ -48,7 +48,7 @@ class FactEngagementAdminDashQueries:
48
48
  """
49
49
 
50
50
  @staticmethod
51
- def get_top_courses_by_engagement_query(record_count=20):
51
+ def get_top_courses_by_engagement_query(record_count=10):
52
52
  """
53
53
  Get the query to fetch the learning time in hours by courses.
54
54
 
@@ -61,16 +61,40 @@ class FactEngagementAdminDashQueries:
61
61
  (str): Query to fetch the learning time in hours by courses for the top courses by user engagement.
62
62
  """
63
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
64
+ WITH filtered_data AS (
65
+ SELECT
66
+ course_key,
67
+ course_title,
68
+ enroll_type,
69
+ (learning_time_seconds / 60.0 / 60.0) AS learning_time_hours,
70
+ activity_date
71
+ FROM fact_enrollment_engagement_day_admin_dash
72
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
67
73
  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};
74
+ ),
75
+ top_10_courses AS (
76
+ SELECT
77
+ course_key,
78
+ SUM(learning_time_hours) as total_learning_time
79
+ FROM filtered_data
80
+ GROUP BY course_key
81
+ ORDER BY total_learning_time DESC
82
+ LIMIT {record_count}
83
+ )
84
+ SELECT
85
+ d.course_key,
86
+ d.course_title,
87
+ d.enroll_type,
88
+ ROUND(SUM(d.learning_time_hours)) AS learning_time_hours
89
+ FROM filtered_data d
90
+ JOIN top_10_courses tc
91
+ ON d.course_key = tc.course_key
92
+ GROUP BY d.course_key, d.course_title, d.enroll_type
93
+ ORDER BY total_learning_time DESC;
70
94
  """
71
95
 
72
96
  @staticmethod
73
- def get_top_subjects_by_engagement_query(record_count=20):
97
+ def get_top_subjects_by_engagement_query(record_count=10):
74
98
  """
75
99
  Get the query to fetch the learning time in hours by subjects.
76
100
 
@@ -83,12 +107,34 @@ class FactEngagementAdminDashQueries:
83
107
  (str): Query to fetch the learning time in hours by subjects for the top subjects by user engagement.
84
108
  """
85
109
  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
110
+ WITH filtered_data AS (
111
+ SELECT
112
+ course_subject,
113
+ enroll_type,
114
+ (learning_time_seconds / 60.0 / 60.0) AS learning_time_hours,
115
+ activity_date
116
+ FROM fact_enrollment_engagement_day_admin_dash
117
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
89
118
  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};
119
+ ),
120
+ top_10_subjects AS (
121
+ SELECT
122
+ course_subject,
123
+ SUM(learning_time_hours) as total_learning_time
124
+ FROM filtered_data
125
+ GROUP BY course_subject
126
+ ORDER BY total_learning_time DESC
127
+ LIMIT {record_count}
128
+ )
129
+ SELECT
130
+ d.course_subject,
131
+ d.enroll_type,
132
+ ROUND(SUM(d.learning_time_hours)) AS learning_time_hours
133
+ FROM filtered_data d
134
+ JOIN top_10_subjects ts
135
+ ON d.course_subject = ts.course_subject
136
+ GROUP BY d.course_subject, d.enroll_type
137
+ ORDER BY total_learning_time DESC;
92
138
  """
93
139
 
94
140
  @staticmethod
@@ -163,6 +209,55 @@ class FactEngagementAdminDashQueries:
163
209
  GROUP BY email;
164
210
  """
165
211
 
212
+ @staticmethod
213
+ def get_engagement_data_for_leaderboard_null_email_only_query():
214
+ """
215
+ Get the query to fetch the engagement data for leaderboard for NULL emails only.
216
+
217
+ Query should fetch the engagement data for like learning time, session length of
218
+ the enterprise learners to show in the leaderboard.
219
+
220
+ Returns:
221
+ (str): Query to fetch the engagement data for leaderboard.
222
+ """
223
+ return """
224
+ SELECT
225
+ email,
226
+ ROUND(SUM(learning_time_seconds) / 3600, 1) as learning_time_hours,
227
+ SUM(is_engaged) as session_count,
228
+ CASE
229
+ WHEN SUM(is_engaged) = 0 THEN 0.0
230
+ ELSE ROUND(SUM(learning_time_seconds) / 3600 / SUM(is_engaged), 1)
231
+ END AS average_session_length
232
+ FROM fact_enrollment_engagement_day_admin_dash
233
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
234
+ (activity_date BETWEEN %(start_date)s AND %(end_date)s) AND
235
+ is_engaged = 1 AND
236
+ email is NULL
237
+ GROUP BY email;
238
+ """
239
+
240
+ @staticmethod
241
+ def get_completion_data_for_leaderboard_null_email_only_query():
242
+ """
243
+ Get the query to fetch the completions data for leaderboard for NULL emails.
244
+
245
+ Query should fetch the completion data for like course completion count of
246
+ the enterprise learners to show in the leaderboard.
247
+
248
+ Returns:
249
+ (list<str>): Query to fetch the completions data for leaderboard.
250
+ """
251
+ return """
252
+ SELECT email, count(course_key) as course_completion_count
253
+ FROM fact_enrollment_admin_dash
254
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
255
+ (passed_date BETWEEN %(start_date)s AND %(end_date)s) AND
256
+ has_passed = 1 AND
257
+ email is NULL
258
+ GROUP BY email;
259
+ """
260
+
166
261
  @staticmethod
167
262
  def get_leaderboard_data_count_query():
168
263
  """
@@ -7,6 +7,18 @@ class FactEnrollmentAdminDashQueries:
7
7
  """
8
8
  Queries related to the fact_enrollment_admin_dash table.
9
9
  """
10
+ @staticmethod
11
+ def get_top_enterprises_query(count=10):
12
+ """
13
+ Get the query to fetch the top enterprises by enrollments.
14
+ """
15
+ return f"""
16
+ SELECT enterprise_customer_uuid
17
+ FROM fact_enrollment_admin_dash
18
+ GROUP BY enterprise_customer_uuid
19
+ ORDER BY COUNT(enterprise_customer_uuid) DESC LIMIT {count};
20
+ """
21
+
10
22
  @staticmethod
11
23
  def get_enrollment_count_query():
12
24
  """
@@ -86,7 +98,7 @@ class FactEnrollmentAdminDashQueries:
86
98
  """
87
99
 
88
100
  @staticmethod
89
- def get_top_courses_by_enrollments_query(record_count=20):
101
+ def get_top_courses_by_enrollments_query(record_count=10):
90
102
  """
91
103
  Get the query to fetch the enrollment count by courses.
92
104
 
@@ -96,15 +108,32 @@ class FactEnrollmentAdminDashQueries:
96
108
  record_count (int): Number of records to fetch.
97
109
  """
98
110
  return f"""
99
- SELECT course_key, course_title , enroll_type, count(course_key) as enrollment_count
100
- FROM fact_enrollment_admin_dash
101
- WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
111
+ WITH filtered_data AS (
112
+ SELECT *
113
+ FROM fact_enrollment_admin_dash
114
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
102
115
  enterprise_enrollment_date BETWEEN %(start_date)s AND %(end_date)s
103
- GROUP BY course_key, course_title, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
116
+ ),
117
+ top_10_courses AS (
118
+ SELECT course_key
119
+ FROM filtered_data
120
+ GROUP BY course_key
121
+ ORDER BY COUNT(*) DESC
122
+ LIMIT {record_count}
123
+ )
124
+
125
+ SELECT
126
+ d.course_key,
127
+ d.enroll_type,
128
+ COUNT(*) AS enrollment_count
129
+ FROM filtered_data d
130
+ JOIN top_10_courses tc
131
+ ON d.course_key = tc.course_key
132
+ GROUP BY d.course_key, d.enroll_type;
104
133
  """
105
134
 
106
135
  @staticmethod
107
- def get_top_subjects_by_enrollments_query(record_count=20):
136
+ def get_top_subjects_by_enrollments_query(record_count=10):
108
137
  """
109
138
  Get the query to fetch the enrollment count by subjects.
110
139
 
@@ -114,11 +143,27 @@ class FactEnrollmentAdminDashQueries:
114
143
  record_count (int): Number of records to fetch.
115
144
  """
116
145
  return f"""
117
- SELECT course_subject, enroll_type, count(course_subject) enrollment_count
118
- FROM fact_enrollment_admin_dash
119
- WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
146
+ WITH filtered_data AS (
147
+ SELECT *
148
+ FROM fact_enrollment_admin_dash
149
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
120
150
  enterprise_enrollment_date BETWEEN %(start_date)s AND %(end_date)s
121
- GROUP BY course_subject, enroll_type ORDER BY enrollment_count DESC LIMIT {record_count};
151
+ ),
152
+ top_10_subjects AS (
153
+ SELECT course_subject
154
+ FROM filtered_data
155
+ GROUP BY course_subject
156
+ ORDER BY COUNT(*) DESC
157
+ LIMIT {record_count}
158
+ )
159
+ SELECT
160
+ d.course_subject,
161
+ d.enroll_type,
162
+ COUNT(*) AS enrollment_count
163
+ FROM filtered_data d
164
+ JOIN top_10_subjects ts
165
+ ON d.course_subject = ts.course_subject
166
+ GROUP BY d.course_subject, d.enroll_type;
122
167
  """
123
168
 
124
169
  @staticmethod
@@ -150,7 +195,7 @@ class FactEnrollmentAdminDashQueries:
150
195
  """
151
196
 
152
197
  @staticmethod
153
- def get_top_courses_by_completions_query(record_count=20):
198
+ def get_top_courses_by_completions_query(record_count=10):
154
199
  """
155
200
  Get the query to fetch the completion count by courses.
156
201
 
@@ -163,17 +208,40 @@ class FactEnrollmentAdminDashQueries:
163
208
  (str): Query to fetch the enrollment count by courses for the top courses by enrollment count.
164
209
  """
165
210
  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
211
+ WITH filtered_data AS (
212
+ SELECT
213
+ course_key,
214
+ course_title,
215
+ enroll_type,
216
+ passed_date
217
+ FROM fact_enrollment_admin_dash
218
+ WHERE has_passed = 1 AND
219
+ enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
170
220
  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};
221
+ ),
222
+ top_10_courses AS (
223
+ SELECT
224
+ course_key,
225
+ COUNT(*) AS total_completion_count
226
+ FROM filtered_data
227
+ GROUP BY course_key
228
+ ORDER BY total_completion_count DESC
229
+ LIMIT {record_count}
230
+ )
231
+ SELECT
232
+ d.course_key,
233
+ d.course_title,
234
+ d.enroll_type,
235
+ COUNT(*) AS completion_count
236
+ FROM filtered_data d
237
+ JOIN top_10_courses tc
238
+ ON d.course_key = tc.course_key
239
+ GROUP BY d.course_key, d.course_title, d.enroll_type
240
+ ORDER BY total_completion_count DESC;
173
241
  """
174
242
 
175
243
  @staticmethod
176
- def get_top_subjects_by_completions_query(record_count=20):
244
+ def get_top_subjects_by_completions_query(record_count=10):
177
245
  """
178
246
  Get the query to fetch the completion count by subjects.
179
247
 
@@ -186,13 +254,34 @@ class FactEnrollmentAdminDashQueries:
186
254
  (str): Query to fetch the completion count by subjects for the top subjects by completion count.
187
255
  """
188
256
  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
257
+ WITH filtered_data AS (
258
+ SELECT
259
+ course_subject,
260
+ enroll_type,
261
+ passed_date
262
+ FROM fact_enrollment_admin_dash
263
+ WHERE has_passed = 1 AND
264
+ enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
193
265
  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};
266
+ ),
267
+ top_10_subjects AS (
268
+ SELECT
269
+ course_subject,
270
+ COUNT(*) AS total_completion_count
271
+ FROM filtered_data
272
+ GROUP BY course_subject
273
+ ORDER BY total_completion_count DESC
274
+ LIMIT {record_count}
275
+ )
276
+ SELECT
277
+ d.course_subject,
278
+ d.enroll_type,
279
+ COUNT(*) AS completion_count
280
+ FROM filtered_data d
281
+ JOIN top_10_subjects ts
282
+ ON d.course_subject = ts.course_subject
283
+ GROUP BY d.course_subject, d.enroll_type
284
+ ORDER BY total_completion_count DESC;
196
285
  """
197
286
 
198
287
  @staticmethod
@@ -5,6 +5,7 @@ from datetime import date
5
5
  from uuid import UUID
6
6
 
7
7
  from enterprise_data.cache.decorators import cache_it
8
+ from enterprise_data.utils import find_first
8
9
 
9
10
  from ..queries import FactEngagementAdminDashQueries
10
11
  from ..utils import run_query
@@ -168,7 +169,14 @@ class FactEngagementAdminDashTable(BaseTable):
168
169
 
169
170
  @cache_it()
170
171
  def _get_engagement_data_for_leaderboard(
171
- self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
172
+ self,
173
+ enterprise_customer_uuid: UUID,
174
+ start_date: date,
175
+ end_date: date,
176
+ limit: int,
177
+ offset: int,
178
+ include_null_email: bool,
179
+
172
180
  ):
173
181
  """
174
182
  Get the engagement data for leaderboard.
@@ -182,11 +190,12 @@ class FactEngagementAdminDashTable(BaseTable):
182
190
  end_date (date): The end date.
183
191
  limit (int): The maximum number of records to return.
184
192
  offset (int): The number of records to skip.
193
+ include_null_email (bool): If True, only fetch data for NULL emails.
185
194
 
186
195
  Returns:
187
196
  list[dict]: The engagement data for leaderboard.
188
197
  """
189
- return run_query(
198
+ engagements = run_query(
190
199
  query=self.queries.get_engagement_data_for_leaderboard_query(),
191
200
  params={
192
201
  'enterprise_customer_uuid': enterprise_customer_uuid,
@@ -198,9 +207,27 @@ class FactEngagementAdminDashTable(BaseTable):
198
207
  as_dict=True,
199
208
  )
200
209
 
210
+ if include_null_email:
211
+ engagement_for_null_email = run_query(
212
+ query=self.queries.get_engagement_data_for_leaderboard_null_email_only_query(),
213
+ params={
214
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
215
+ 'start_date': start_date,
216
+ 'end_date': end_date,
217
+ },
218
+ as_dict=True,
219
+ )
220
+ engagements += engagement_for_null_email
221
+ return engagements
222
+
201
223
  @cache_it()
202
224
  def _get_completion_data_for_leaderboard_query(
203
- self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, email_list: list
225
+ self,
226
+ enterprise_customer_uuid: UUID,
227
+ start_date: date,
228
+ end_date: date,
229
+ email_list: list,
230
+ include_null_email: bool,
204
231
  ):
205
232
  """
206
233
  Get the completion data for leaderboard.
@@ -213,11 +240,13 @@ class FactEngagementAdminDashTable(BaseTable):
213
240
  start_date (date): The start date.
214
241
  end_date (date): The end date.
215
242
  email_list (list<str>): List of emails of the enterprise learners.
243
+ include_null_email (bool): If True, only fetch data for NULL emails.
216
244
 
217
245
  Returns:
218
246
  list[dict]: The engagement data for leaderboard.
219
247
  """
220
- return run_query(
248
+
249
+ completions = run_query(
221
250
  query=self.queries.get_completion_data_for_leaderboard_query(email_list),
222
251
  params={
223
252
  'enterprise_customer_uuid': enterprise_customer_uuid,
@@ -227,8 +256,28 @@ class FactEngagementAdminDashTable(BaseTable):
227
256
  as_dict=True,
228
257
  )
229
258
 
259
+ if include_null_email:
260
+ completions_for_null_email = run_query(
261
+ query=self.queries.get_completion_data_for_leaderboard_null_email_only_query(),
262
+ params={
263
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
264
+ 'start_date': start_date,
265
+ 'end_date': end_date,
266
+ },
267
+ as_dict=True,
268
+ )
269
+ completions += completions_for_null_email
270
+
271
+ return completions
272
+
230
273
  def get_all_leaderboard_data(
231
- self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
274
+ self,
275
+ enterprise_customer_uuid: UUID,
276
+ start_date: date,
277
+ end_date: date,
278
+ limit: int,
279
+ offset: int,
280
+ total_count: int,
232
281
  ):
233
282
  """
234
283
  Get the leaderboard data for the given enterprise customer.
@@ -239,32 +288,48 @@ class FactEngagementAdminDashTable(BaseTable):
239
288
  end_date (date): The end date.
240
289
  limit (int): The maximum number of records to return.
241
290
  offset (int): The number of records to skip.
291
+ total_count (int): The total number of records.
242
292
 
243
293
  Returns:
244
294
  list[dict]: The leaderboard data.
245
295
  """
296
+ include_null_email = False
297
+ # If this is the last or only page, we need to include NULL emails record.
298
+ if total_count <= offset + limit:
299
+ include_null_email = True
300
+
246
301
  engagement_data = self._get_engagement_data_for_leaderboard(
247
302
  enterprise_customer_uuid=enterprise_customer_uuid,
248
303
  start_date=start_date,
249
304
  end_date=end_date,
250
305
  limit=limit,
251
306
  offset=offset,
307
+ include_null_email=include_null_email,
252
308
  )
253
309
  # If there is no data, no need to proceed.
254
310
  if not engagement_data:
255
311
  return []
256
312
 
257
- engagement_data_dict = {engagement['email']: engagement for engagement in engagement_data}
313
+ engagement_data_dict = {
314
+ engagement['email']: engagement for engagement in engagement_data if engagement['email']
315
+ }
258
316
  completion_data = self._get_completion_data_for_leaderboard_query(
259
317
  enterprise_customer_uuid=enterprise_customer_uuid,
260
318
  start_date=start_date,
261
319
  end_date=end_date,
262
320
  email_list=list(engagement_data_dict.keys()),
321
+ include_null_email=include_null_email,
263
322
  )
264
323
  for completion in completion_data:
265
324
  email = completion['email']
266
325
  engagement_data_dict[email]['course_completion_count'] = completion['course_completion_count']
267
326
 
327
+ if include_null_email:
328
+ engagement_data_dict['None'] = find_first(engagement_data, lambda x: x['email'] is None) or {}
329
+ completion = find_first(completion_data, lambda x: x['email'] is None) or \
330
+ {'course_completion_count': 'Unknown'}
331
+ engagement_data_dict['None']['course_completion_count'] = completion['course_completion_count']
332
+
268
333
  return list(engagement_data_dict.values())
269
334
 
270
335
  @cache_it()
@@ -17,6 +17,22 @@ class FactEnrollmentAdminDashTable(BaseTable):
17
17
  """
18
18
  queries = FactEnrollmentAdminDashQueries()
19
19
 
20
+ def get_top_enterprises(self, count=10):
21
+ """
22
+ Get the top enterprises by enrollments.
23
+
24
+ Arguments:
25
+ count (int): The number of enterprises to return.
26
+
27
+ Returns:
28
+ list<str>: A list of enterprise UUIDs.
29
+ """
30
+ result = run_query(
31
+ query=self.queries.get_top_enterprises_query(count),
32
+ as_dict=False,
33
+ )
34
+ return [row[0] for row in result]
35
+
20
36
  @cache_it()
21
37
  def get_enrollment_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
22
38
  """
@@ -77,7 +93,7 @@ class FactEnrollmentAdminDashTable(BaseTable):
77
93
  Get the enrollment date range for the given enterprise customer.
78
94
 
79
95
  Arguments:
80
- enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
96
+ enterprise_customer_uuid (UUID | str): The UUID of the enterprise customer.
81
97
 
82
98
  Returns:
83
99
  (tuple<date, date>): The minimum and maximum enrollment dates.
@@ -2,7 +2,7 @@
2
2
  Views for enterprise admin completions analytics.
3
3
  """
4
4
 
5
- from datetime import datetime
5
+ from datetime import date
6
6
  from logging import getLogger
7
7
 
8
8
  from edx_rbac.decorators import permission_required
@@ -50,7 +50,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
50
50
 
51
51
  # get values from query params or use default values
52
52
  start_date = serializer.data.get('start_date', min_enrollment_date)
53
- end_date = serializer.data.get('end_date', datetime.now())
53
+ end_date = serializer.data.get('end_date', date.today())
54
54
  page = serializer.data.get('page', 1)
55
55
  page_size = serializer.data.get('page_size', 100)
56
56
  completions = FactEnrollmentAdminDashTable().get_all_completions(
@@ -132,7 +132,7 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
132
132
  )
133
133
  # get values from query params or use default
134
134
  start_date = serializer.data.get('start_date', min_enrollment_date)
135
- end_date = serializer.data.get('end_date', datetime.now())
135
+ end_date = serializer.data.get('end_date', date.today())
136
136
  with timer('construct_completion_all_stats'):
137
137
  data = {
138
138
  'completions_over_time': FactEnrollmentAdminDashTable().get_completions_time_series_data(
@@ -2,7 +2,7 @@
2
2
  Views for handling REST endpoints related to Engagements analytics.
3
3
  """
4
4
 
5
- from datetime import datetime
5
+ from datetime import date
6
6
  from logging import getLogger
7
7
 
8
8
  from edx_rbac.decorators import permission_required
@@ -50,7 +50,7 @@ class AdvanceAnalyticsEngagementView(AnalyticsPaginationMixin, ViewSet):
50
50
 
51
51
  # get values from query params or use default values
52
52
  start_date = serializer.data.get('start_date', min_enrollment_date)
53
- end_date = serializer.data.get('end_date', datetime.now())
53
+ end_date = serializer.data.get('end_date', date.today())
54
54
  page = serializer.data.get('page', 1)
55
55
  page_size = serializer.data.get('page_size', 100)
56
56
  engagements = FactEngagementAdminDashTable().get_all_engagements(
@@ -132,7 +132,7 @@ class AdvanceAnalyticsEngagementView(AnalyticsPaginationMixin, ViewSet):
132
132
  )
133
133
  # get values from query params or use default
134
134
  start_date = serializer.data.get('start_date', min_enrollment_date)
135
- end_date = serializer.data.get('end_date', datetime.now())
135
+ end_date = serializer.data.get('end_date', date.today())
136
136
  with timer('construct_engagement_all_stats'):
137
137
  data = {
138
138
  'engagement_over_time': FactEngagementAdminDashTable().get_engagement_time_series_data(