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,20 +1,23 @@
1
1
  from __future__ import absolute_import
2
2
 
3
3
  from datetime import datetime, timedelta
4
+ from unittest.mock import ANY, Mock, patch
4
5
 
6
+ import pytest
5
7
  import pytz
6
- import re
7
- from common.models import Teacher, Student
8
+ from common.mail import campaign_ids
9
+ from common.models import DailyActivity, Student, Teacher
8
10
  from common.tests.utils.classes import create_class_directly
9
11
  from common.tests.utils.organisation import create_organisation_directly
10
12
  from common.tests.utils.student import (
11
13
  create_independent_student_directly,
12
14
  create_school_student_directly,
15
+ generate_independent_student_details,
13
16
  )
14
- from common.tests.utils.teacher import signup_teacher_directly
17
+ from common.tests.utils.teacher import generate_details, signup_teacher_directly
15
18
  from django.core import mail
16
19
  from django.test import Client, TestCase
17
- from django.urls import reverse
20
+ from django.urls import reverse, reverse_lazy
18
21
 
19
22
  from portal.helpers.ratelimit import get_ratelimit_count_for_user
20
23
  from portal.views.login import has_user_lockout_expired
@@ -27,20 +30,17 @@ class TestRatelimit(TestCase):
27
30
  def _teacher_login(self, username, password):
28
31
  return self.client.post(
29
32
  reverse("teacher_login"),
30
- {
31
- "auth-username": username,
32
- "auth-password": password,
33
- "teacher_login_view-current_step": "auth",
34
- },
33
+ {"auth-username": username, "auth-password": password, "teacher_login_view-current_step": "auth"},
35
34
  )
36
35
 
37
36
  def _student_login(self, username, password):
37
+ return self.client.post(reverse("independent_student_login"), {"username": username, "password": password})
38
+
39
+ def _student_school_login(self, access_code, student_name, student_password):
38
40
  return self.client.post(
39
- reverse("independent_student_login"),
40
- {
41
- "username": username,
42
- "password": password,
43
- },
41
+ reverse("student_login", kwargs={"access_code": access_code}),
42
+ {"username": student_name, "password": student_password},
43
+ follow=True,
44
44
  )
45
45
 
46
46
  def _teacher_update_account_bad_request(self) -> None:
@@ -79,23 +79,13 @@ class TestRatelimit(TestCase):
79
79
 
80
80
  def _reset_password_request(self, email):
81
81
  return self.client.post(
82
- reverse("teacher_password_reset"),
83
- {
84
- "email": email,
85
- "g-recaptcha-response": "something",
86
- },
82
+ reverse("teacher_password_reset"), {"email": email, "g-recaptcha-response": "something"}
87
83
  )
88
84
 
89
85
  def _reset_password(self, url, new_password):
90
- return self.client.post(
91
- url,
92
- {
93
- "new_password1": new_password,
94
- "new_password2": new_password,
95
- },
96
- )
86
+ return self.client.post(url, {"new_password1": new_password, "new_password2": new_password})
97
87
 
98
- def _is_user_blocked(self, model: Teacher or Student, username: str) -> bool:
88
+ def _is_user_blocked(self, model: Teacher or Student, username: str, access_code: str = None) -> bool:
99
89
  """
100
90
  Checks if a Teacher or a Student object is blocked, by checking if they
101
91
  have a blocked_time value, and if so, if it the lockout has expired or not.
@@ -103,20 +93,30 @@ class TestRatelimit(TestCase):
103
93
  :param username: The username of the Teacher or Student.
104
94
  :return: Whether or not the model object is marked as blocked.
105
95
  """
106
- user = model.objects.get(new_user__username=username)
96
+ user = (
97
+ model.objects.get(new_user__username=username)
98
+ if not access_code
99
+ else model.objects.get(new_user__first_name=username, class_field__access_code=access_code)
100
+ )
107
101
  if user.blocked_time:
108
102
  return not has_user_lockout_expired(user)
109
103
  else:
110
104
  return False
111
105
 
112
- def _block_user(self, model: Teacher or Student, username: str) -> None:
106
+ def _block_user(self, model: Teacher or Student, username: str, access_code=None) -> None:
113
107
  """
114
108
  Finds the Teacher or Student corresponding to the username, and sets it as
115
109
  blocked and sets the blocked date to now.
116
110
  :param model: The model Class to be checked against.
117
111
  :param username: The username of the Teacher or Student.
118
112
  """
119
- user = model.objects.get(new_user__username=username)
113
+
114
+ user = (
115
+ model.objects.get(new_user__username=username)
116
+ if access_code is None
117
+ else model.objects.get(new_user__first_name=username, class_field__access_code=access_code)
118
+ )
119
+
120
120
  user.blocked_time = datetime.now(tz=pytz.utc)
121
121
  user.save()
122
122
 
@@ -137,6 +137,54 @@ class TestRatelimit(TestCase):
137
137
 
138
138
  assert self._is_user_blocked(Teacher, email)
139
139
 
140
+ def test_student_login_ratelimit(self):
141
+ """
142
+ Given a student,
143
+ When they perform 6 failed login attempts,
144
+ Then on the 6th one, the student should be blocked.
145
+ """
146
+ teacher_email, teacher_password = signup_teacher_directly()
147
+ school = create_organisation_directly(teacher_email)
148
+ klass, klass_name, klass_access_code = create_class_directly(teacher_email)
149
+ student_name, student_password, student = create_school_student_directly(klass_access_code)
150
+
151
+ for i in range(10):
152
+ response = self._student_school_login(klass_access_code, student_name, "bad_password")
153
+
154
+ assert not self._is_user_blocked(Student, student_name, klass_access_code)
155
+
156
+ _ = self._student_school_login(klass_access_code, student_name, "bad_password")
157
+
158
+ assert self._is_user_blocked(Student, student_name, klass_access_code)
159
+ student = Student.objects.get(id=student.id)
160
+ current_student = Student.objects.get(
161
+ new_user__first_name=student_name, class_field__access_code=klass_access_code
162
+ )
163
+
164
+ # now check if teacher can unlock it, both ways :)
165
+ url = reverse_lazy("teacher_class_password_reset", kwargs={"access_code": klass_access_code})
166
+ data = {"transfer_students": [[current_student.id]]}
167
+ c = Client()
168
+
169
+ c.login(username=teacher_email, password=teacher_password)
170
+ c.post(url, data)
171
+ assert not self._is_user_blocked(Student, student_name, klass_access_code)
172
+
173
+ # now block again and test the edit by student method
174
+ self._block_user(Student, student_name, klass_access_code)
175
+ assert self._is_user_blocked(Student, student_name, klass_access_code)
176
+ url = reverse_lazy("teacher_edit_student", kwargs={"pk": current_student.id})
177
+ strong_password = "£EDCVFR$5tgbnhy6"
178
+ data = {"password": strong_password, "confirm_password": strong_password, "set_password": ""}
179
+
180
+ c.post(url, data)
181
+ assert not self._is_user_blocked(Student, student_name, klass_access_code)
182
+ c.logout()
183
+ student = Student.objects.get(id=student.id)
184
+ self._student_school_login(klass_access_code, student_name, "password1")
185
+ student = Student.objects.get(id=student.id)
186
+ assert not self._is_user_blocked(Student, student_name, klass_access_code)
187
+
140
188
  def test_independent_student_login_ratelimit(self):
141
189
  """
142
190
  Given an independent student,
@@ -277,7 +325,8 @@ class TestRatelimit(TestCase):
277
325
 
278
326
  assert get_ratelimit_count_for_user(email) == 1
279
327
 
280
- def test_teacher_reset_password_unblocks_user(self):
328
+ @patch("portal.forms.registration.send_dotdigital_email")
329
+ def test_teacher_reset_password_unblocks_user(self, mock_send_dotdigital_email: Mock):
281
330
  """
282
331
  Given a blocked teacher,
283
332
  When they reset they password,
@@ -295,17 +344,150 @@ class TestRatelimit(TestCase):
295
344
  # Ask for reset password link
296
345
  self._reset_password_request(email)
297
346
 
298
- assert len(mail.outbox) == 1
347
+ mock_send_dotdigital_email.assert_called_once_with(
348
+ campaign_ids["reset_password"], ANY, personalization_values=ANY
349
+ )
299
350
 
300
- # Get reset link from email
301
- message = str(mail.outbox[0].body)
302
- url = re.search("http.+/", message).group(0)
351
+ reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
352
+ "RESET_PASSWORD_LINK"
353
+ ]
303
354
 
304
355
  new_password = "AnotherPassword12!"
305
356
 
306
- self._reset_password(url, new_password)
357
+ self._reset_password(reset_password_url, new_password)
307
358
 
308
359
  login_response = self._teacher_login(email, new_password)
309
360
 
310
361
  assert login_response.status_code == 302
311
362
  assert not self._is_user_blocked(Teacher, email)
363
+
364
+ def test_lockout_reset_tracking(self):
365
+ old_date = datetime.now() - timedelta(days=1)
366
+ old_daily_activity = DailyActivity(date=old_date)
367
+ old_daily_activity.save()
368
+ teacher_email, teacher_password = signup_teacher_directly()
369
+ indy_email, indy_password, student = create_independent_student_directly()
370
+ create_organisation_directly(teacher_email)
371
+
372
+ self._block_user(Teacher, teacher_email)
373
+ self._block_user(Student, indy_email)
374
+
375
+ # check teacher response for resetting password
376
+ url = reverse_lazy("teacher_password_reset")
377
+ data = {"email": teacher_email}
378
+
379
+ c = Client()
380
+
381
+ response = c.post(url, data=data)
382
+ old_daily_activity = DailyActivity.objects.get(date=old_date)
383
+ current_daily_activity = DailyActivity.objects.get(date=datetime.now())
384
+
385
+ assert response.status_code == 200
386
+ assert old_daily_activity.teacher_lockout_resets == 0
387
+ assert current_daily_activity.teacher_lockout_resets == 1
388
+ # now check the indy student
389
+
390
+ url = reverse_lazy("student_password_reset")
391
+ data = {"email": indy_email}
392
+ c = Client()
393
+
394
+ response = c.post(url, data=data)
395
+ old_daily_activity = DailyActivity.objects.get(date=old_date)
396
+ current_daily_activity = DailyActivity.objects.get(date=datetime.now())
397
+
398
+ assert response.status_code == 200
399
+ assert old_daily_activity.indy_lockout_resets == 0
400
+ assert current_daily_activity.indy_lockout_resets == 1
401
+ # finally check the school student
402
+
403
+ # method 1
404
+ _, _, klass_access_code = create_class_directly(teacher_email)
405
+ student_name, _, student = create_school_student_directly(klass_access_code)
406
+
407
+ self._block_user(Student, student_name, access_code=klass_access_code)
408
+
409
+ c = Client()
410
+ c.login(username=teacher_email, password=teacher_password)
411
+
412
+ url = reverse_lazy("teacher_edit_student", kwargs={"pk": student.id})
413
+ strong_password = "£EDCVFR$5tgb"
414
+ data = {"password": strong_password, "confirm_password": strong_password, "set_password": ""}
415
+
416
+ response = c.post(url, data)
417
+ old_daily_activity = DailyActivity.objects.get(date=old_date)
418
+ current_daily_activity = DailyActivity.objects.get(date=datetime.now())
419
+
420
+ assert response.status_code == 200
421
+ assert old_daily_activity.school_student_lockout_resets == 0
422
+ assert current_daily_activity.school_student_lockout_resets == 1
423
+
424
+ # method 2
425
+ self._block_user(Student, student_name, access_code=klass_access_code)
426
+ url = reverse_lazy("teacher_class_password_reset", kwargs={"access_code": klass_access_code})
427
+ data = {"transfer_students": [[student.id]]}
428
+
429
+ response = c.post(url, data)
430
+ old_daily_activity = DailyActivity.objects.get(date=old_date)
431
+ current_daily_activity = DailyActivity.objects.get(date=datetime.now())
432
+
433
+ assert response.status_code == 200
434
+ assert old_daily_activity.school_student_lockout_resets == 0
435
+ assert current_daily_activity.school_student_lockout_resets == 2
436
+
437
+
438
+ @patch("common.helpers.emails.send_dotdigital_email")
439
+ @pytest.mark.django_db
440
+ def test_teacher_already_registered_email(mock_send_dotdigital_email: Mock, client):
441
+ first_name, last_name, email, password = generate_details()
442
+ register_url = reverse("register")
443
+ data = {
444
+ "teacher_signup-teacher_first_name": first_name,
445
+ "teacher_signup-teacher_last_name": last_name,
446
+ "teacher_signup-teacher_email": email,
447
+ "teacher_signup-consent_ticked": "on",
448
+ "teacher_signup-teacher_password": password,
449
+ "teacher_signup-teacher_confirm_password": password,
450
+ "g-recaptcha-response": "something",
451
+ }
452
+
453
+ # Register the teacher first time, there should be a registration email
454
+ client.post(register_url, data)
455
+ mock_send_dotdigital_email.assert_called_once_with(campaign_ids["verify_new_user"], ANY, personalization_values=ANY)
456
+
457
+ # Register with the same email again, there should also be an already registered email
458
+ client.post(register_url, data)
459
+ assert len(mail.outbox) == 1
460
+
461
+ # Register with the same email one more time, there shouldn't be any new emails
462
+ client.post(register_url, data)
463
+ assert len(mail.outbox) == 1
464
+
465
+
466
+ @patch("common.helpers.emails.send_dotdigital_email")
467
+ @pytest.mark.django_db
468
+ def test_independent_student_already_registered_email(mock_send_dotdigital_email: Mock, client):
469
+ name, username, email_address, password = generate_independent_student_details()
470
+ register_url = reverse("register")
471
+ data = {
472
+ "independent_student_signup-date_of_birth_day": 7,
473
+ "independent_student_signup-date_of_birth_month": 10,
474
+ "independent_student_signup-date_of_birth_year": 1997,
475
+ "independent_student_signup-name": name,
476
+ "independent_student_signup-email": email_address,
477
+ "independent_student_signup-consent_ticked": "on",
478
+ "independent_student_signup-password": password,
479
+ "independent_student_signup-confirm_password": password,
480
+ "g-recaptcha-response": "something",
481
+ }
482
+
483
+ # Register the independent student first time, there should be a registration email
484
+ client.post(register_url, data)
485
+ mock_send_dotdigital_email.assert_called_once_with(campaign_ids["verify_new_user"], ANY, personalization_values=ANY)
486
+
487
+ # Register with the same email again, there should also be an already registered email
488
+ client.post(register_url, data)
489
+ assert len(mail.outbox) == 1
490
+
491
+ # Reset mock and register with the same email one more time, there shouldn't be any new emails
492
+ client.post(register_url, data)
493
+ assert len(mail.outbox) == 1
@@ -7,10 +7,7 @@ from common.tests.utils.teacher import signup_teacher_directly
7
7
 
8
8
  from portal.tests.pageObjects.portal.home_page import HomePage
9
9
  from .base_test import BaseTest
10
- from .utils.messages import (
11
- is_student_details_updated_message_showing,
12
- is_password_updated_message_showing,
13
- )
10
+ from .utils.messages import is_student_details_updated_message_showing, is_password_updated_message_showing
14
11
 
15
12
 
16
13
  class TestSchoolStudent(BaseTest):
@@ -36,15 +33,10 @@ class TestSchoolStudent(BaseTest):
36
33
  student_name, _, _ = create_school_student_directly(access_code)
37
34
 
38
35
  self.selenium.get(self.live_server_url)
39
- page = (
40
- HomePage(self.selenium)
41
- .go_to_student_login_page()
42
- .student_input_access_code_failure("not a class code")
43
- )
36
+ page = HomePage(self.selenium).go_to_student_login_page().student_input_access_code_failure("not a class code")
44
37
 
45
38
  assert page.has_access_code_input_failed(
46
- "form-login-school-class-code",
47
- "Uh oh! You didn't input a valid class code.",
39
+ "form-login-school-class-code", "Uh oh! You didn't input a valid class code."
48
40
  )
49
41
 
50
42
  def test_login_failure(self):
@@ -61,9 +53,7 @@ class TestSchoolStudent(BaseTest):
61
53
  .student_login_failure(student_name, "some other password")
62
54
  )
63
55
 
64
- assert page.has_login_failed(
65
- "form-login-school", "Invalid name, class access code or password"
66
- )
56
+ assert page.has_login_failed("form-login-school", "Invalid name, class access code or password")
67
57
 
68
58
  def test_login_nonexistent_class(self):
69
59
  email, _ = signup_teacher_directly()
@@ -79,9 +69,7 @@ class TestSchoolStudent(BaseTest):
79
69
  .student_login_failure(student_name, student_password)
80
70
  )
81
71
 
82
- assert page.has_login_failed(
83
- "form-login-school", "Invalid name, class access code or password"
84
- )
72
+ assert page.has_login_failed("form-login-school", "Invalid name, class access code or password")
85
73
 
86
74
  def test_login_empty_class(self):
87
75
  email, _ = signup_teacher_directly()
@@ -98,9 +86,7 @@ class TestSchoolStudent(BaseTest):
98
86
  .student_login_failure(student_name, student_password)
99
87
  )
100
88
 
101
- assert page.has_login_failed(
102
- "form-login-school", "Invalid name, class access code or password"
103
- )
89
+ assert page.has_login_failed("form-login-school", "Invalid name, class access code or password")
104
90
 
105
91
  def test_update_password_current_password_wrong(self):
106
92
  email, _ = signup_teacher_directly()
@@ -118,12 +104,10 @@ class TestSchoolStudent(BaseTest):
118
104
  assert self.is_dashboard(page)
119
105
 
120
106
  page = page.go_to_account_page().update_password_failure(
121
- "NewPassword", "NewPassword", "WrongPassword"
107
+ "£EDCVFR$5tgb", "£EDCVFR$5tgb", "Wrong_123$£$3_Password"
122
108
  )
123
109
  assert self.is_account_page(page)
124
- assert page.was_form_invalid(
125
- "student_account_form", "Your current password was incorrect"
126
- )
110
+ assert page.was_form_invalid("student_account_form", "Your current password was incorrect")
127
111
 
128
112
  def test_update_password_passwords_not_match(self):
129
113
  email, _ = signup_teacher_directly()
@@ -140,13 +124,9 @@ class TestSchoolStudent(BaseTest):
140
124
  )
141
125
  assert self.is_dashboard(page)
142
126
 
143
- page = page.go_to_account_page().update_password_failure(
144
- "NewPassword1", "OtherPassword1", student_password
145
- )
127
+ page = page.go_to_account_page().update_password_failure("£EDECVFR$5tgb", "%TGBNHY^&ujm,ki8", student_password)
146
128
  assert self.is_account_page(page)
147
- assert page.was_form_invalid(
148
- "student_account_form", "Your new passwords do not match"
149
- )
129
+ assert page.was_form_invalid("student_account_form", "Your new passwords do not match")
150
130
 
151
131
  def test_update_password_too_weak(self):
152
132
  email, _ = signup_teacher_directly()
@@ -163,16 +143,14 @@ class TestSchoolStudent(BaseTest):
163
143
  )
164
144
  assert self.is_dashboard(page)
165
145
 
166
- page = page.go_to_account_page().update_password_failure(
167
- "tiny", "tiny", student_password
168
- )
146
+ page = page.go_to_account_page().update_password_failure("tiny", "tiny", student_password)
169
147
  assert self.is_account_page(page)
170
148
  assert page.was_form_invalid(
171
149
  "student_account_form",
172
150
  "Password not strong enough, consider using at least 6 characters and making it hard to guess.",
173
151
  )
174
152
 
175
- def test_update_password_success(self):
153
+ def test_update_password_too_common(self):
176
154
  email, _ = signup_teacher_directly()
177
155
  create_organisation_directly(email)
178
156
  _, _, access_code = create_class_directly(email)
@@ -187,18 +165,35 @@ class TestSchoolStudent(BaseTest):
187
165
  )
188
166
  assert self.is_dashboard(page)
189
167
 
190
- new_password = "NewPassword"
168
+ page = page.go_to_account_page().update_password_failure("Password123$", "Password123$", student_password)
169
+ assert self.is_account_page(page)
170
+ assert page.was_form_invalid(
171
+ "student_account_form", "Password is too common, consider using a different password."
172
+ )
191
173
 
192
- page = page.go_to_account_page().update_password_success(
193
- new_password, student_password
174
+ def test_update_password_success(self):
175
+ email, _ = signup_teacher_directly()
176
+ create_organisation_directly(email)
177
+ _, _, access_code = create_class_directly(email)
178
+ student_name, student_password, _ = create_school_student_directly(access_code)
179
+
180
+ self.selenium.get(self.live_server_url)
181
+ page = (
182
+ HomePage(self.selenium)
183
+ .go_to_student_login_page()
184
+ .student_input_access_code(access_code)
185
+ .student_login(student_name, student_password)
194
186
  )
187
+ assert self.is_dashboard(page)
188
+
189
+ new_password = "£EDCVFR$%TGBhny6"
190
+
191
+ page = page.go_to_account_page().update_password_success(new_password, student_password)
195
192
  assert is_student_details_updated_message_showing(self.selenium)
196
193
  assert is_password_updated_message_showing(self.selenium)
197
194
  assert self.is_login_class_code_page(page)
198
195
 
199
- page = page.student_input_access_code(access_code).student_login(
200
- student_name, new_password
201
- )
196
+ page = page.student_input_access_code(access_code).student_login(student_name, new_password)
202
197
  assert self.is_dashboard(page)
203
198
 
204
199
  def is_dashboard(self, page):
@@ -2,13 +2,12 @@ from __future__ import absolute_import
2
2
 
3
3
  from builtins import str
4
4
 
5
- from django.contrib.auth.models import User
6
- from django.urls import reverse, reverse_lazy
7
- from django.test import Client, TestCase
8
-
9
5
  from common.models import School, Student, UserProfile
10
6
  from common.tests.utils.classes import create_class_directly
11
7
  from common.tests.utils.teacher import signup_teacher_directly
8
+ from django.contrib.auth.models import User
9
+ from django.test import Client, TestCase
10
+ from django.urls import reverse, reverse_lazy
12
11
 
13
12
 
14
13
  class SecurityTestCase(TestCase):
@@ -20,7 +19,7 @@ class SecurityTestCase(TestCase):
20
19
  c = Client()
21
20
  assert c.login(username=email2, password=pass2)
22
21
  page = reverse(view_name, args=[access_code])
23
- self.assertNotEqual(c.get(page).status_code, 200)
22
+ assert not c.get(page).status_code == 200
24
23
 
25
24
  def _test_incorrect_teacher_no_info_leak(self, view_name):
26
25
  email1, _ = signup_teacher_directly()
@@ -33,10 +32,10 @@ class SecurityTestCase(TestCase):
33
32
  invalid_page = reverse(view_name, args=[access_code])
34
33
  invalid_login_code = c.get(invalid_page).status_code
35
34
 
36
- non_existant_page = reverse(view_name, args=["AAAAA"])
37
- non_existant_code = c.get(non_existant_page).status_code
35
+ non_existent_page = reverse(view_name, args=["AAAAA"])
36
+ non_existent_code = c.get(non_existent_page).status_code
38
37
 
39
- self.assertEqual(non_existant_code, invalid_login_code)
38
+ assert non_existent_code == invalid_login_code
40
39
 
41
40
  def test_reminder_cards_info_leak(self):
42
41
  """Check that it isn't leaked whether an access code exists."""
@@ -55,20 +54,11 @@ class SecurityTestCase(TestCase):
55
54
  stu = Student(user=profile)
56
55
  stu.save()
57
56
 
58
- self.assertEqual(
59
- c.get(reverse("teacher_edit_student", kwargs={"pk": "9999"})).status_code,
60
- c.get(reverse("teacher_edit_student", kwargs={"pk": stu.pk})).status_code,
57
+ assert (
58
+ c.get(reverse("teacher_edit_student", kwargs={"pk": "9999"})).status_code
59
+ == c.get(reverse("teacher_edit_student", kwargs={"pk": stu.pk})).status_code
61
60
  )
62
61
 
63
- def test_cannot_lookup_schools_if_not_logged_in(self):
64
- client = Client()
65
-
66
- url = reverse("organisation_fuzzy_lookup")
67
- data = {"fuzzy_name": ["A"]}
68
- response = client.get(url, data=data)
69
-
70
- self.assertEqual(403, response.status_code)
71
-
72
62
  def test_cannot_create_school_with_email_as_name(self):
73
63
  number_of_existing_schools = len(School.objects.all())
74
64
 
@@ -78,16 +68,11 @@ class SecurityTestCase(TestCase):
78
68
  client.login(username=email, password=password)
79
69
 
80
70
  url = reverse("onboarding-organisation")
81
- data = {
82
- "name": email,
83
- "postcode": "TEST",
84
- "country": "GB",
85
- "create_organisation": "",
86
- }
71
+ data = {"name": email, "postcode": "TEST", "country": "GB", "create_organisation": ""}
87
72
 
88
73
  client.post(url, data)
89
74
 
90
- self.assertEqual(number_of_existing_schools, len(School.objects.all()))
75
+ assert number_of_existing_schools == len(School.objects.all())
91
76
 
92
77
  def test_reminder_cards_wrong_teacher(self):
93
78
  """Try and view reminder cards without being the teacher for that class."""
@@ -97,7 +82,3 @@ class SecurityTestCase(TestCase):
97
82
  """Try and view a class page without being the teacher for that class."""
98
83
  self._test_incorrect_teacher_cannot_login("onboarding-class")
99
84
 
100
- def test_anonymous_cannot_access_teaching_materials(self):
101
- c = Client()
102
- page = reverse_lazy("materials")
103
- self.assertNotEqual(str(c.get(page).status_code)[0], 2)