edx-enterprise-data 9.1.1__tar.gz → 9.2.1__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 (204) hide show
  1. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/CHANGELOG.rst +8 -0
  2. {edx_enterprise_data-9.1.1/edx_enterprise_data.egg-info → edx_enterprise_data-9.2.1}/PKG-INFO +1 -1
  3. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1/edx_enterprise_data.egg-info}/PKG-INFO +1 -1
  4. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/edx_enterprise_data.egg-info/SOURCES.txt +0 -3
  5. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/__init__.py +1 -1
  6. edx_enterprise_data-9.2.1/enterprise_data/admin_analytics/constants.py +11 -0
  7. edx_enterprise_data-9.2.1/enterprise_data/admin_analytics/data_loaders.py +24 -0
  8. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/queries/fact_engagement_admin_dash.py +85 -0
  9. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/tables/fact_engagement_admin_dash.py +50 -0
  10. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/serializers.py +1 -38
  11. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/urls.py +2 -2
  12. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/analytics_completions.py +0 -2
  13. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/analytics_engagements.py +0 -2
  14. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/analytics_enrollments.py +0 -2
  15. edx_enterprise_data-9.2.1/enterprise_data/api/v1/views/analytics_leaderboard.py +107 -0
  16. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/enterprise_learner.py +21 -12
  17. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/renderers.py +2 -2
  18. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/mock_analytics_data.py +15 -60
  19. edx_enterprise_data-9.2.1/enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py +130 -0
  20. edx_enterprise_data-9.2.1/enterprise_data/tests/admin_analytics/test_data_loaders.py +29 -0
  21. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/utils.py +0 -16
  22. edx_enterprise_data-9.1.1/enterprise_data/admin_analytics/constants.py +0 -25
  23. edx_enterprise_data-9.1.1/enterprise_data/admin_analytics/data_loaders.py +0 -149
  24. edx_enterprise_data-9.1.1/enterprise_data/admin_analytics/utils.py +0 -180
  25. edx_enterprise_data-9.1.1/enterprise_data/api/v1/paginators.py +0 -121
  26. edx_enterprise_data-9.1.1/enterprise_data/api/v1/views/analytics_leaderboard.py +0 -144
  27. edx_enterprise_data-9.1.1/enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py +0 -163
  28. edx_enterprise_data-9.1.1/enterprise_data/tests/admin_analytics/test_data_loaders.py +0 -86
  29. edx_enterprise_data-9.1.1/enterprise_data/tests/admin_analytics/test_utils.py +0 -102
  30. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/LICENSE +0 -0
  31. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/MANIFEST.in +0 -0
  32. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/README.md +0 -0
  33. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/edx_enterprise_data.egg-info/dependency_links.txt +0 -0
  34. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/edx_enterprise_data.egg-info/not-zip-safe +0 -0
  35. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/edx_enterprise_data.egg-info/requires.txt +0 -0
  36. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/edx_enterprise_data.egg-info/top_level.txt +0 -0
  37. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/__init__.py +0 -0
  38. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/__init__.py +0 -0
  39. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/queries/__init__.py +0 -0
  40. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/queries/fact_enrollment_admin_dash.py +0 -0
  41. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/queries/skills_daily_rollup_admin_dash.py +0 -0
  42. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/tables/__init__.py +0 -0
  43. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/tables/base.py +0 -0
  44. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/tables/fact_enrollment_admin_dash.py +0 -0
  45. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/tables/skills_daily_rollup_admin_dash.py +0 -0
  46. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/admin_analytics/database/utils.py +0 -0
  47. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/__init__.py +0 -0
  48. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/urls.py +0 -0
  49. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v0/__init__.py +0 -0
  50. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v0/serializers.py +0 -0
  51. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v0/urls.py +0 -0
  52. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v0/views.py +0 -0
  53. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/__init__.py +0 -0
  54. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/__init__.py +0 -0
  55. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/base.py +0 -0
  56. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/enterprise_admin.py +0 -0
  57. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/api/v1/views/enterprise_offers.py +0 -0
  58. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/apps.py +0 -0
  59. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/clients.py +0 -0
  60. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/constants.py +0 -0
  61. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/filters.py +0 -0
  62. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/fixtures/enterprise_enrollment.json +0 -0
  63. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/fixtures/enterprise_user.json +0 -0
  64. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/__init__.py +0 -0
  65. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/__init__.py +0 -0
  66. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_dummy_data.py +0 -0
  67. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_dummy_data_lpr_v1.py +0 -0
  68. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_enterprise_enrollment.py +0 -0
  69. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  70. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_enterprise_learner_lpr_v1.py +0 -0
  71. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_enterprise_offer.py +0 -0
  72. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/create_enterprise_user.py +0 -0
  73. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/__init__.py +0 -0
  74. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/test_create_dummy_data_lpr_v1.py +0 -0
  75. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/test_create_enterprise_enrollment.py +0 -0
  76. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/test_create_enterprise_learner_enrollment_lpr_v1.py +0 -0
  77. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/test_create_enterprise_learner_lpr_v1.py +0 -0
  78. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/management/commands/tests/test_create_enterprise_user.py +0 -0
  79. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0001_initial.py +0 -0
  80. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0002_auto_20180430_1358.py +0 -0
  81. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0003_auto_20180501_0603.py +0 -0
  82. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0004_auto_20180501_0928.py +0 -0
  83. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0004_auto_20180508_1652.py +0 -0
  84. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0005_auto_20180524_2204.py +0 -0
  85. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0006_auto_20180612_0336.py +0 -0
  86. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0007_auto_20180612_0534.py +0 -0
  87. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0008_auto_20180614_0108.py +0 -0
  88. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0009_auto_20180628_1152.py +0 -0
  89. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0010_enterpriseenrollment_created.py +0 -0
  90. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0011_enterpriseuser.py +0 -0
  91. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0012_auto_20180831_1930.py +0 -0
  92. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0013_auto_20180831_1931.py +0 -0
  93. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0014_enterpriseuser_created.py +0 -0
  94. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0015_auto_20180907_1757.py +0 -0
  95. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0016_auto_20180924_2138.py +0 -0
  96. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0017_enterpriseenrollment_unenrollment_timestamp.py +0 -0
  97. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0018_enterprisedatafeaturerole_enterprisedataroleassignment.py +0 -0
  98. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0019_add_enterprise_data_feature_roles.py +0 -0
  99. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0020_add_role_based_access_control_switch.py +0 -0
  100. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0021_auto_20190329_1241.py +0 -0
  101. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0022_remove_role_based_access_control_switch.py +0 -0
  102. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0023_enterpriselearner_enterpriselearnerenrollment.py +0 -0
  103. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0024_auto_20210602_1811.py +0 -0
  104. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0025_auto_20210703_1854.py +0 -0
  105. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0026_auto_20210916_0414.py +0 -0
  106. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0027_enterpriselearnerenrollment_total_learning_time_seconds.py +0 -0
  107. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0028_enterpriselearnerenrollment_offer_id.py +0 -0
  108. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0029_enterpriseoffer.py +0 -0
  109. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0030_auto_20230609_1353.py +0 -0
  110. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0031_auto_20230615_0705.py +0 -0
  111. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0032_auto_20230704_0818.py +0 -0
  112. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0033_enterpriseadminlearnerprogress_enterpriseadminsummarizeinsights.py +0 -0
  113. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0034_auto_20230907_0834.py +0 -0
  114. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0035_auto_20230907_1154.py +0 -0
  115. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0036_enterprisesubsidybudget_subsidy_access_policy_display_name.py +0 -0
  116. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0037_alter_enterpriseenrollment_consent_granted.py +0 -0
  117. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0038_enterpriseoffer_export_timestamp.py +0 -0
  118. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0039_auto_20240212_1403.py +0 -0
  119. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0040_auto_20240718_0536_squashed_0043_alter_enterpriselearnerenrollment_enterprise_enrollment_id.py +0 -0
  120. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/0044_enterpriseexecedlcmoduleperformance.py +0 -0
  121. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/migrations/__init__.py +0 -0
  122. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/models.py +0 -0
  123. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/paginators.py +0 -0
  124. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/settings/__init__.py +0 -0
  125. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/settings/test.py +0 -0
  126. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/signals.py +0 -0
  127. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/__init__.py +0 -0
  128. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/__init__.py +0 -0
  129. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/mock_enrollments.py +0 -0
  130. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/test_analytics_engagements.py +0 -0
  131. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/test_analytics_enrollments.py +0 -0
  132. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/admin_analytics/test_enterprise_completions.py +0 -0
  133. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/__init__.py +0 -0
  134. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v0/__init__.py +0 -0
  135. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v0/test_serializers.py +0 -0
  136. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v1/__init__.py +0 -0
  137. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v1/test_serializers.py +0 -0
  138. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v1/test_views.py +0 -0
  139. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v1/views/__init__.py +0 -0
  140. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/api/v1/views/test_enterprise_admin.py +0 -0
  141. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/factories.py +0 -0
  142. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/mixins.py +0 -0
  143. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/test_clients.py +0 -0
  144. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/test_filters.py +0 -0
  145. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/test_models.py +0 -0
  146. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/test_utils.py +0 -0
  147. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/tests/test_views.py +0 -0
  148. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data/urls.py +0 -0
  149. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/__init__.py +0 -0
  150. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/admin.py +0 -0
  151. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/apps.py +0 -0
  152. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/constants.py +0 -0
  153. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0001_initial.py +0 -0
  154. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0002_add_enterprise_data_feature_roles.py +0 -0
  155. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0003_add_role_based_access_control_switch.py +0 -0
  156. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0004_enterprisedataroleassignment_enterprise_id.py +0 -0
  157. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0005_turn_on_role_based_access_control_switch.py +0 -0
  158. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0006_remove_role_based_access_control_switch.py +0 -0
  159. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/0007_enterprisedataroleassignment_applies_to_all_contexts.py +0 -0
  160. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/migrations/__init__.py +0 -0
  161. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/models.py +0 -0
  162. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/rules.py +0 -0
  163. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/tests/__init__.py +0 -0
  164. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/tests/factories.py +0 -0
  165. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_data_roles/tests/test_models.py +0 -0
  166. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/__init__.py +0 -0
  167. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/clients/__init__.py +0 -0
  168. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/clients/enterprise.py +0 -0
  169. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/clients/s3.py +0 -0
  170. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/clients/snowflake.py +0 -0
  171. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/clients/vertica.py +0 -0
  172. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/delivery_method.py +0 -0
  173. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/external_resource_link_report.py +0 -0
  174. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/fixtures/__init__.py +0 -0
  175. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/fixtures/enterprise_customer_reporting.json +0 -0
  176. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/reporter.py +0 -0
  177. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/send_enterprise_reports.py +0 -0
  178. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/__init__.py +0 -0
  179. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_clients.py +0 -0
  180. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_delivery_method.py +0 -0
  181. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_enterprise_client.py +0 -0
  182. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_external_link_report.py +0 -0
  183. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_reporter.py +0 -0
  184. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_send_enterprise_reports.py +0 -0
  185. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_utils.py +0 -0
  186. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/test_vertica_client.py +0 -0
  187. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/tests/utils.py +0 -0
  188. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/enterprise_reporting/utils.py +0 -0
  189. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/base.in +0 -0
  190. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/base.txt +0 -0
  191. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/ci.txt +0 -0
  192. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/common_constraints.txt +0 -0
  193. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/constraints.txt +0 -0
  194. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/dev.txt +0 -0
  195. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/django.txt +0 -0
  196. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/pip.txt +0 -0
  197. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/pip_tools.txt +0 -0
  198. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/quality.txt +0 -0
  199. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/reporting.in +0 -0
  200. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/test-master.txt +0 -0
  201. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/test-reporting.txt +0 -0
  202. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/requirements/test.txt +0 -0
  203. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/setup.cfg +0 -0
  204. {edx_enterprise_data-9.1.1 → edx_enterprise_data-9.2.1}/setup.py +0 -0
@@ -16,6 +16,14 @@ Unreleased
16
16
 
17
17
  =========================
18
18
 
19
+ [9.2.1] - 2024-09-25
20
+ ---------------------
21
+ * fix: Added temporary cache logging on EnterpriseLearnerEnrollmentViewSet.
22
+
23
+ [9.2.0] - 2024-09-25
24
+ ---------------------
25
+ * refactor: Performance optimizations for leaderboard API endpoints
26
+
19
27
  [9.1.1] - 2024-09-24
20
28
  ---------------------
21
29
  * fix: disable caching for EnterpriseLearnerEnrollmentViewSet
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: edx-enterprise-data
3
- Version: 9.1.1
3
+ Version: 9.2.1
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: 9.1.1
3
+ Version: 9.2.1
4
4
  Summary: Enterprise Reporting
5
5
  Home-page: https://github.com/openedx/edx-enterprise-data
6
6
  Author: edX
@@ -23,7 +23,6 @@ enterprise_data/utils.py
23
23
  enterprise_data/admin_analytics/__init__.py
24
24
  enterprise_data/admin_analytics/constants.py
25
25
  enterprise_data/admin_analytics/data_loaders.py
26
- enterprise_data/admin_analytics/utils.py
27
26
  enterprise_data/admin_analytics/database/__init__.py
28
27
  enterprise_data/admin_analytics/database/utils.py
29
28
  enterprise_data/admin_analytics/database/queries/__init__.py
@@ -42,7 +41,6 @@ enterprise_data/api/v0/serializers.py
42
41
  enterprise_data/api/v0/urls.py
43
42
  enterprise_data/api/v0/views.py
44
43
  enterprise_data/api/v1/__init__.py
45
- enterprise_data/api/v1/paginators.py
46
44
  enterprise_data/api/v1/serializers.py
47
45
  enterprise_data/api/v1/urls.py
48
46
  enterprise_data/api/v1/views/__init__.py
@@ -132,7 +130,6 @@ enterprise_data/tests/admin_analytics/test_analytics_enrollments.py
132
130
  enterprise_data/tests/admin_analytics/test_analytics_leaderboard.py
133
131
  enterprise_data/tests/admin_analytics/test_data_loaders.py
134
132
  enterprise_data/tests/admin_analytics/test_enterprise_completions.py
135
- enterprise_data/tests/admin_analytics/test_utils.py
136
133
  enterprise_data/tests/api/__init__.py
137
134
  enterprise_data/tests/api/v0/__init__.py
138
135
  enterprise_data/tests/api/v0/test_serializers.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__ = "9.1.1"
5
+ __version__ = "9.2.1"
@@ -0,0 +1,11 @@
1
+ """
2
+ Constants for admin analytics app.
3
+ """
4
+
5
+ from enum import Enum
6
+
7
+
8
+ class ResponseType(Enum):
9
+ """Response type choices"""
10
+ JSON = 'json'
11
+ CSV = 'csv'
@@ -0,0 +1,24 @@
1
+ """
2
+ Utility functions for fetching data from the database.
3
+ """
4
+ from logging import getLogger
5
+
6
+ import pandas
7
+
8
+ from enterprise_data.admin_analytics.database import run_query
9
+
10
+ LOGGER = getLogger(__name__)
11
+
12
+
13
+ def fetch_max_enrollment_datetime():
14
+ """
15
+ Fetch the latest created date from the enterprise_learner_enrollment table.
16
+
17
+ created will be same for all records as this is added at the time of data load. Which is when the async process
18
+ populates the data in the table. We can use this to get the latest data load time.
19
+ """
20
+ query = "SELECT MAX(created) FROM enterprise_learner_enrollment"
21
+ results = run_query(query)
22
+ if not results:
23
+ return None
24
+ return pandas.to_datetime(results[0][0])
@@ -109,3 +109,88 @@ class FactEngagementAdminDashQueries:
109
109
  GROUP BY activity_date, enroll_type
110
110
  ORDER BY activity_date;
111
111
  """
112
+
113
+ @staticmethod
114
+ def get_all_leaderboard_data_query():
115
+ """
116
+ Get the query to fetch the leaderboard data.
117
+
118
+ Query should fetch the leaderboard data for the enterprise customer to show in the data table.
119
+
120
+ Returns:
121
+ (str): Query to fetch the leaderboard data.
122
+ """
123
+ return """
124
+ WITH Engagement AS (
125
+ SELECT
126
+ email,
127
+ ROUND(SUM(learning_time_seconds) / 3600, 1) as learning_time_hours,
128
+ SUM(is_engaged) as session_count,
129
+ CASE
130
+ WHEN SUM(is_engaged) = 0 THEN 0.0
131
+ ELSE ROUND(SUM(learning_time_seconds) / 3600 / SUM(is_engaged), 1)
132
+ END AS average_session_length
133
+ FROM fact_enrollment_engagement_day_admin_dash
134
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
135
+ (activity_date BETWEEN %(start_date)s AND %(end_date)s) AND
136
+ is_engaged = 1
137
+ GROUP BY email
138
+ ),
139
+ Completions AS (
140
+ SELECT email, count(course_key) as course_completion_count
141
+ FROM fact_enrollment_admin_dash
142
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
143
+ (passed_date BETWEEN %(start_date)s AND %(end_date)s) AND
144
+ has_passed = 1
145
+ GROUP BY email
146
+ )
147
+ SELECT
148
+ Engagement.email,
149
+ Engagement.learning_time_hours,
150
+ Engagement.session_count,
151
+ Engagement.average_session_length,
152
+ Completions.course_completion_count
153
+ FROM Engagement
154
+ LEFT JOIN Completions
155
+ ON Engagement.email = Completions.email
156
+ ORDER BY
157
+ Engagement.learning_time_hours DESC,
158
+ Engagement.session_count DESC,
159
+ Completions.course_completion_count DESC
160
+ LIMIT %(limit)s OFFSET %(offset)s;
161
+ """
162
+
163
+ @staticmethod
164
+ def get_leaderboard_data_count_query():
165
+ """
166
+ Get the query to fetch the leaderboard row count.
167
+
168
+ Query should fetch the count of rows for the leaderboard data for the enterprise customer.
169
+
170
+ Returns:
171
+ (str): Query to fetch the leaderboard row count.
172
+ """
173
+ return """
174
+ WITH Engagement AS (
175
+ SELECT
176
+ email
177
+ FROM fact_enrollment_engagement_day_admin_dash
178
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
179
+ (activity_date BETWEEN %(start_date)s AND %(end_date)s) AND
180
+ is_engaged = 1
181
+ GROUP BY email
182
+ ),
183
+ Completions AS (
184
+ SELECT email, count(course_key) as course_completion_count
185
+ FROM fact_enrollment_admin_dash
186
+ WHERE enterprise_customer_uuid=%(enterprise_customer_uuid)s AND
187
+ (passed_date BETWEEN %(start_date)s AND %(end_date)s) AND
188
+ has_passed = 1
189
+ GROUP BY email
190
+ )
191
+ SELECT
192
+ count(*)
193
+ FROM Engagement
194
+ LEFT JOIN Completions
195
+ ON Engagement.email = Completions.email
196
+ """
@@ -152,3 +152,53 @@ class FactEngagementAdminDashTable(BaseTable):
152
152
  },
153
153
  as_dict=True,
154
154
  )
155
+
156
+ def get_all_leaderboard_data(
157
+ self, enterprise_customer_uuid: UUID, start_date: date, end_date: date, limit: int, offset: int
158
+ ):
159
+ """
160
+ Get the leaderboard data for the given enterprise customer.
161
+
162
+ Arguments:
163
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
164
+ start_date (date): The start date.
165
+ end_date (date): The end date.
166
+ limit (int): The maximum number of records to return.
167
+ offset (int): The number of records to skip.
168
+
169
+ Returns:
170
+ list[dict]: The leaderboard data.
171
+ """
172
+ return run_query(
173
+ query=self.queries.get_all_leaderboard_data_query(),
174
+ params={
175
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
176
+ 'start_date': start_date,
177
+ 'end_date': end_date,
178
+ 'limit': limit,
179
+ 'offset': offset,
180
+ },
181
+ as_dict=True,
182
+ )
183
+
184
+ def get_leaderboard_data_count(self, enterprise_customer_uuid: UUID, start_date: date, end_date: date):
185
+ """
186
+ Get the total number of leaderboard records for the given enterprise customer.
187
+
188
+ Arguments:
189
+ enterprise_customer_uuid (UUID): The UUID of the enterprise customer.
190
+ start_date (date): The start date.
191
+ end_date (date): The end date.
192
+
193
+ Returns:
194
+ (int): The total number of leaderboard records.
195
+ """
196
+ results = run_query(
197
+ query=self.queries.get_leaderboard_data_count_query(),
198
+ params={
199
+ 'enterprise_customer_uuid': enterprise_customer_uuid,
200
+ 'start_date': start_date,
201
+ 'end_date': end_date,
202
+ }
203
+ )
204
+ return results[0][0]
@@ -5,7 +5,7 @@ from uuid import UUID
5
5
 
6
6
  from rest_framework import serializers
7
7
 
8
- from enterprise_data.admin_analytics.constants import Calculation, Granularity, ResponseType
8
+ from enterprise_data.admin_analytics.constants import ResponseType
9
9
  from enterprise_data.models import (
10
10
  EnterpriseAdminLearnerProgress,
11
11
  EnterpriseAdminSummarizeInsights,
@@ -241,23 +241,8 @@ class AdvanceAnalyticsQueryParamSerializer(serializers.Serializer): # pylint: d
241
241
  ResponseType.JSON.value,
242
242
  ResponseType.CSV.value
243
243
  ]
244
- GRANULARITY_CHOICES = [
245
- Granularity.DAILY.value,
246
- Granularity.WEEKLY.value,
247
- Granularity.MONTHLY.value,
248
- Granularity.QUARTERLY.value
249
- ]
250
- CALCULATION_CHOICES = [
251
- Calculation.TOTAL.value,
252
- Calculation.RUNNING_TOTAL.value,
253
- Calculation.MOVING_AVERAGE_3_PERIOD.value,
254
- Calculation.MOVING_AVERAGE_7_PERIOD.value
255
- ]
256
-
257
244
  start_date = serializers.DateField(required=False)
258
245
  end_date = serializers.DateField(required=False)
259
- granularity = serializers.CharField(required=False)
260
- calculation = serializers.CharField(required=False)
261
246
  response_type = serializers.CharField(required=False)
262
247
  page = serializers.IntegerField(required=False, min_value=1)
263
248
  page_size = serializers.IntegerField(required=False, min_value=2)
@@ -287,25 +272,3 @@ class AdvanceAnalyticsQueryParamSerializer(serializers.Serializer): # pylint: d
287
272
  if value not in self.RESPONSE_TYPES:
288
273
  raise serializers.ValidationError(f"response_type must be one of {self.RESPONSE_TYPES}")
289
274
  return value
290
-
291
- def validate_granularity(self, value):
292
- """
293
- Validate the granularity value.
294
-
295
- Raises:
296
- serializers.ValidationError: If granularity is not one of the valid choices.
297
- """
298
- if value not in self.GRANULARITY_CHOICES:
299
- raise serializers.ValidationError(f"Granularity must be one of {self.GRANULARITY_CHOICES}")
300
- return value
301
-
302
- def validate_calculation(self, value):
303
- """
304
- Validate the calculation value.
305
-
306
- Raises:
307
- serializers.ValidationError: If calculation is not one of the valid choices
308
- """
309
- if value not in self.CALCULATION_CHOICES:
310
- raise serializers.ValidationError(f"Calculation must be one of {self.CALCULATION_CHOICES}")
311
- return value
@@ -58,8 +58,8 @@ urlpatterns = [
58
58
  ),
59
59
  re_path(
60
60
  fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/leaderboard$',
61
- AdvanceAnalyticsLeaderboardView.as_view(),
62
- name='enterprise-admin-analytics-leaderboard'
61
+ AdvanceAnalyticsLeaderboardView.as_view({'get': 'list'}),
62
+ name='enterprise-admin-analytics-leaderboard-list'
63
63
  ),
64
64
  re_path(
65
65
  fr'^admin/analytics/(?P<enterprise_uuid>{UUID4_REGEX})/enrollments/stats$',
@@ -15,7 +15,6 @@ from django.http import StreamingHttpResponse
15
15
 
16
16
  from enterprise_data.admin_analytics.constants import ResponseType
17
17
  from enterprise_data.admin_analytics.database.tables import FactEnrollmentAdminDashTable
18
- from enterprise_data.api.v1.paginators import AdvanceAnalyticsPagination
19
18
  from enterprise_data.api.v1.serializers import AdvanceAnalyticsQueryParamSerializer
20
19
  from enterprise_data.api.v1.views.base import AnalyticsPaginationMixin
21
20
  from enterprise_data.renderers import IndividualCompletionsCSVRenderer
@@ -33,7 +32,6 @@ class AdvanceAnalyticsCompletionsView(AnalyticsPaginationMixin, ViewSet):
33
32
  2. `enterprise_data_api_v1.enterprise-learner-completion-stats`: Get completion stats data.
34
33
  """
35
34
  authentication_classes = (JwtAuthentication,)
36
- pagination_class = AdvanceAnalyticsPagination
37
35
  http_method_names = ('get', )
38
36
 
39
37
  @permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
@@ -15,7 +15,6 @@ from django.http import StreamingHttpResponse
15
15
 
16
16
  from enterprise_data.admin_analytics.constants import ResponseType
17
17
  from enterprise_data.admin_analytics.database.tables import FactEngagementAdminDashTable, FactEnrollmentAdminDashTable
18
- from enterprise_data.api.v1.paginators import AdvanceAnalyticsPagination
19
18
  from enterprise_data.api.v1.serializers import AdvanceAnalyticsQueryParamSerializer
20
19
  from enterprise_data.api.v1.views.base import AnalyticsPaginationMixin
21
20
  from enterprise_data.renderers import IndividualEngagementsCSVRenderer
@@ -33,7 +32,6 @@ class AdvanceAnalyticsEngagementView(AnalyticsPaginationMixin, ViewSet):
33
32
  2. `enterprise_data_api_v1.enterprise-learner-engagement-stats`: Get engagement stats data.
34
33
  """
35
34
  authentication_classes = (JwtAuthentication,)
36
- pagination_class = AdvanceAnalyticsPagination
37
35
  http_method_names = ('get', )
38
36
 
39
37
  @permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
@@ -14,7 +14,6 @@ from django.http import StreamingHttpResponse
14
14
 
15
15
  from enterprise_data.admin_analytics.constants import ResponseType
16
16
  from enterprise_data.admin_analytics.database.tables import FactEnrollmentAdminDashTable
17
- from enterprise_data.api.v1.paginators import AdvanceAnalyticsPagination
18
17
  from enterprise_data.api.v1.serializers import AdvanceAnalyticsQueryParamSerializer
19
18
  from enterprise_data.api.v1.views.base import AnalyticsPaginationMixin
20
19
  from enterprise_data.renderers import IndividualEnrollmentsCSVRenderer
@@ -32,7 +31,6 @@ class AdvanceAnalyticsEnrollmentsView(AnalyticsPaginationMixin, ViewSet):
32
31
  2. `enterprise_data_api_v1.enterprise-learner-enrollment-stats`: Get enrollment stats data.
33
32
  """
34
33
  authentication_classes = (JwtAuthentication,)
35
- pagination_class = AdvanceAnalyticsPagination
36
34
  http_method_names = ('get', )
37
35
 
38
36
  @permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
@@ -0,0 +1,107 @@
1
+ """
2
+ Views for fetching leaderboard data.
3
+ """
4
+
5
+ from datetime import datetime
6
+ from logging import getLogger
7
+
8
+ from edx_rbac.decorators import permission_required
9
+ from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
10
+ from rest_framework.viewsets import ViewSet
11
+
12
+ from django.http import StreamingHttpResponse
13
+
14
+ from enterprise_data.admin_analytics.constants import ResponseType
15
+ from enterprise_data.admin_analytics.database.tables import FactEngagementAdminDashTable, FactEnrollmentAdminDashTable
16
+ from enterprise_data.api.v1.serializers import AdvanceAnalyticsQueryParamSerializer
17
+ from enterprise_data.api.v1.views.base import AnalyticsPaginationMixin
18
+ from enterprise_data.renderers import LeaderboardCSVRenderer
19
+
20
+ LOGGER = getLogger(__name__)
21
+
22
+
23
+ class AdvanceAnalyticsLeaderboardView(AnalyticsPaginationMixin, ViewSet):
24
+ """
25
+ View to handle requests for enterprise leaderboard data.
26
+
27
+ Here is the list of URLs that are handled by this view:
28
+ 1. `enterprise_data_api_v1.enterprise-admin-analytics-leaderboard-list`: Get leaderboard data.
29
+ """
30
+ authentication_classes = (JwtAuthentication,)
31
+ http_method_names = ('get', )
32
+
33
+ @permission_required('can_access_enterprise', fn=lambda request, enterprise_uuid: enterprise_uuid)
34
+ def list(self, request, enterprise_uuid):
35
+ """
36
+ Get individual leaderboard data for the enterprise.
37
+ """
38
+ # Remove hyphens from the UUID
39
+ enterprise_uuid = enterprise_uuid.replace('-', '')
40
+
41
+ serializer = AdvanceAnalyticsQueryParamSerializer(data=request.GET)
42
+ serializer.is_valid(raise_exception=True)
43
+ min_enrollment_date, _ = FactEnrollmentAdminDashTable().get_enrollment_date_range(
44
+ enterprise_uuid,
45
+ )
46
+
47
+ # get values from query params or use default values
48
+ start_date = serializer.data.get('start_date', min_enrollment_date)
49
+ end_date = serializer.data.get('end_date', datetime.now())
50
+ page = serializer.data.get('page', 1)
51
+ page_size = serializer.data.get('page_size', 100)
52
+ leaderboard = FactEngagementAdminDashTable().get_all_leaderboard_data(
53
+ enterprise_customer_uuid=enterprise_uuid,
54
+ start_date=start_date,
55
+ end_date=end_date,
56
+ limit=page_size,
57
+ offset=(page - 1) * page_size,
58
+ )
59
+ total_count = FactEngagementAdminDashTable().get_leaderboard_data_count(
60
+ enterprise_customer_uuid=enterprise_uuid,
61
+ start_date=start_date,
62
+ end_date=end_date,
63
+ )
64
+ response_type = request.query_params.get('response_type', ResponseType.JSON.value)
65
+
66
+ LOGGER.info(
67
+ 'Leaderboard data requested for enterprise [%s] from [%s] to [%s]',
68
+ enterprise_uuid,
69
+ start_date,
70
+ end_date,
71
+ )
72
+
73
+ if response_type == ResponseType.CSV.value:
74
+ filename = f'Leaderboard, {start_date} - {end_date}.csv'
75
+
76
+ return StreamingHttpResponse(
77
+ LeaderboardCSVRenderer().render(self._stream_serialized_data(
78
+ enterprise_uuid, start_date, end_date, total_count
79
+ )),
80
+ content_type='text/csv',
81
+ headers={'Content-Disposition': f'attachment; filename="{filename}"'},
82
+ )
83
+
84
+ return self.get_paginated_response(
85
+ request=request,
86
+ records=leaderboard,
87
+ page=page,
88
+ page_size=page_size,
89
+ total_count=total_count,
90
+ )
91
+
92
+ @staticmethod
93
+ def _stream_serialized_data(enterprise_uuid, start_date, end_date, total_count, page_size=50000):
94
+ """
95
+ Stream the serialized data.
96
+ """
97
+ offset = 0
98
+ while offset < total_count:
99
+ leaderboard = FactEngagementAdminDashTable().get_all_leaderboard_data(
100
+ enterprise_customer_uuid=enterprise_uuid,
101
+ start_date=start_date,
102
+ end_date=end_date,
103
+ limit=page_size,
104
+ offset=offset,
105
+ )
106
+ yield from leaderboard
107
+ offset += page_size
@@ -6,6 +6,7 @@ from datetime import date, timedelta
6
6
  from logging import getLogger
7
7
  from uuid import UUID
8
8
 
9
+ from edx_django_utils.cache import TieredCache
9
10
  from rest_framework import filters, viewsets
10
11
  from rest_framework.decorators import action
11
12
  from rest_framework.response import Response
@@ -18,12 +19,13 @@ from django.db.models.functions import Coalesce
18
19
  from django.http import StreamingHttpResponse
19
20
  from django.utils import timezone
20
21
 
22
+ from enterprise_data.admin_analytics.database.utils import LOGGER
21
23
  from enterprise_data.api.v1 import serializers
22
24
  from enterprise_data.filters import AuditEnrollmentsFilterBackend, AuditUsersEnrollmentFilterBackend
23
25
  from enterprise_data.models import EnterpriseLearner, EnterpriseLearnerEnrollment
24
26
  from enterprise_data.paginators import EnterpriseEnrollmentsPagination
25
27
  from enterprise_data.renderers import EnrollmentsCSVRenderer
26
- from enterprise_data.utils import subtract_one_month
28
+ from enterprise_data.utils import get_cache_key, subtract_one_month
27
29
 
28
30
  from .base import EnterpriseViewSetMixin
29
31
 
@@ -82,19 +84,26 @@ class EnterpriseLearnerEnrollmentViewSet(EnterpriseViewSetMixin, viewsets.ReadOn
82
84
  enterprise_customer_uuid = self.kwargs['enterprise_id']
83
85
 
84
86
  # TODO: Created a ticket ENT0-9531 to fix the cache issue
85
- # Reason for Comenting cache: Remove the cache for this ViewSet
86
- # becuae the cache is not working as expected
87
- # cache_key = get_cache_key(
88
- # resource='enterprise-learner',
89
- # enterprise_customer=enterprise_customer_uuid,
90
- # )
91
- # cached_response = TieredCache.get_cached_response(cache_key)
92
- # if cached_response.is_found:
93
- # return cached_response.value
94
- # else:
87
+ # Temporary logging to test cache issue
88
+ try:
89
+ LOGGER.info("Trying to get Learner Enrollment data from Cache")
90
+ cache_key = get_cache_key(
91
+ resource='enterprise-learner',
92
+ enterprise_customer=enterprise_customer_uuid,
93
+ )
94
+ cached_response = TieredCache.get_cached_response(cache_key)
95
+ if cached_response.is_found:
96
+ LOGGER.info("Learner Enrollment data found in Cache for Enterprise: [%s]", enterprise_customer_uuid)
97
+ else:
98
+ LOGGER.info("Learner Enrollment data not found in Cache for Enterprise: [%s]", enterprise_customer_uuid)
99
+ TieredCache.set_all_tiers(cache_key, 'dummy_enrollments', DEFAULT_LEARNER_CACHE_TIMEOUT)
100
+ LOGGER.info("Cache set for Enterprise: [%s] whose key is: [%s]", enterprise_customer_uuid, cache_key)
101
+ except Exception as e:
102
+ LOGGER.error("Memcached connection test failed: %s", e)
103
+
95
104
  enrollments = EnterpriseLearnerEnrollment.objects.filter(enterprise_customer_uuid=enterprise_customer_uuid)
96
105
  enrollments = self.apply_filters(enrollments)
97
- # TieredCache.set_all_tiers(cache_key, enrollments, DEFAULT_LEARNER_CACHE_TIMEOUT)
106
+
98
107
  return enrollments
99
108
 
100
109
  def list(self, request, *args, **kwargs):
@@ -82,7 +82,7 @@ class LeaderboardCSVRenderer(CSVStreamingRenderer):
82
82
  header = [
83
83
  'email',
84
84
  'learning_time_hours',
85
- 'daily_sessions',
85
+ 'session_count',
86
86
  'average_session_length',
87
- 'course_completions',
87
+ 'course_completion_count',
88
88
  ]