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,25 +1,153 @@
1
1
  /* global showPopupConfirmation */
2
2
 
3
3
  function showRemoveConfirmation(path, name) {
4
- let title = "Remove teacher";
5
- let text = "<div class='popup-text'><p>The teacher " + name + ", will be removed from the school or club. If they have any classes you will be asked to move them to other teachers of this school or club.</p><p>Are you sure?</p></div>";
6
- let confirm_handler = "postWithCsrf('" + path + "')";
4
+ let title = "Remove teacher";
5
+ let text =
6
+ "<div class='popup-text'><p>The teacher " +
7
+ name +
8
+ ", will be removed from the school or club. If they have any classes you will be asked to move them to other teachers of this school or club.</p><p>Are you sure?</p></div>";
9
+ let confirm_handler = "postWithCsrf('" + path + "')";
7
10
 
8
- showPopupConfirmation(title, text, confirm_handler);
11
+ showPopupConfirmation(title, text, confirm_handler);
9
12
  }
10
13
 
11
- function showToggleAdminConfirmation(path, name) {
12
- let title = "Make teacher admin";
13
- let text = "<div class='popup-text'><p>The teacher " + name + ", will be made an administrator of this school or club. They will gain all of the powers that you currently have.</p><p>Are you sure?</p></div>";
14
- let confirm_handler = "postWithCsrf('" + path + "')";
15
-
16
- showPopupConfirmation(title, text, confirm_handler);
14
+ function showToggleAdminConfirmation(path) {
15
+ let confirm_handler = "postWithCsrf('" + path + "')";
16
+ const popup = $("#popup-make-admin-teacher")
17
+ popup.addClass("popup--fade")
18
+ const add_admin_button = $("#add_admin_button")
19
+ add_admin_button.attr("onclick", confirm_handler)
17
20
  }
18
21
 
19
22
  function showDisable2FAConfirmation(path, name) {
20
- let title = "Disable 2FA for " + name;
21
- let text = "<div class='popup-text'><p>The teacher " + name + ", will have their two factor authentication disabled. This will make their account less secure.</p><p>Are you sure?</p></div>";
22
- let confirm_handler = "postWithCsrf('" + path + "')";
23
+ let title = "Disable 2FA for " + name;
24
+ let text =
25
+ "<div class='popup-text'><p>The teacher " +
26
+ name +
27
+ ", will have their two factor authentication disabled. This will make their account less secure.</p><p>Are you sure?</p></div>";
28
+ let confirm_handler = "postWithCsrf('" + path + "')";
29
+
30
+ showPopupConfirmation(title, text, confirm_handler);
31
+ }
32
+
33
+ /**
34
+ * Popup for inviting a teacher
35
+ **/
36
+ function showMakeAdminTeacherPopup(event) {
37
+ const popup = $("#popup-make-admin-teacher")
38
+ const is_invite_admin = document.getElementById("id_make_admin_ticked").checked
39
+ if (is_invite_admin) {
40
+ event.preventDefault()
41
+ popup.addClass("popup--fade");
42
+ const add_admin_button = $("#add_admin_button")
43
+
44
+ add_admin_button.on("click", () => event.target.submit())
45
+ }
46
+ }
23
47
 
24
- showPopupConfirmation(title, text, confirm_handler);
48
+ function hideMakeAdminTeacherPopup() {
49
+ $("#popup-make-admin-teacher").removeClass("popup--fade");
25
50
  }
51
+
52
+ /**
53
+ * Show an account delete confirmation popup with a red delete button and either a Cancel or a Review classes button.
54
+ * See dashboard.html for the popup declaration.
55
+ */
56
+ function showDeleteAccountConfirmation(delete_password, unsubscribe_newsletter, has_class = true) {
57
+ const popup = $("#popup-delete-review");
58
+
59
+ if (has_class) {
60
+ popup.find(".popup-box__title").text("You still have classes associated with this account");
61
+ popup
62
+ .find(".popup-box__msg")
63
+ .append("Review classes if you would like to download the scoreboard or transfer students first.");
64
+
65
+ popup.find("#cancel_popup_button").hide();
66
+ } else {
67
+ popup.find(".popup-box__title").text("You are about to delete your account");
68
+ popup.find(".popup-box__msg").append("This action is not reversible. Are you sure you wish to proceed?");
69
+
70
+ popup.find("#review_button").hide();
71
+ }
72
+
73
+ const delete_button = popup.find("#delete_button");
74
+ const delete_path = delete_button.data("delete-path");
75
+ const handler =
76
+ "postWithCsrf('" +
77
+ delete_path +
78
+ "', {password: '" +
79
+ delete_password +
80
+ "', unsubscribe_newsletter: '" +
81
+ unsubscribe_newsletter +
82
+ "'})";
83
+
84
+ delete_button.attr("onclick", handler);
85
+
86
+ popup.addClass("popup--fade");
87
+ }
88
+
89
+ function hideDeleteAccountPopup() {
90
+ $("#popup-delete-review").removeClass("popup--fade");
91
+ }
92
+
93
+ $(document).ready(() => {
94
+ $('#edit_account_details_password, #student_account_form').on(
95
+ 'click',
96
+ '#password-field-icon, #confirm-password-field-icon',
97
+ () => {
98
+ let inputType;
99
+ let dataIcon = $('#password-field-icon').attr('data-icon');
100
+ if (dataIcon === 'material-symbols:visibility') {
101
+ inputType = 'password';
102
+ dataIcon = 'material-symbols:visibility-off';
103
+ } else {
104
+ inputType = 'text';
105
+ dataIcon = 'material-symbols:visibility';
106
+ }
107
+
108
+ $('#id_password').attr('type', inputType);
109
+ $('#id_confirm_password').attr('type', inputType);
110
+
111
+ $('#password-field-icon').attr('data-icon', dataIcon);
112
+ $('#confirm-password-field-icon').attr('data-icon', dataIcon);
113
+ }
114
+ );
115
+
116
+ $('#edit_account_details_password, #student_account_form').on(
117
+ 'click',
118
+ '#current-password-field-icon',
119
+ () => {
120
+ let inputType;
121
+ let dataIcon = $('#current-password-field-icon').attr('data-icon');
122
+ if (dataIcon === 'material-symbols:visibility') {
123
+ inputType = 'password';
124
+ dataIcon = 'material-symbols:visibility-off';
125
+ } else {
126
+ inputType = 'text';
127
+ dataIcon = 'material-symbols:visibility';
128
+ }
129
+
130
+ $('#id_current_password').attr('type', inputType);
131
+ $('#current-password-field-icon').attr('data-icon', dataIcon);
132
+ }
133
+ );
134
+
135
+ $('#delete-account, #delete-indy-account').on(
136
+ 'click',
137
+ '#delete-password-field-icon',
138
+ () => {
139
+ let inputType;
140
+ let dataIcon = $('#delete-password-field-icon').attr('data-icon');
141
+ if (dataIcon === 'material-symbols:visibility') {
142
+ inputType = 'password';
143
+ dataIcon = 'material-symbols:visibility-off';
144
+ } else {
145
+ inputType = 'text';
146
+ dataIcon = 'material-symbols:visibility';
147
+ }
148
+
149
+ $('#id_delete_password').attr('type', inputType);
150
+ $('#delete-password-field-icon').attr('data-icon', dataIcon);
151
+ }
152
+ );
153
+ });
@@ -1,82 +1,172 @@
1
- var TEACHER_PASSWORD_FIELD_ID = '';
2
- var INDEP_STUDENT_PASSWORD_FIELD_ID = '';
3
- let teacher_password_field = '';
4
- let indep_student_password_field = '';
5
- let most_used_passwords = ['Abcd1234', 'Password1', 'Qwerty123'];
1
+ const TEACHER_PASSWORD_FIELD = $(`#${TEACHER_PASSWORD_FIELD_ID}`);
2
+ const INDEP_STUDENT_PASSWORD_FIELD = $(`#${INDEP_STUDENT_PASSWORD_FIELD_ID}`);
6
3
 
7
4
  let password_strengths = [
8
- { name: 'No password!', colour: '#FF0000' },
9
- { name: 'Password too weak!', colour: '#DBA901' },
10
- { name: 'Strong password!', colour: '#088A08' },
11
- { name: 'Password too common!', colour: '#DBA901' }
5
+ { name: 'No password!', colour: '#FF0000' },
6
+ { name: 'Password too weak!', colour: '#DBA901' },
7
+ { name: 'Password too common!', colour: '#DBA901' },
8
+ { name: 'Strong password!', colour: '#088A08' }
12
9
  ];
13
10
 
14
- $(function() {
15
-
16
- teacher_password_field = $('#' + TEACHER_PASSWORD_FIELD_ID);
17
- indep_student_password_field = $('#' + INDEP_STUDENT_PASSWORD_FIELD_ID);
18
-
19
- setUpDynamicUpdates(teacher_password_field, true);
20
- setUpDynamicUpdates(indep_student_password_field, false);
21
-
22
- updatePasswordStrength(true);
23
- updatePasswordStrength(false);
24
- });
25
-
26
- function setUpDynamicUpdates(password_field, isTeacher) {
27
- password_field.on('keyup', function(){
28
- updatePasswordStrength(isTeacher)
29
- });
30
- password_field.on('paste', function(){
31
- updatePasswordStrength(isTeacher)
32
- });
33
- password_field.on('cut', function(){
34
- updatePasswordStrength(isTeacher)
35
- });
11
+ async function handlePasswordStrength() {
12
+ const teacherPwd = TEACHER_PASSWORD_FIELD.val();
13
+ const studentPwd = INDEP_STUDENT_PASSWORD_FIELD.val();
14
+
15
+ const isTeacherPwdTyped = teacherPwd.length > 0;
16
+ const isStudentPwdTyped = studentPwd.length > 0;
17
+
18
+ const isTeacherPwdStrong =
19
+ isTeacherPwdTyped && isPasswordStrong(teacherPwd, true);
20
+ const isStudentPwdStrong =
21
+ isStudentPwdTyped && isPasswordStrong(studentPwd, false);
22
+
23
+ const isTeacherPwdSafe =
24
+ isTeacherPwdStrong && !(await isPasswordPwned(teacherPwd));
25
+ const isStudentPwdSafe =
26
+ isStudentPwdStrong && !(await isPasswordPwned(studentPwd));
27
+
28
+ const teacherPwdStrength = [
29
+ isTeacherPwdTyped,
30
+ isTeacherPwdStrong,
31
+ isTeacherPwdSafe
32
+ ].filter(Boolean).length;
33
+ const studentPwdStrength = [
34
+ isStudentPwdTyped,
35
+ isStudentPwdStrong,
36
+ isStudentPwdSafe
37
+ ].filter(Boolean).length;
38
+
39
+ $('#teacher-password-sign').css(
40
+ 'background-color',
41
+ password_strengths[teacherPwdStrength].colour
42
+ );
43
+ $('#teacher-password-text').html(password_strengths[teacherPwdStrength].name);
44
+ $('#student-password-sign').css(
45
+ 'background-color',
46
+ password_strengths[studentPwdStrength].colour
47
+ );
48
+ $('#student-password-text').html(password_strengths[studentPwdStrength].name);
36
49
  }
37
50
 
38
- function updatePasswordStrength(isTeacher) {
39
- // The reason for the timeout is that if we just got $('#...').val() we'd get the
40
- // old value before the keypress / change. Apparently even jQuery itself implements
41
- // things this way, so maybe there is no better workaround.
51
+ const isPasswordPwned = async (password) => {
52
+ const computeSHA1Hash = (password) =>
53
+ CryptoJS.SHA1(password).toString().toUpperCase();
42
54
 
43
- setTimeout(function() {
44
- let password;
55
+ try {
56
+ const hashedPassword = computeSHA1Hash(password);
57
+ const prefix = hashedPassword.substring(0, 5);
58
+ const suffix = hashedPassword.substring(5);
59
+ const apiUrl = `https://api.pwnedpasswords.com/range/${prefix}`;
45
60
 
46
- if (isTeacher) {
47
- password = $('#' + TEACHER_PASSWORD_FIELD_ID).val();
48
- }
49
- else {
50
- password = $('#' + INDEP_STUDENT_PASSWORD_FIELD_ID).val();
51
- }
61
+ const response = await fetch(apiUrl);
52
62
 
53
- let strength = 0;
54
- if (password.length > 0) { strength++; }
55
- if (isPasswordStrong(password, isTeacher)) { strength++; }
63
+ if (!response.ok) {
64
+ return false; // ignore the check if the server is down as the popup warns
65
+ // the user that we cannot check the password
66
+ }
56
67
 
57
- if ($.inArray(password, most_used_passwords) >= 0 && strength == 2) { strength = 3; }
68
+ const data = await response.text();
58
69
 
59
- if (isTeacher) {
60
- updatePasswordCSS('#teacher-password-sign', '#teacher-password-text', strength);
61
- }
62
- else {
63
- updatePasswordCSS('#student-password-sign', '#student-password-text', strength);
64
- }
70
+ return data.includes(suffix);
71
+ } catch (error) {
72
+ console.error(`Request failed with error: ${error.message}`);
73
+ return false;
74
+ }
75
+ };
65
76
 
66
- });
77
+ function isPasswordStrong(password, isTeacher) {
78
+ if (isTeacher) {
79
+ return (
80
+ password.length >= 10 &&
81
+ !(
82
+ password.search(/[A-Z]/) === -1 ||
83
+ password.search(/[a-z]/) === -1 ||
84
+ password.search(/[0-9]/) === -1 ||
85
+ password.search(/[!@#$%^&*()_+\-=\[\]{};':\"\\|,.<>\/?]/) === -1
86
+ )
87
+ );
88
+ } else {
89
+ return (
90
+ password.length >= 8 &&
91
+ !(
92
+ password.search(/[A-Z]/) === -1 ||
93
+ password.search(/[a-z]/) === -1 ||
94
+ password.search(/[0-9]/) === -1
95
+ )
96
+ );
97
+ }
67
98
  }
68
99
 
69
- function isPasswordStrong(password, isTeacher) {
70
- if (isTeacher) {
71
- return password.length >= 10 && !(password.search(/[A-Z]/) === -1 || password.search(/[a-z]/) === -1 || password.search(/[0-9]/) === -1 || password.search(/[!@#$%^&*()_+\-=\[\]{};':\"\\|,.<>\/?]/) === -1)
72
- }
73
- else {
74
- return password.length >= 8 && !(password.search(/[A-Z]/) === -1 || password.search(/[a-z]/) === -1 || password.search(/[0-9]/) === -1)
75
- }
100
+ async function isPwnedPasswordApiAvailable(url) {
101
+ try {
102
+ const response = await fetch(url, { metheod: 'GET' });
103
+ return response.ok;
104
+ } catch (error) {
105
+ console.error(error);
106
+ return false;
107
+ }
108
+ }
109
+ async function handlePwnedPasswordApiAvailability() {
110
+ const url = 'https://api.pwnedpasswords.com/range/00000';
111
+ const isAvailable = await isPwnedPasswordApiAvailable(url);
112
+ const errorTitle = 'Password Vulnerability Check Unavailable';
113
+ const errorMessage =
114
+ 'We are currently unable to check your password vulnerability. Please ensure that you are using a strong password. If you are happy to continue, please confirm.';
115
+ if (!isAvailable) {
116
+ showServiceUnavailable(errorTitle, errorMessage);
117
+ }
76
118
  }
77
119
 
78
- function updatePasswordCSS(passwordStrengthSign, passwordStrengthText, strength) {
79
- $(passwordStrengthSign).css('background-color', password_strengths[strength].colour);
80
- $(passwordStrengthText).html(password_strengths[strength].name);
120
+ function onClickPasswordVisibility(
121
+ formId,
122
+ passwordIconId,
123
+ confirmPasswordIconId,
124
+ passwordId,
125
+ confirmPasswordId
126
+ ) {
127
+ // Delegate event listeners.
128
+ $(formId).on('click', '[data-icon^="material-symbols:visibility"]', function () {
129
+ // Get icons and input types.
130
+ let inputType;
131
+ let dataIcon;
132
+ if ($(this).attr('data-icon') === 'material-symbols:visibility') {
133
+ inputType = 'password';
134
+ dataIcon = 'material-symbols:visibility-off';
135
+ } else {
136
+ inputType = 'text';
137
+ dataIcon = 'material-symbols:visibility';
138
+ }
139
+
140
+ // Set icons.
141
+ $(passwordIconId).attr('data-icon', dataIcon);
142
+ $(confirmPasswordIconId).attr('data-icon', dataIcon);
143
+
144
+ // Set input types.
145
+ $(passwordId).attr('type', inputType);
146
+ $(confirmPasswordId).attr('type', inputType);
147
+ })
81
148
  }
82
149
 
150
+ $(document).ready(function () {
151
+ handlePasswordStrength(); // the password strength text is updated dynamically hence this is the initial first call
152
+ handlePwnedPasswordApiAvailability();
153
+ $(
154
+ `#${TEACHER_PASSWORD_FIELD_ID}, #${INDEP_STUDENT_PASSWORD_FIELD_ID}`
155
+ ).on('input change focus blur', handlePasswordStrength);
156
+
157
+ onClickPasswordVisibility(
158
+ '#teacher-register-form',
159
+ '#teacher-password-field-icon',
160
+ '#teacher-confirm-password-field-icon',
161
+ '#id_teacher_signup-teacher_password',
162
+ '#id_teacher_signup-teacher_confirm_password'
163
+ );
164
+
165
+ onClickPasswordVisibility(
166
+ '#independent-student-register-form',
167
+ '#independent-student-password-field-icon',
168
+ '#independent-student-confirm-password-field-icon',
169
+ '#id_independent_student_signup-password',
170
+ '#id_independent_student_signup-confirm_password'
171
+ );
172
+ });
@@ -0,0 +1,23 @@
1
+ $(document).ready(() => {
2
+ $('#reset-password-form').on(
3
+ 'click',
4
+ '#password-field-icon, #confirm-password-field-icon',
5
+ () => {
6
+ let inputType;
7
+ let dataIcon = $('#password-field-icon').attr('data-icon');
8
+ if (dataIcon === 'material-symbols:visibility') {
9
+ inputType = 'password';
10
+ dataIcon = 'material-symbols:visibility-off';
11
+ } else {
12
+ inputType = 'text';
13
+ dataIcon = 'material-symbols:visibility';
14
+ }
15
+
16
+ $('#id_new_password1').attr('type', inputType);
17
+ $('#id_new_password2').attr('type', inputType);
18
+
19
+ $('#password-field-icon').attr('data-icon', dataIcon);
20
+ $('#confirm-password-field-icon').attr('data-icon', dataIcon);
21
+ }
22
+ );
23
+ });