codeforlife-portal 5.33.5__py2.py3-none-any.whl → 8.9.9__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (391) hide show
  1. cfl_common/common/__init__.py +1 -0
  2. cfl_common/common/app_settings.py +66 -0
  3. cfl_common/common/apps.py +6 -0
  4. cfl_common/common/context_processors.py +9 -0
  5. cfl_common/common/csp_config.py +85 -0
  6. cfl_common/common/helpers/__init__.py +0 -0
  7. cfl_common/common/helpers/data_migration_loader.py +42 -0
  8. cfl_common/common/helpers/emails.py +393 -0
  9. cfl_common/common/helpers/generators.py +52 -0
  10. cfl_common/common/helpers/organisation.py +10 -0
  11. cfl_common/common/mail.py +201 -0
  12. cfl_common/common/migrations/0001_initial.py +240 -0
  13. cfl_common/common/migrations/0002_emailverification.py +55 -0
  14. cfl_common/common/migrations/0003_aimmocharacter.py +31 -0
  15. cfl_common/common/migrations/0004_add_aimmocharacters.py +17 -0
  16. cfl_common/common/migrations/0005_add_worksheets.py +8 -0
  17. cfl_common/common/migrations/0006_update_aimmo_character_image_path.py +17 -0
  18. cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +8 -0
  19. cfl_common/common/migrations/0008_unlock_worksheet_3.py +11 -0
  20. cfl_common/common/migrations/0009_add_blocked_time_to_teacher_and_student.py +24 -0
  21. cfl_common/common/migrations/0010_remove_teacher_title.py +18 -0
  22. cfl_common/common/migrations/0011_student_login_id.py +18 -0
  23. cfl_common/common/migrations/0012_usersession.py +39 -0
  24. cfl_common/common/migrations/0013_class_school.py +42 -0
  25. cfl_common/common/migrations/0014_login_type.py +29 -0
  26. cfl_common/common/migrations/0015_dailyactivity.py +31 -0
  27. cfl_common/common/migrations/0016_joinreleasestudent.py +42 -0
  28. cfl_common/common/migrations/0017_copy_email_to_username.py +18 -0
  29. cfl_common/common/migrations/0018_update_aimmo_character_image_path.py +15 -0
  30. cfl_common/common/migrations/0019_aimmocharacter_alt.py +16 -0
  31. cfl_common/common/migrations/0020_class_is_active_and_null_access_code.py +23 -0
  32. cfl_common/common/migrations/0021_school_is_active.py +28 -0
  33. cfl_common/common/migrations/0022_school_cleanup.py +29 -0
  34. cfl_common/common/migrations/0023_userprofile_aimmo_badges.py +22 -0
  35. cfl_common/common/migrations/0024_teacher_invited_by.py +25 -0
  36. cfl_common/common/migrations/0025_schoolteacherinvitation.py +47 -0
  37. cfl_common/common/migrations/0026_teacher_remove_join_request.py +22 -0
  38. cfl_common/common/migrations/0027_class_created_by.py +25 -0
  39. cfl_common/common/migrations/0028_coding_club_downloads.py +23 -0
  40. cfl_common/common/migrations/0029_dynamicelement.py +22 -0
  41. cfl_common/common/migrations/0030_add_maintenance_banner.py +25 -0
  42. cfl_common/common/migrations/0031_improve_admin_panel.py +56 -0
  43. cfl_common/common/migrations/0032_dailyactivity_level_control_submits.py +18 -0
  44. cfl_common/common/migrations/0033_password_reset_tracking_fields.py +23 -0
  45. cfl_common/common/migrations/0034_dailyactivity_daily_school_student_lockout_reset.py +18 -0
  46. cfl_common/common/migrations/0035_rename_lockout_fields.py +27 -0
  47. cfl_common/common/migrations/0036_rename_awaiting_email_verification_userprofile_is_verified.py +17 -0
  48. cfl_common/common/migrations/0037_migrate_email_verification.py +21 -0
  49. cfl_common/common/migrations/0038_delete_emailverification.py +16 -0
  50. cfl_common/common/migrations/0039_copy_email_to_username.py +18 -0
  51. cfl_common/common/migrations/0040_school_county.py +18 -0
  52. cfl_common/common/migrations/0041_populate_gb_counties.py +27 -0
  53. cfl_common/common/migrations/0042_totalactivity.py +25 -0
  54. cfl_common/common/migrations/0043_add_total_activity.py +30 -0
  55. cfl_common/common/migrations/0044_update_activity_models.py +33 -0
  56. cfl_common/common/migrations/0045_otp.py +23 -0
  57. cfl_common/common/migrations/0046_alter_school_country.py +19 -0
  58. cfl_common/common/migrations/0047_delete_school_postcode.py +16 -0
  59. cfl_common/common/migrations/0048_unique_school_names.py +42 -0
  60. cfl_common/common/migrations/0049_anonymise_orphan_users.py +29 -0
  61. cfl_common/common/migrations/0050_anonymise_orphan_schools.py +30 -0
  62. cfl_common/common/migrations/0051_verify_returning_users.py +26 -0
  63. cfl_common/common/migrations/0052_add_cse_fields.py +68 -0
  64. cfl_common/common/migrations/0053_clean_class_data.py +24 -0
  65. cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
  66. cfl_common/common/migrations/0055_alter_schoolteacherinvitation_token.py +18 -0
  67. cfl_common/common/migrations/0056_set_non_school_teachers_as_non_admins.py +25 -0
  68. cfl_common/common/migrations/0057_teacher_teacher__is_admin.py +19 -0
  69. cfl_common/common/migrations/0058_userprofile_google_refresh_token_and_more.py +24 -0
  70. cfl_common/common/migrations/__init__.py +0 -0
  71. cfl_common/common/models.py +557 -0
  72. cfl_common/common/permissions.py +84 -0
  73. cfl_common/common/tests/__init__.py +0 -0
  74. cfl_common/common/tests/test_migration_anonymise_orphan_schools.py +30 -0
  75. cfl_common/common/tests/test_migration_anonymise_orphan_users.py +30 -0
  76. cfl_common/common/tests/test_migration_blocked_time.py +15 -0
  77. cfl_common/common/tests/test_migration_remove_teacher_title.py +13 -0
  78. cfl_common/common/tests/test_migration_unique_school_names.py +33 -0
  79. cfl_common/common/tests/test_migration_verify_returning_users.py +59 -0
  80. cfl_common/common/tests/test_models.py +87 -0
  81. cfl_common/common/tests/utils/__init__.py +0 -0
  82. cfl_common/common/tests/utils/classes.py +38 -0
  83. cfl_common/common/tests/utils/email.py +67 -0
  84. cfl_common/common/tests/utils/organisation.py +41 -0
  85. cfl_common/common/tests/utils/student.py +123 -0
  86. cfl_common/common/tests/utils/teacher.py +73 -0
  87. cfl_common/common/tests/utils/user.py +27 -0
  88. cfl_common/common/utils.py +56 -0
  89. cfl_common/setup.py +61 -0
  90. codeforlife_portal-8.9.9.dist-info/METADATA +226 -0
  91. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/RECORD +339 -241
  92. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/WHEEL +1 -1
  93. codeforlife_portal-8.9.9.dist-info/licenses/LICENSE.md +3 -0
  94. {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/top_level.txt +1 -0
  95. deploy/middleware/maintenance.py +25 -0
  96. deploy/middleware/screentime_warning.py +29 -0
  97. deploy/middleware/security.py +5 -6
  98. deploy/middleware/session_timeout.py +4 -2
  99. deploy/middleware/tmp_basic_auth.py +41 -0
  100. example_project/portal_test_settings.py +239 -0
  101. example_project/settings.py +156 -17
  102. example_project/urls.py +5 -6
  103. portal/__init__.py +1 -1
  104. portal/admin.py +142 -29
  105. portal/app_settings.py +8 -7
  106. portal/forms/dotmailer.py +6 -4
  107. portal/forms/invite_teacher.py +19 -10
  108. portal/forms/organisation.py +137 -68
  109. portal/forms/play.py +53 -98
  110. portal/forms/registration.py +70 -164
  111. portal/forms/teach.py +147 -121
  112. portal/handlers.py +1 -2
  113. portal/helpers/decorators.py +30 -10
  114. portal/helpers/password.py +86 -47
  115. portal/helpers/ratelimit.py +32 -15
  116. portal/helpers/regexes.py +5 -0
  117. portal/helpers/request_handlers.py +10 -0
  118. portal/migrations/0044_auto_20150430_0959.py +6 -2
  119. portal/mixins/__init__.py +1 -0
  120. portal/mixins/cron_mixin.py +12 -0
  121. portal/permissions/__init__.py +1 -0
  122. portal/permissions/is_cron_request_from_google.py +14 -0
  123. portal/static/portal/img/10_years_anniversary.png +0 -0
  124. portal/static/portal/img/RR_logo_grass_background.png +0 -0
  125. portal/static/portal/img/coding_club_hero.jpg +0 -0
  126. portal/static/portal/img/coding_club_python_pack.png +0 -0
  127. portal/static/portal/img/facebook.png +0 -0
  128. portal/static/portal/img/gitbook.png +0 -0
  129. portal/static/portal/img/howe_dell_1.png +0 -0
  130. portal/static/portal/img/howe_dell_2.png +0 -0
  131. portal/static/portal/img/howe_dell_3.png +0 -0
  132. portal/static/portal/img/logo_cfl.png +0 -0
  133. portal/static/portal/img/logo_cfl_powered.svg +35 -0
  134. portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
  135. portal/static/portal/img/logo_ocado_group.png +0 -0
  136. portal/static/portal/img/logo_python_den.svg +21 -0
  137. portal/static/portal/img/long_europe_map.png +0 -0
  138. portal/static/portal/img/python_den.png +0 -0
  139. portal/static/portal/img/python_den_banner.svg +26 -0
  140. portal/static/portal/img/rapid_router_landing_hero.png +0 -0
  141. portal/static/portal/img/rr_advanced.png +0 -0
  142. portal/static/portal/img/ten_year_map_pin.svg +1 -0
  143. portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
  144. portal/static/portal/img/thumbnail_educate_resources.png +0 -0
  145. portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
  146. portal/static/portal/img/thumbnail_python_den.png +0 -0
  147. portal/static/portal/img/twitter.png +0 -0
  148. portal/static/portal/js/carouselCards.js +25 -0
  149. portal/static/portal/js/common.js +96 -1
  150. portal/static/portal/js/independentLogin.js +16 -0
  151. portal/static/portal/js/independentRegistration.js +86 -0
  152. portal/static/portal/js/levelControl.js +77 -0
  153. portal/static/portal/js/lib/jquery.min.js +2 -0
  154. portal/static/portal/js/organisation_manage.js +142 -14
  155. portal/static/portal/js/passwordStrength.js +154 -64
  156. portal/static/portal/js/resetPassword.js +23 -0
  157. portal/static/portal/js/riveted.min.js +238 -239
  158. portal/static/portal/js/school.js +13 -0
  159. portal/static/portal/js/studentLogin.js +16 -0
  160. portal/static/portal/js/teacherEditStudent.js +23 -0
  161. portal/static/portal/js/teacherLogin.js +16 -0
  162. portal/static/portal/js/tenYearMap.js +14 -0
  163. portal/static/portal/sass/colorbox.scss +0 -1
  164. portal/static/portal/sass/modules/_colours.scss +1 -0
  165. portal/static/portal/sass/modules/_levels.scss +1 -1
  166. portal/static/portal/sass/modules/_mixins.scss +21 -0
  167. portal/static/portal/sass/partials/_banners.scss +4 -177
  168. portal/static/portal/sass/partials/_buttons.scss +12 -15
  169. portal/static/portal/sass/partials/_carousel.scss +129 -0
  170. portal/static/portal/sass/partials/_footer.scss +21 -22
  171. portal/static/portal/sass/partials/_forms.scss +60 -5
  172. portal/static/portal/sass/partials/_grids.scss +34 -61
  173. portal/static/portal/sass/partials/_header.scss +28 -20
  174. portal/static/portal/sass/partials/_images.scss +292 -39
  175. portal/static/portal/sass/partials/_popup.scss +18 -15
  176. portal/static/portal/sass/partials/_tables.scss +12 -20
  177. portal/static/portal/sass/partials/_text.scss +6 -10
  178. portal/static/portal/sass/styles.scss +0 -1
  179. portal/static/portal/video/code for life .pdf +0 -0
  180. portal/strings/about.py +5 -0
  181. portal/strings/coding_club.py +9 -0
  182. portal/strings/play.py +6 -5
  183. portal/strings/teach.py +1 -1
  184. portal/strings/teacher_resources.py +2 -8
  185. portal/strings/ten_year_map.py +13 -0
  186. portal/templates/403.html +2 -2
  187. portal/templates/404.html +1 -1
  188. portal/templates/500.html +2 -2
  189. portal/templates/{captcha → django_recaptcha}/includes/js_v2_invisible.html +3 -3
  190. portal/templates/{captcha → django_recaptcha}/widget_v2_invisible.html +2 -2
  191. portal/templates/email.html +4 -2
  192. portal/templates/maintenance.html +34 -0
  193. portal/templates/portal/about.html +94 -62
  194. portal/templates/portal/base.html +176 -152
  195. portal/templates/portal/coding_club.html +100 -0
  196. portal/templates/portal/contribute.html +56 -52
  197. portal/templates/portal/email_invitation_sent.html +1 -1
  198. portal/templates/portal/email_style_template.html +374 -0
  199. portal/templates/portal/email_verification_failed.html +1 -1
  200. portal/templates/portal/email_verification_needed.html +9 -9
  201. portal/templates/portal/form_shapes.html +20 -8
  202. portal/templates/portal/getinvolved.html +6 -6
  203. portal/templates/portal/home.html +35 -10
  204. portal/templates/portal/home_learning.html +19 -19
  205. portal/templates/portal/locked_out.html +0 -1
  206. portal/templates/portal/locked_out_school_student.html +16 -0
  207. portal/templates/portal/login/independent_student.html +31 -15
  208. portal/templates/portal/login/student.html +10 -7
  209. portal/templates/portal/login/student_class_code.html +7 -4
  210. portal/templates/portal/login/teacher.html +34 -17
  211. portal/templates/portal/partials/banner.html +18 -4
  212. portal/templates/portal/partials/benefits.html +1 -1
  213. portal/templates/portal/partials/card_list.html +34 -24
  214. portal/templates/portal/partials/character_list.html +5 -5
  215. portal/templates/portal/partials/cookie_list.html +161 -0
  216. portal/templates/portal/partials/delete_popup.html +18 -0
  217. portal/templates/portal/partials/footer.html +57 -26
  218. portal/templates/portal/partials/header.html +118 -117
  219. portal/templates/portal/partials/hero_card.html +4 -3
  220. portal/templates/portal/partials/info_popup.html +3 -3
  221. portal/templates/portal/partials/invite_admin_teacher.html +23 -0
  222. portal/templates/portal/partials/popup.html +7 -2
  223. portal/templates/portal/partials/register_newsletter_tickbox.html +2 -5
  224. portal/templates/portal/partials/screentime_popup.html +14 -0
  225. portal/templates/portal/partials/service_unavailable_popup.html +17 -0
  226. portal/templates/portal/partials/session_popup.html +19 -0
  227. portal/templates/portal/play/student_dashboard.html +42 -29
  228. portal/templates/portal/play/student_edit_account.html +64 -9
  229. portal/templates/portal/play.html +61 -41
  230. portal/templates/portal/privacy_notice.html +697 -0
  231. portal/templates/portal/register.html +122 -92
  232. portal/templates/portal/reset_password.html +20 -40
  233. portal/templates/portal/reset_password_confirm.html +9 -4
  234. portal/templates/portal/reset_password_email_sent.html +15 -13
  235. portal/templates/portal/teach/base_registering.html +1 -1
  236. portal/templates/portal/teach/class.html +4 -6
  237. portal/templates/portal/teach/dashboard.html +212 -117
  238. portal/templates/portal/teach/invited.html +90 -0
  239. portal/templates/portal/teach/onboarding_classes.html +5 -3
  240. portal/templates/portal/teach/onboarding_print.html +1 -1
  241. portal/templates/portal/teach/onboarding_school.html +26 -139
  242. portal/templates/portal/teach/onboarding_students.html +1 -1
  243. portal/templates/portal/teach/teacher_dismiss_students.html +73 -55
  244. portal/templates/portal/teach/teacher_edit_class.html +168 -11
  245. portal/templates/portal/teach/teacher_edit_student.html +12 -5
  246. portal/templates/portal/teach/teacher_move_all_classes.html +25 -38
  247. portal/templates/portal/teach/teacher_move_students_to_class.html +1 -1
  248. portal/templates/portal/teach.html +61 -42
  249. portal/templates/portal/ten_year_map.html +147 -0
  250. portal/templates/portal/terms.html +191 -42
  251. portal/templates/two_factor/core/login.html +71 -59
  252. portal/templates/two_factor/core/setup.html +58 -49
  253. portal/templates/two_factor/profile/disable.html +1 -1
  254. portal/templates/two_factor/profile/profile.html +35 -17
  255. portal/templatetags/app_tags.py +59 -84
  256. portal/templatetags/card_list_tags.py +0 -4
  257. portal/tests/base_test.py +14 -3
  258. portal/tests/conftest.py +0 -15
  259. portal/tests/migrations/test_migration_make_portaladmin_teacher.py +2 -6
  260. portal/tests/migrations/test_migration_preview_users.py +3 -9
  261. portal/tests/migrations/test_migration_remove_guardian.py +1 -3
  262. portal/tests/migrations/test_migration_use_common_models.py +2 -6
  263. portal/tests/migrations/test_migration_verify_portaladmin.py +1 -3
  264. portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -21
  265. portal/tests/pageObjects/portal/base_page.py +16 -26
  266. portal/tests/pageObjects/portal/email_verification_needed_page.py +3 -2
  267. portal/tests/pageObjects/portal/game_page.py +12 -19
  268. portal/tests/pageObjects/portal/home_page.py +13 -15
  269. portal/tests/pageObjects/portal/independent_login_page.py +13 -17
  270. portal/tests/pageObjects/portal/password_reset_form_page.py +20 -4
  271. portal/tests/pageObjects/portal/password_reset_page.py +25 -0
  272. portal/tests/pageObjects/portal/play/account_page.py +18 -27
  273. portal/tests/pageObjects/portal/play/dashboard_page.py +4 -4
  274. portal/tests/pageObjects/portal/play/join_school_or_club_page.py +8 -10
  275. portal/tests/pageObjects/portal/play/play_base_page.py +5 -3
  276. portal/tests/pageObjects/portal/signup_page.py +28 -59
  277. portal/tests/pageObjects/portal/student_login_class_code.py +6 -9
  278. portal/tests/pageObjects/portal/student_login_page.py +6 -8
  279. portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +3 -3
  280. portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +3 -1
  281. portal/tests/pageObjects/portal/teach/class_page.py +36 -13
  282. portal/tests/pageObjects/portal/teach/dashboard_page.py +43 -84
  283. portal/tests/pageObjects/portal/teach/dismiss_students_page.py +7 -5
  284. portal/tests/pageObjects/portal/teach/edit_student_page.py +10 -8
  285. portal/tests/pageObjects/portal/teach/move_class_page.py +5 -10
  286. portal/tests/pageObjects/portal/teach/move_classes_page.py +4 -2
  287. portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +4 -2
  288. portal/tests/pageObjects/portal/teach/move_students_page.py +6 -13
  289. portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +5 -3
  290. portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +11 -49
  291. portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +7 -12
  292. portal/tests/pageObjects/portal/teach/onboarding_students_page.py +4 -27
  293. portal/tests/pageObjects/portal/teach/teach_base_page.py +6 -4
  294. portal/tests/pageObjects/portal/teacher_login_page.py +10 -16
  295. portal/tests/selenium_test_case.py +3 -43
  296. portal/tests/snapshots/snap_test_partials.py +11 -165
  297. portal/tests/test_2FA.py +15 -33
  298. portal/tests/test_admin.py +15 -97
  299. portal/tests/test_api.py +212 -91
  300. portal/tests/test_captcha_forms.py +2 -2
  301. portal/tests/test_class.py +374 -24
  302. portal/tests/test_emails.py +83 -20
  303. portal/tests/{test_newsletter_footer.py → test_global_forms.py} +5 -5
  304. portal/tests/test_helper_methods.py +30 -0
  305. portal/tests/test_independent_student.py +255 -144
  306. portal/tests/test_invite_teacher.py +318 -10
  307. portal/tests/test_middleware.py +96 -9
  308. portal/tests/test_organisation.py +78 -262
  309. portal/tests/test_partials.py +0 -88
  310. portal/tests/test_ratelimit.py +218 -36
  311. portal/tests/test_school_student.py +35 -40
  312. portal/tests/test_security.py +12 -31
  313. portal/tests/test_teacher.py +425 -325
  314. portal/tests/test_teacher_student.py +103 -91
  315. portal/tests/test_views.py +900 -76
  316. portal/tests/utils/classes.py +2 -2
  317. portal/tests/utils/messages.py +13 -28
  318. portal/urls.py +235 -166
  319. portal/views/admin.py +0 -332
  320. portal/views/api.py +82 -48
  321. portal/views/cron/__init__.py +1 -0
  322. portal/views/cron/user.py +322 -0
  323. portal/views/dotmailer.py +9 -1
  324. portal/views/email.py +33 -77
  325. portal/views/google_analytics.py +28 -0
  326. portal/views/home.py +126 -97
  327. portal/views/legal.py +13 -0
  328. portal/views/login/independent_student.py +5 -5
  329. portal/views/login/student.py +51 -14
  330. portal/views/login/teacher.py +2 -6
  331. portal/views/organisation.py +20 -189
  332. portal/views/registration.py +97 -17
  333. portal/views/student/edit_account_details.py +99 -72
  334. portal/views/student/play.py +81 -62
  335. portal/views/teacher/dashboard.py +421 -149
  336. portal/views/teacher/teach.py +226 -177
  337. portal/views/two_factor/core.py +22 -19
  338. portal/views/two_factor/profile.py +2 -2
  339. codeforlife_portal-5.33.5.dist-info/LICENSE.md +0 -577
  340. codeforlife_portal-5.33.5.dist-info/METADATA +0 -38
  341. deploy/permissions.py +0 -2
  342. example_project/manage.py +0 -10
  343. portal/autoconfig.py +0 -141
  344. portal/csp_config.py +0 -60
  345. portal/forms/add_game.py +0 -33
  346. portal/helpers/location.py +0 -121
  347. portal/static/portal/img/kurono_hero.jpg +0 -0
  348. portal/static/portal/img/kurono_landing_hero.png +0 -0
  349. portal/static/portal/img/kurono_logo.svg +0 -1
  350. portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
  351. portal/static/portal/img/kurono_logo_mark.svg +0 -1
  352. portal/static/portal/img/kurono_resources_hero.jpg +0 -0
  353. portal/static/portal/img/kurono_story.png +0 -0
  354. portal/static/portal/img/ocado-swirl.svg +0 -22
  355. portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
  356. portal/static/portal/img/thumbnail_educate_resources_and_progress_tracking.png +0 -0
  357. portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
  358. portal/static/portal/img/thumbnail_play_kurono.png +0 -0
  359. portal/static/portal/img/x_close_video.png +0 -0
  360. portal/static/portal/js/aimmoGame.js +0 -106
  361. portal/static/portal/js/deleteWorkspaces.js +0 -14
  362. portal/static/portal/js/fuzzySchoolLookup.js +0 -46
  363. portal/static/portal/js/lib/jquery-3.5.1.min.js +0 -2
  364. portal/static/portal/js/lib/jquery-ui-1.12.1.min.js +0 -13
  365. portal/static/portal/sass/partials/_videos.scss +0 -10
  366. portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
  367. portal/strings/student_aimmo_dashboard.py +0 -6
  368. portal/templates/portal/admin/aggregated_data.html +0 -35
  369. portal/templates/portal/admin/map.html +0 -70
  370. portal/templates/portal/mouseflow.html +0 -9
  371. portal/templates/portal/partials/aimmo_games_table.html +0 -83
  372. portal/templates/portal/partials/register_over_required_age_tickbox.html +0 -9
  373. portal/templates/portal/play/independent_student_dashboard.html +0 -64
  374. portal/templates/portal/play/student_aimmo_dashboard.html +0 -63
  375. portal/templates/portal/privacy_policy.html +0 -483
  376. portal/templates/portal/reset_password_email.html +0 -9
  377. portal/templates/portal/teach/invite.html +0 -25
  378. portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
  379. portal/templates/portal/teach/teacher_resources.html +0 -68
  380. portal/templatetags/character_list_tags.py +0 -16
  381. portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
  382. portal/tests/pageObjects/portal/student_password_reset_form_page.py +0 -23
  383. portal/tests/pageObjects/portal/teach/onboarding_revoke_request_page.py +0 -20
  384. portal/tests/pageObjects/portal/teacher_password_reset_form_page.py +0 -23
  385. portal/tests/test_aimmo_dashboards.py +0 -172
  386. portal/tests/test_location.py +0 -217
  387. portal/tests/utils/aimmo_games.py +0 -30
  388. portal/views/aimmo/dashboard.py +0 -119
  389. portal/views/privacy_policy.py +0 -9
  390. portal/views/teacher/teacher_resources.py +0 -42
  391. {portal/views/aimmo → cfl_common}/__init__.py +0 -0
@@ -1,13 +1,11 @@
1
1
  from __future__ import absolute_import
2
2
 
3
3
  import json
4
- import pytest
5
-
6
- from django.test import Client
7
- from django.urls import reverse
8
- from django.contrib.auth.models import User
9
- from selenium.webdriver.common.alert import Alert
4
+ import time
5
+ from unittest.mock import Mock, patch
10
6
 
7
+ import pytest
8
+ from common.models import JoinReleaseStudent
11
9
  from common.tests.utils.classes import create_class_directly
12
10
  from common.tests.utils.organisation import (
13
11
  create_organisation_directly,
@@ -20,13 +18,18 @@ from common.tests.utils.student import (
20
18
  create_student_with_direct_login,
21
19
  )
22
20
  from common.tests.utils.teacher import signup_teacher_directly
21
+ from django.contrib.auth.models import User
22
+ from django.test import Client
23
+ from django.urls import reverse
24
+ from selenium.webdriver.common.alert import Alert
25
+ from selenium.webdriver.common.by import By
23
26
 
24
27
  from portal.tests.pageObjects.portal.home_page import HomePage
25
28
  from .base_test import BaseTest
26
29
 
27
30
 
28
- class TestTeacherStudent(BaseTest):
29
- def test_create(self):
31
+ class TestTeacherStudentFrontend(BaseTest):
32
+ def test_create_valid_name(self):
30
33
  email, password = signup_teacher_directly()
31
34
  create_organisation_directly(email)
32
35
  create_class_directly(email)
@@ -36,52 +39,20 @@ class TestTeacherStudent(BaseTest):
36
39
  HomePage(self.selenium)
37
40
  .go_to_teacher_login_page()
38
41
  .login_no_students(email, password)
42
+ .open_classes_tab()
43
+ .go_to_class_page()
39
44
  )
40
45
 
41
- page, student_name = create_school_student(page)
42
- assert page.student_exists(student_name)
43
-
44
- assert page.__class__.__name__ == "OnboardingStudentListPage"
45
-
46
- def test_create_valid_name_dash(self):
47
- email, password = signup_teacher_directly()
48
- create_organisation_directly(email)
49
- create_class_directly(email)
50
-
51
46
  student_name = "Florian-Gilbert"
47
+ page = page.type_student_name(student_name)
52
48
 
53
- self.selenium.get(self.live_server_url)
54
- page = (
55
- HomePage(self.selenium)
56
- .go_to_teacher_login_page()
57
- .login_no_students(email, password)
58
- )
59
-
60
- page = page.type_student_name(student_name).create_students()
61
-
62
- assert page.student_exists(student_name)
63
-
64
- assert page.__class__.__name__ == "OnboardingStudentListPage"
65
-
66
- def test_create_valid_name_underscore(self):
67
- email, password = signup_teacher_directly()
68
- create_organisation_directly(email)
69
- create_class_directly(email)
49
+ student_name2 = "Florian_Gilbert"
50
+ page = page.type_student_name(student_name2)
70
51
 
71
- student_name = "Florian_Gilbert"
72
-
73
- self.selenium.get(self.live_server_url)
74
- page = (
75
- HomePage(self.selenium)
76
- .go_to_teacher_login_page()
77
- .login_no_students(email, password)
78
- )
79
-
80
- page = page.type_student_name(student_name).create_students()
52
+ page.click_create_students()
81
53
 
82
54
  assert page.student_exists(student_name)
83
-
84
- assert page.__class__.__name__ == "OnboardingStudentListPage"
55
+ assert page.student_exists(student_name2)
85
56
 
86
57
  def test_create_invalid_name(self):
87
58
  email, password = signup_teacher_directly()
@@ -95,14 +66,15 @@ class TestTeacherStudent(BaseTest):
95
66
  HomePage(self.selenium)
96
67
  .go_to_teacher_login_page()
97
68
  .login_no_students(email, password)
69
+ .open_classes_tab()
70
+ .go_to_class_page()
98
71
  )
99
72
 
100
- page = page.type_student_name(student_name).create_students_failure()
73
+ page = page.type_student_name(student_name).click_create_students()
101
74
 
102
75
  assert page.adding_students_failed()
103
76
  assert page.was_form_invalid(
104
- "form-create-students",
105
- "Names may only contain letters, numbers, dashes, underscores, and spaces.",
77
+ "form-create-students", "Names may only contain letters, numbers, dashes, underscores, and spaces."
106
78
  )
107
79
 
108
80
  def test_create_multiple(self):
@@ -115,6 +87,8 @@ class TestTeacherStudent(BaseTest):
115
87
  HomePage(self.selenium)
116
88
  .go_to_teacher_login_page()
117
89
  .login_no_students(email, password)
90
+ .open_classes_tab()
91
+ .go_to_class_page()
118
92
  )
119
93
 
120
94
  page, student_names = create_many_school_students(page, 12)
@@ -134,13 +108,11 @@ class TestTeacherStudent(BaseTest):
134
108
  HomePage(self.selenium)
135
109
  .go_to_teacher_login_page()
136
110
  .login_no_students(email, password)
111
+ .open_classes_tab()
112
+ .go_to_class_page()
137
113
  )
138
114
 
139
- page = (
140
- page.type_student_name(student_name)
141
- .type_student_name(student_name)
142
- .create_students_failure()
143
- )
115
+ page = page.type_student_name(student_name).type_student_name(student_name).click_create_students()
144
116
  assert page.adding_students_failed()
145
117
  assert page.duplicate_students(student_name)
146
118
 
@@ -154,6 +126,8 @@ class TestTeacherStudent(BaseTest):
154
126
  HomePage(self.selenium)
155
127
  .go_to_teacher_login_page()
156
128
  .login_no_students(email, password)
129
+ .open_classes_tab()
130
+ .go_to_class_page()
157
131
  .import_students_from_csv("test_students_names.csv")
158
132
  )
159
133
 
@@ -172,6 +146,8 @@ class TestTeacherStudent(BaseTest):
172
146
  .import_students_from_csv("test_students_names_no_name.csv")
173
147
  )
174
148
 
149
+ time.sleep(1)
150
+
175
151
  alert = Alert(page.browser)
176
152
  assert alert.text == "'Name' column not found in CSV file."
177
153
  alert.dismiss()
@@ -210,6 +186,8 @@ class TestTeacherStudent(BaseTest):
210
186
  .import_students_from_csv("test_students_names_no_name.csv")
211
187
  )
212
188
 
189
+ time.sleep(1)
190
+
213
191
  alert = Alert(page.browser)
214
192
  assert alert.text == "'Name' column not found in CSV file."
215
193
  alert.dismiss()
@@ -258,10 +236,7 @@ class TestTeacherStudent(BaseTest):
258
236
  login_url = page.get_first_login_url()
259
237
  page.browser.get(login_url)
260
238
  assert page.on_correct_page("play_dashboard_page")
261
- assert (
262
- new_student_name
263
- in page.browser.find_element_by_xpath("//div[@class='header']").text
264
- )
239
+ assert new_student_name in page.browser.find_element(By.XPATH, "//div[@class='header']").text
265
240
 
266
241
  def test_update_student_name(self):
267
242
  email, password = signup_teacher_directly()
@@ -366,8 +341,7 @@ class TestTeacherStudent(BaseTest):
366
341
 
367
342
  assert page.is_student_name(name)
368
343
  assert page.was_form_invalid(
369
- "form-edit-student",
370
- "Names may only contain letters, numbers, dashes, underscores, and spaces.",
344
+ "form-edit-student", "Names may only contain letters, numbers, dashes, underscores, and spaces."
371
345
  )
372
346
 
373
347
  def test_update_student_password(self):
@@ -388,7 +362,7 @@ class TestTeacherStudent(BaseTest):
388
362
 
389
363
  assert page.is_student_name(name)
390
364
 
391
- new_student_password = "New_password1"
365
+ new_student_password = "£EDCVFR$5tgb"
392
366
 
393
367
  page = page.type_student_password(new_student_password)
394
368
  page = page.click_set_password_button()
@@ -420,18 +394,13 @@ class TestTeacherStudent(BaseTest):
420
394
 
421
395
  # user/student is removed if they never log in (see below for active student)
422
396
  with pytest.raises(User.DoesNotExist):
423
- u = User.objects.get(id=student.new_user.id)
397
+ User.objects.get(id=student.new_user.id)
424
398
 
425
399
  def test_delete_active_student(self):
426
400
  email, password = signup_teacher_directly()
427
401
  create_organisation_directly(email)
428
402
  _, _, access_code = create_class_directly(email)
429
- (
430
- student,
431
- login_id,
432
- student_name,
433
- student_password,
434
- ) = create_student_with_direct_login(access_code)
403
+ student, login_id, student_name, student_password = create_student_with_direct_login(access_code)
435
404
 
436
405
  # "active student" is one who has logged in
437
406
  c = Client()
@@ -449,7 +418,7 @@ class TestTeacherStudent(BaseTest):
449
418
  # user should be anonymised
450
419
  u = User.objects.get(id=student.new_user.id)
451
420
  assert u.first_name == "Deleted"
452
- assert u.is_active == False
421
+ assert not u.is_active
453
422
 
454
423
  student.refresh_from_db()
455
424
  assert student.login_id == ""
@@ -489,7 +458,7 @@ class TestTeacherStudent(BaseTest):
489
458
  email, password = signup_teacher_directly()
490
459
  create_organisation_directly(email)
491
460
  _, _, access_code = create_class_directly(email)
492
- _, _, _ = create_school_student_directly(access_code)
461
+ create_school_student_directly(access_code)
493
462
 
494
463
  self.selenium.get(self.live_server_url)
495
464
  page = (
@@ -512,10 +481,10 @@ class TestTeacherStudent(BaseTest):
512
481
  def test_move_cancel_disambiguate(self):
513
482
  old_teacher_email, password_1 = signup_teacher_directly()
514
483
  email_2, _ = signup_teacher_directly()
515
- org_name, postcode = create_organisation_directly(old_teacher_email)
516
- join_teacher_to_organisation(email_2, org_name, postcode)
484
+ school = create_organisation_directly(old_teacher_email)
485
+ join_teacher_to_organisation(email_2, school.name)
517
486
  _, _, access_code_1 = create_class_directly(old_teacher_email)
518
- _, _, _ = create_class_directly(email_2)
487
+ create_class_directly(email_2)
519
488
  student_name, _, _ = create_school_student_directly(access_code_1)
520
489
 
521
490
  self.selenium.get(self.live_server_url)
@@ -537,12 +506,15 @@ class TestTeacherStudent(BaseTest):
537
506
  def test_move(self):
538
507
  email_1, password_1 = signup_teacher_directly()
539
508
  email_2, password_2 = signup_teacher_directly()
540
- org_name, postcode = create_organisation_directly(email_1)
541
- join_teacher_to_organisation(email_2, org_name, postcode)
509
+ school = create_organisation_directly(email_1)
510
+ join_teacher_to_organisation(email_2, school.name)
542
511
  _, _, access_code_1 = create_class_directly(email_1)
543
- _, _, _ = create_class_directly(email_2)
512
+ create_class_directly(email_2)
544
513
  student_name_1, _, _ = create_school_student_directly(access_code_1)
545
514
  student_name_2, _, _ = create_school_student_directly(access_code_1)
515
+ # Sort student names alphabetically to match the UI
516
+ if student_name_1 > student_name_2:
517
+ student_name_1, student_name_2 = student_name_2, student_name_1
546
518
 
547
519
  self.selenium.get(self.live_server_url)
548
520
  page = (
@@ -561,21 +533,15 @@ class TestTeacherStudent(BaseTest):
561
533
 
562
534
  page = page.go_to_dashboard()
563
535
 
564
- page = (
565
- page.logout()
566
- .go_to_teacher_login_page()
567
- .login(email_2, password_2)
568
- .open_classes_tab()
569
- .go_to_class_page()
570
- )
536
+ page = page.logout().go_to_teacher_login_page().login(email_2, password_2).open_classes_tab().go_to_class_page()
571
537
  assert page.student_exists(student_name_1)
572
538
 
573
- def test_dismiss(self):
539
+ @patch("common.helpers.emails.send_dotdigital_email")
540
+ def test_dismiss(self, mock_send_dotdigital_email: Mock):
574
541
  email, password = signup_teacher_directly()
575
542
  create_organisation_directly(email)
576
543
  _, _, access_code = create_class_directly(email)
577
- student_name_1, _, _ = create_school_student_directly(access_code)
578
- _, _, _ = create_school_student_directly(access_code)
544
+ student_name_1, _, student = create_school_student_directly(access_code)
579
545
 
580
546
  self.selenium.get(self.live_server_url)
581
547
  page = (
@@ -592,10 +558,56 @@ class TestTeacherStudent(BaseTest):
592
558
  page = page.cancel()
593
559
  assert page.__class__.__name__ == "TeachClassPage"
594
560
 
561
+ page = page.toggle_select_student().dismiss_students().enter_email("student_email@gmail.com").dismiss()
562
+ assert not page.student_exists(student_name_1)
563
+
564
+ # check whether a record is created correctly
565
+ logs = JoinReleaseStudent.objects.filter(student=student)
566
+ assert len(logs) == 1
567
+ assert logs[0].action_type == JoinReleaseStudent.RELEASE
568
+
569
+ mock_send_dotdigital_email.assert_called()
570
+
571
+ @patch("common.helpers.emails.send_dotdigital_email")
572
+ def test_multiple_dismiss(self, mock_send_dotdigital_email: Mock):
573
+ email, password = signup_teacher_directly()
574
+ create_organisation_directly(email)
575
+ _, _, access_code = create_class_directly(email)
576
+ student_name_1, _, student = create_school_student_directly(access_code)
577
+ student_name_2, _, student_2 = create_school_student_directly(access_code)
578
+
579
+ self.selenium.get(self.live_server_url)
595
580
  page = (
596
- page.toggle_select_student()
597
- .dismiss_students()
598
- .enter_email("student_email@gmail.com")
599
- .dismiss()
581
+ HomePage(self.selenium)
582
+ .go_to_teacher_login_page()
583
+ .login(email, password)
584
+ .open_classes_tab()
585
+ .go_to_class_page()
600
586
  )
587
+ assert page.student_exists(student_name_1)
588
+ assert page.student_exists(student_name_2)
589
+
590
+ page = page.toggle_all_students()
591
+ page = page.dismiss_students()
592
+
593
+ # dismiss with the same email address
594
+ SAME_EMAIL = "student_email@gmail.com"
595
+ page = page.enter_email(SAME_EMAIL, 0)
596
+ page = page.enter_email(SAME_EMAIL, 1)
597
+ page = page.dismiss()
598
+
599
+ # the first should be released, the second not
601
600
  assert not page.student_exists(student_name_1)
601
+ assert page.student_exists(student_name_2)
602
+
603
+ # dismiss using teacher's email
604
+ page = page.toggle_all_students()
605
+ page = page.dismiss_students()
606
+
607
+ page = page.enter_email(email, 0)
608
+ page = page.dismiss()
609
+
610
+ # student should still exist
611
+ assert page.student_exists(student_name_2)
612
+
613
+ mock_send_dotdigital_email.assert_called()