codeforlife-portal 5.32.2__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 (393) 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.32.2.dist-info → codeforlife_portal-8.9.9.dist-info}/RECORD +341 -238
  92. {codeforlife_portal-5.32.2.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.32.2.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 +31 -0
  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 +10 -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 -73
  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 +138 -15
  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 +237 -164
  319. portal/views/admin.py +0 -332
  320. portal/views/api.py +82 -68
  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/__init__.py +0 -0
  338. portal/views/two_factor/core.py +28 -0
  339. portal/views/two_factor/form.py +7 -0
  340. portal/views/two_factor/profile.py +11 -0
  341. codeforlife_portal-5.32.2.dist-info/LICENSE.md +0 -577
  342. codeforlife_portal-5.32.2.dist-info/METADATA +0 -38
  343. deploy/permissions.py +0 -2
  344. example_project/manage.py +0 -10
  345. portal/autoconfig.py +0 -140
  346. portal/csp_config.py +0 -60
  347. portal/forms/add_game.py +0 -33
  348. portal/helpers/location.py +0 -121
  349. portal/static/portal/img/kurono_hero.jpg +0 -0
  350. portal/static/portal/img/kurono_landing_hero.png +0 -0
  351. portal/static/portal/img/kurono_logo.svg +0 -1
  352. portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
  353. portal/static/portal/img/kurono_logo_mark.svg +0 -1
  354. portal/static/portal/img/kurono_resources_hero.jpg +0 -0
  355. portal/static/portal/img/kurono_story.png +0 -0
  356. portal/static/portal/img/ocado-swirl.svg +0 -22
  357. portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
  358. portal/static/portal/img/thumbnail_educate_resources_and_progress_tracking.png +0 -0
  359. portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
  360. portal/static/portal/img/thumbnail_play_kurono.png +0 -0
  361. portal/static/portal/img/x_close_video.png +0 -0
  362. portal/static/portal/js/aimmoGame.js +0 -106
  363. portal/static/portal/js/deleteWorkspaces.js +0 -14
  364. portal/static/portal/js/fuzzySchoolLookup.js +0 -46
  365. portal/static/portal/js/lib/jquery-3.5.1.min.js +0 -2
  366. portal/static/portal/js/lib/jquery-ui-1.12.1.min.js +0 -13
  367. portal/static/portal/sass/partials/_videos.scss +0 -10
  368. portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
  369. portal/strings/student_aimmo_dashboard.py +0 -6
  370. portal/templates/portal/admin/aggregated_data.html +0 -35
  371. portal/templates/portal/admin/map.html +0 -70
  372. portal/templates/portal/mouseflow.html +0 -9
  373. portal/templates/portal/partials/aimmo_games_table.html +0 -83
  374. portal/templates/portal/partials/register_over_required_age_tickbox.html +0 -9
  375. portal/templates/portal/play/independent_student_dashboard.html +0 -64
  376. portal/templates/portal/play/student_aimmo_dashboard.html +0 -63
  377. portal/templates/portal/privacy_policy.html +0 -483
  378. portal/templates/portal/reset_password_email.html +0 -9
  379. portal/templates/portal/teach/invite.html +0 -25
  380. portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
  381. portal/templates/portal/teach/teacher_resources.html +0 -68
  382. portal/templatetags/character_list_tags.py +0 -16
  383. portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
  384. portal/tests/pageObjects/portal/student_password_reset_form_page.py +0 -23
  385. portal/tests/pageObjects/portal/teach/onboarding_revoke_request_page.py +0 -20
  386. portal/tests/pageObjects/portal/teacher_password_reset_form_page.py +0 -23
  387. portal/tests/test_aimmo_dashboards.py +0 -172
  388. portal/tests/test_location.py +0 -217
  389. portal/tests/utils/aimmo_games.py +0 -30
  390. portal/views/aimmo/dashboard.py +0 -119
  391. portal/views/privacy_policy.py +0 -9
  392. portal/views/teacher/teacher_resources.py +0 -42
  393. {portal/views/aimmo → cfl_common}/__init__.py +0 -0
@@ -1,41 +1,59 @@
1
1
  {% extends "two_factor/_base.html" %}
2
- {% load future i18n two_factor %}
2
+ {% load i18n %}
3
+ {% load two_factor_tags %}
3
4
 
4
5
  {% block content %}
5
- <h4>{% block title %}{% trans "Account Security" %}{% endblock %}</h4>
6
+ <h1>{% block title %}{% trans "Account Security" %}{% endblock %}</h1>
6
7
 
7
8
  {% if default_device %}
8
- {% if default_device_type == 'TOTPDevice' %}
9
- <p>{% trans "Tokens will be generated by your token generator." %}</p>
10
- {% elif default_device_type == 'PhoneDevice' %}
11
- <p>{% blocktrans with primary=default_device|device_action %}Primary method: {{ primary }}{% endblocktrans %}</p>
12
- {% elif default_device_type == 'RemoteYubikeyDevice' %}
13
- <p>{% blocktrans %}Tokens will be generated by your YubiKey.{% endblocktrans %}</p>
9
+ <p>{% blocktrans with primary=default_device|as_action %}Primary method: {{ primary }}{% endblocktrans %}</p>
10
+
11
+ {% if available_phone_methods %}
12
+ <h2>{% trans "Backup Phone Numbers" %}</h2>
13
+ <p>{% blocktrans trimmed %}If your primary method is not available, we are able to
14
+ send backup tokens to the phone numbers listed below.{% endblocktrans %}</p>
15
+ {% if backup_phones %}
16
+ <ul>
17
+ {% for phone in backup_phones %}
18
+ <li>
19
+ {{ phone|as_action }}
20
+ <form method="post" action="{% url 'two_factor:phone_delete' phone.id %}"
21
+ onsubmit="return confirm({% trans 'Are you sure?' %})">
22
+ {% csrf_token %}
23
+ <button class="btn btn-sm btn-warning"
24
+ type="submit">{% trans "Unregister" %}</button>
25
+ </form>
26
+ </li>
27
+ {% endfor %}
28
+ </ul>
29
+ {% endif %}
30
+ <p><a href="{% url 'two_factor:phone_create' %}"
31
+ class="btn btn-info">{% trans "Add Phone Number" %}</a></p>
14
32
  {% endif %}
15
33
 
16
- <h4>{% trans "Backup Tokens" %}</h4>
34
+ <h2>{% trans "Backup Tokens" %}</h2>
17
35
  <p>
18
- {% blocktrans %}If you don't have any device with you, you can access
36
+ {% blocktrans trimmed %}If you don't have any device with you, you can access
19
37
  your account using backup tokens.{% endblocktrans %}
20
- {% blocktrans count counter=backup_tokens %}
38
+ {% blocktrans trimmed count counter=backup_tokens %}
21
39
  You have only one backup token remaining.
22
40
  {% plural %}
23
41
  You have {{ counter }} backup tokens remaining.
24
42
  {% endblocktrans %}
25
43
  </p>
26
44
  <p><a href="{% url 'two_factor:backup_tokens' %}"
27
- class="button button--primary">{% trans "Show Codes" %}</a></p>
45
+ class="btn btn-info">{% trans "Show Codes" %}</a></p>
28
46
 
29
- <h4>{% trans "Disable Two-Factor Authentication" %}</h4>
30
- <p>{% blocktrans %}However we strongly discourage you to do so, you can
47
+ <h3>{% trans "Disable Two-Factor Authentication" %}</h3>
48
+ <p>{% blocktrans trimmed %}However we strongly discourage you to do so, you can
31
49
  also disable two-factor authentication for your account.{% endblocktrans %}</p>
32
- <p><a class="button button--primary" href="{% url 'two_factor:disable' %}">
50
+ <p><a class="btn btn-secondary" href="{% url 'two_factor:disable' %}">
33
51
  {% trans "Disable Two-Factor Authentication" %}</a></p>
34
52
  {% else %}
35
- <p>{% blocktrans %}Two-factor authentication is not enabled for your
53
+ <p>{% blocktrans trimmed %}Two-factor authentication is not enabled for your
36
54
  account. Enable two-factor authentication for enhanced account
37
55
  security.{% endblocktrans %}</p>
38
- <p><a href="{% url 'two_factor:setup' %}" class="button button--primary">
56
+ <p><a href="{% url 'two_factor:setup' %}" class="btn btn-primary">
39
57
  {% trans "Enable Two-Factor Authentication" %}</a>
40
58
  </p>
41
59
  {% endif %}
@@ -1,16 +1,9 @@
1
- from aimmo.templatetags.players_utils import get_user_playable_games
2
- from aimmo.worksheets import get_complete_worksheets, get_incomplete_worksheets
3
1
  from common import app_settings as common_app_settings
4
- from common.models import EmailVerification
5
- from common.permissions import logged_in_as_teacher
6
2
  from common.utils import using_two_factor
7
3
  from django import template
8
4
  from django.conf import settings
9
- from django.contrib.auth.models import User
10
- from django.core.exceptions import ObjectDoesNotExist
11
- from django.shortcuts import reverse
12
- from django.template.context import RequestContext
13
5
  from django.template.defaultfilters import stringfilter
6
+
14
7
  from portal import __version__, beta
15
8
 
16
9
  register = template.Library()
@@ -23,33 +16,25 @@ def emaildomain(email):
23
16
 
24
17
 
25
18
  @register.filter(name="has_2FA")
26
- def has_2FA(u):
27
- return using_two_factor(u)
19
+ def has_2FA(user):
20
+ return using_two_factor(user)
28
21
 
29
22
 
30
23
  @register.filter(name="is_logged_in")
31
- def is_logged_in(u):
24
+ def is_logged_in(user):
32
25
  return (
33
- u
34
- and u.is_authenticated
35
- and (not using_two_factor(u) or (hasattr(u, "is_verified") and u.is_verified()))
26
+ user
27
+ and user.is_authenticated
28
+ and (
29
+ not using_two_factor(user)
30
+ or (hasattr(user, "is_verified") and user.userprofile.is_verified)
31
+ )
36
32
  )
37
33
 
38
34
 
39
35
  @register.filter
40
- def is_verified(u: User) -> bool:
41
- try:
42
- verifications = EmailVerification.objects.filter(user=u)
43
- latest_verification = verifications.latest("user")
44
- except ObjectDoesNotExist:
45
- return False
46
-
47
- return latest_verification.verified
48
-
49
-
50
- @register.filter
51
- def is_developer(u):
52
- return not u.is_anonymous and u.userprofile.developer
36
+ def is_developer(user):
37
+ return not user.is_anonymous and user.userprofile.developer
53
38
 
54
39
 
55
40
  @register.filter
@@ -63,98 +48,91 @@ def has_beta_access(request):
63
48
  return beta.has_beta_access(request)
64
49
 
65
50
 
66
- @register.inclusion_tag("portal/partials/aimmo_games_table.html", takes_context=True)
67
- def games_table(context, base_url):
68
- playable_games = get_user_playable_games(context, base_url)
69
-
70
- playable_games["complete_worksheets"] = get_complete_worksheets()
71
- playable_games["incomplete_worksheets"] = get_incomplete_worksheets()
72
-
73
- return playable_games
74
-
75
-
76
51
  @register.filter(name="make_into_username")
77
- def make_into_username(u):
52
+ def make_into_username(user):
78
53
  username = ""
79
- if hasattr(u, "userprofile"):
80
- if hasattr(u.userprofile, "student"):
81
- username = u.first_name
82
- elif hasattr(u.userprofile, "teacher"):
83
- username = u.first_name + " " + u.last_name
54
+ if hasattr(user, "userprofile"):
55
+ if hasattr(user.userprofile, "student"):
56
+ username = user.first_name
57
+ elif hasattr(user.userprofile, "teacher"):
58
+ username = user.first_name + " " + user.last_name
84
59
 
85
60
  return username
86
61
 
87
62
 
88
63
  @register.filter(name="is_logged_in_as_teacher")
89
- def is_logged_in_as_teacher(u):
90
- return is_logged_in(u) and u.userprofile and hasattr(u.userprofile, "teacher")
64
+ def is_logged_in_as_teacher(user):
65
+ return (
66
+ is_logged_in(user)
67
+ and user.userprofile
68
+ and hasattr(user.userprofile, "teacher")
69
+ )
70
+
71
+
72
+ @register.filter(name="is_logged_in_as_admin_teacher")
73
+ def is_logged_in_as_admin_teacher(user):
74
+ return is_logged_in_as_teacher(user) and user.userprofile.teacher.is_admin
91
75
 
92
76
 
93
77
  @register.filter(name="is_logged_in_as_student")
94
- def is_logged_in_as_student(u):
78
+ def is_logged_in_as_student(user):
95
79
  return (
96
- is_logged_in(u)
97
- and u.userprofile
98
- and hasattr(u.userprofile, "student")
99
- and u.userprofile.student.class_field != None
80
+ is_logged_in(user)
81
+ and user.userprofile
82
+ and hasattr(user.userprofile, "student")
83
+ and user.userprofile.student.class_field is not None
100
84
  )
101
85
 
102
86
 
103
87
  @register.filter(name="is_independent_student")
104
- def is_independent_student(u):
88
+ def is_independent_student(user):
105
89
  return (
106
- is_logged_in(u)
107
- and u.userprofile
108
- and hasattr(u.userprofile, "student")
109
- and u.userprofile.student.is_independent()
90
+ is_logged_in(user)
91
+ and user.userprofile
92
+ and hasattr(user.userprofile, "student")
93
+ and user.userprofile.student.is_independent()
110
94
  )
111
95
 
112
96
 
113
97
  @register.filter(name="has_teacher_finished_onboarding")
114
- def has_teacher_finished_onboarding(u):
115
- teacher = u.userprofile.teacher
116
- classes = teacher.class_teacher.all()
117
- return (
118
- is_logged_in_as_teacher(u)
119
- and teacher.has_school()
120
- and classes
121
- and (classes.count() > 1 or classes[0].has_students())
122
- )
98
+ def has_teacher_finished_onboarding(user):
99
+ teacher = user.userprofile.teacher
100
+ return is_logged_in_as_teacher(user) and teacher.has_school()
123
101
 
124
102
 
125
103
  @register.filter(name="is_logged_in_as_school_user")
126
- def is_logged_in_as_school_user(u):
104
+ def is_logged_in_as_school_user(user):
127
105
  return (
128
- is_logged_in(u)
129
- and u.userprofile
106
+ is_logged_in(user)
107
+ and user.userprofile
130
108
  and (
131
109
  (
132
- hasattr(u.userprofile, "student")
133
- and u.userprofile.student.class_field != None
110
+ hasattr(user.userprofile, "student")
111
+ and user.userprofile.student.class_field is not None
134
112
  )
135
- or hasattr(u.userprofile, "teacher")
113
+ or hasattr(user.userprofile, "teacher")
136
114
  )
137
115
  )
138
116
 
139
117
 
140
118
  @register.filter(name="get_user_status")
141
- def get_user_status(u):
142
- if is_logged_in_as_school_user(u):
143
- if is_logged_in_as_teacher(u):
119
+ def get_user_status(user):
120
+ if is_logged_in_as_school_user(user):
121
+ if is_logged_in_as_teacher(user):
144
122
  return "TEACHER"
145
123
  else:
146
124
  return "SCHOOL_STUDENT"
147
- elif is_logged_in(u):
125
+ elif is_logged_in(user):
148
126
  return "INDEPENDENT_STUDENT"
149
127
  else:
150
128
  return "UNTRACKED"
151
129
 
152
130
 
153
131
  @register.filter(name="make_title_caps")
154
- def make_title_caps(s):
155
- if len(s) > 0:
156
- s = s[0].upper() + s[1:]
157
- return s
132
+ def make_title_caps(string):
133
+ if len(string) > 0:
134
+ string = string[0].upper() + string[1:]
135
+ return string
158
136
 
159
137
 
160
138
  @register.filter(name="cloud_storage")
@@ -168,9 +146,6 @@ def get_project_version():
168
146
  return __version__
169
147
 
170
148
 
171
- @register.simple_tag(takes_context=True)
172
- def url_for_aimmo_dashboard(context: RequestContext):
173
- if logged_in_as_teacher(context.request.user):
174
- return reverse("teacher_aimmo_dashboard")
175
- else:
176
- return reverse("student_aimmo_dashboard")
149
+ @register.filter
150
+ def get_dict_item(dictionary, key):
151
+ return dictionary[key]
@@ -11,9 +11,5 @@ def card_list(context):
11
11
  - image: the path to the card's image (top-half)
12
12
  - title: the heading of the card
13
13
  - description (optional): the text paragraph of the card
14
- - thumbnail_text (optional): text to be shown as the thumbnail
15
- - thumbnail_image (optional): the path to the image to be shown as the thumbnail
16
- - button_text (optional): the text on the card's button
17
- - button_link (optional): the link that the button redirects to
18
14
  """
19
15
  return context["CARD_LIST"]
portal/tests/base_test.py CHANGED
@@ -1,12 +1,10 @@
1
1
  import socket
2
2
  import time
3
3
 
4
+ from django.contrib.sites.models import Site
4
5
  from django.urls import reverse
5
6
 
6
7
  from deploy import captcha
7
-
8
- # Uncomment to use FireFox
9
- # master_browser = webdriver.Firefox()
10
8
  from portal.tests.pageObjects.portal.home_page import HomePage
11
9
  from .selenium_test_case import SeleniumTestCase
12
10
 
@@ -41,3 +39,16 @@ class BaseTest(SeleniumTestCase):
41
39
  else:
42
40
  break
43
41
  attempts += 1
42
+
43
+ def __call__(self, result=None):
44
+ self._set_site_to_local_domain()
45
+ return super().__call__(result)
46
+
47
+ def _set_site_to_local_domain(self):
48
+ """
49
+ Sets the Site Django object to the local domain (locally, localhost:8000).
50
+ Needed to generate valid registration and password reset links in tests.
51
+ """
52
+ current_site = Site.objects.get_current()
53
+ current_site.domain = f"{self.server_thread.host}:{self.server_thread.port}"
54
+ current_site.save()
portal/tests/conftest.py CHANGED
@@ -1,8 +1,6 @@
1
1
  from collections import namedtuple
2
- from unittest.mock import MagicMock
3
2
 
4
3
  import pytest
5
- from aimmo.models import Game
6
4
  from common.models import Class
7
5
  from common.tests.utils.classes import create_class_directly
8
6
  from common.tests.utils.organisation import create_organisation_directly
@@ -12,8 +10,6 @@ from common.tests.utils.student import (
12
10
  )
13
11
  from common.tests.utils.teacher import signup_teacher_directly
14
12
 
15
- from .utils.aimmo_games import create_aimmo_game_directly
16
-
17
13
  SchoolStudent = namedtuple("student", ["username", "password"])
18
14
  IndependentStudent = namedtuple("independent_student", ["username", "password"])
19
15
  TeacherLoginDetails = namedtuple("teacher", ["email", "password"])
@@ -41,14 +37,3 @@ def student1(db, class1) -> SchoolStudent:
41
37
  def independent_student1(db) -> IndependentStudent:
42
38
  username, password, _ = create_independent_student_directly()
43
39
  return IndependentStudent(username, password)
44
-
45
-
46
- @pytest.fixture
47
- def aimmo_game1(db, class1) -> Game:
48
- return create_aimmo_game_directly(klass=class1, worksheet_id=1)
49
-
50
-
51
- @pytest.fixture(autouse=True)
52
- def mock_game_manager(monkeypatch):
53
- """Mock GameManager for all tests."""
54
- monkeypatch.setattr("aimmo.game_creator.GameManager", MagicMock())
@@ -4,9 +4,7 @@ import pytest
4
4
  @pytest.mark.django_db
5
5
  def test_portaladmin_has_teacher_profile(migrator):
6
6
  migrator.apply_initial_migration(("portal", "0060_delete_guardian"))
7
- new_state = migrator.apply_tested_migration(
8
- ("portal", "0061_make_portaladmin_teacher")
9
- )
7
+ new_state = migrator.apply_tested_migration(("portal", "0061_make_portaladmin_teacher"))
10
8
 
11
9
  User = new_state.apps.get_model("auth", "User")
12
10
  UserProfile = new_state.apps.get_model("common", "UserProfile")
@@ -34,9 +32,7 @@ def test_portaladmin_has_teacher_profile(migrator):
34
32
  assert portaladmin_class.teacher == portaladmin_teacher
35
33
 
36
34
  portaladmin_student_user = User.objects.get(username="portaladmin student")
37
- portaladmin_student_userprofile = UserProfile.objects.get(
38
- user=portaladmin_student_user
39
- )
35
+ portaladmin_student_userprofile = UserProfile.objects.get(user=portaladmin_student_user)
40
36
  portaladmin_student = Student.objects.get(user=portaladmin_student_userprofile)
41
37
 
42
38
  assert portaladmin_student.class_field == portaladmin_class
@@ -3,17 +3,11 @@ import pytest
3
3
 
4
4
  @pytest.mark.django_db
5
5
  def test_preview_user_field_added(migrator):
6
- migrator.apply_initial_migration(
7
- ("portal", "0054_pending_join_request_can_be_blank")
8
- )
6
+ migrator.apply_initial_migration(("portal", "0054_pending_join_request_can_be_blank"))
9
7
  new_state = migrator.apply_tested_migration(("portal", "0055_add_preview_user"))
10
8
 
11
9
  userprofile_model = new_state.apps.get_model("portal", "UserProfile")
12
- assert userprofile_model._meta.get_field(
13
- "preview_user"
14
- ).get_internal_type(), "BooleanField"
10
+ assert userprofile_model._meta.get_field("preview_user").get_internal_type(), "BooleanField"
15
11
 
16
12
  school_model = new_state.apps.get_model("portal", "School")
17
- assert school_model._meta.get_field(
18
- "eligible_for_testing"
19
- ).get_internal_type(), "BooleanField"
13
+ assert school_model._meta.get_field("eligible_for_testing").get_internal_type(), "BooleanField"
@@ -3,9 +3,7 @@ import pytest
3
3
 
4
4
  @pytest.mark.django_db
5
5
  def test_guardian_model_removed(migrator):
6
- migrator.apply_initial_migration(
7
- ("portal", "0059_move_email_verifications_to_common")
8
- )
6
+ migrator.apply_initial_migration(("portal", "0059_move_email_verifications_to_common"))
9
7
  new_state = migrator.apply_tested_migration(("portal", "0060_delete_guardian"))
10
8
 
11
9
  model_names = [model._meta.db_table for model in new_state.apps.get_models()]
@@ -4,9 +4,7 @@ import pytest
4
4
  @pytest.mark.django_db
5
5
  def test_models_moved_to_common(migrator):
6
6
  migrator.apply_initial_migration(("portal", "0057_delete_frontpagenews"))
7
- new_state = migrator.apply_tested_migration(
8
- ("portal", "0058_move_to_common_models")
9
- )
7
+ new_state = migrator.apply_tested_migration(("portal", "0058_move_to_common_models"))
10
8
 
11
9
  model_names = [model._meta.db_table for model in new_state.apps.get_models()]
12
10
 
@@ -20,9 +18,7 @@ def test_models_moved_to_common(migrator):
20
18
  @pytest.mark.django_db
21
19
  def test_emailverification_moved_to_common(migrator):
22
20
  migrator.apply_initial_migration(("portal", "0058_move_to_common_models"))
23
- new_state = migrator.apply_tested_migration(
24
- ("portal", "0059_move_email_verifications_to_common")
25
- )
21
+ new_state = migrator.apply_tested_migration(("portal", "0059_move_email_verifications_to_common"))
26
22
 
27
23
  model_names = [model._meta.db_table for model in new_state.apps.get_models()]
28
24
 
@@ -18,9 +18,7 @@ def test_verify_portaladmin(migrator):
18
18
  @pytest.mark.django_db
19
19
  def test_verify_portaladmin_rollback(migrator):
20
20
  migrator.apply_initial_migration(("portal", "0062_verify_portaladmin"))
21
- new_state = migrator.apply_tested_migration(
22
- ("portal", "0061_make_portaladmin_teacher")
23
- )
21
+ new_state = migrator.apply_tested_migration(("portal", "0061_make_portaladmin_teacher"))
24
22
 
25
23
  User = new_state.apps.get_model("auth", "User")
26
24
  EmailVerification = new_state.apps.get_model("common", "EmailVerification")
@@ -8,24 +8,3 @@ class AdminBasePage(BasePage):
8
8
  def __init__(self, browser, live_server_url):
9
9
  super(AdminBasePage, self).__init__(browser)
10
10
  self.live_server_url = live_server_url
11
-
12
- def go_to_admin_data_page_failure(self):
13
- url = self.live_server_url + reverse("aggregated_data")
14
- self.browser.get(url)
15
-
16
- return ForbiddenPage(self.browser)
17
-
18
- def go_to_admin_map_page_failure(self):
19
- self._go_to_admin_map_page()
20
- return ForbiddenPage(self.browser)
21
-
22
- def go_to_admin_map_page(self):
23
- self._go_to_admin_map_page()
24
-
25
- from portal.tests.pageObjects.portal.admin.admin_map_page import AdminMapPage
26
-
27
- return AdminMapPage(self.browser, self.live_server_url)
28
-
29
- def _go_to_admin_map_page(self):
30
- url = self.live_server_url + reverse("map")
31
- self.browser.get(url)
@@ -1,15 +1,15 @@
1
1
  from __future__ import absolute_import
2
2
 
3
- from builtins import object
4
3
  import time
4
+ from builtins import object
5
5
 
6
6
  from selenium.common.exceptions import TimeoutException
7
+ from selenium.webdriver.common.action_chains import ActionChains
7
8
  from selenium.webdriver.common.by import By
8
9
  from selenium.webdriver.support import expected_conditions as EC
9
10
  from selenium.webdriver.support.ui import WebDriverWait
10
- from selenium.webdriver.common.action_chains import ActionChains
11
11
 
12
- FADE_TIME = 0.3
12
+ FADE_TIME = 0.5
13
13
 
14
14
 
15
15
  class BasePage(object):
@@ -40,7 +40,9 @@ class BasePage(object):
40
40
  self.wait(EC.presence_of_element_located(locator), wait_seconds)
41
41
 
42
42
  def wait_for_absence(self, locator, wait_seconds=DEFAULT_WAIT_SECONDS):
43
- self.wait_until_not(EC.presence_of_element_located(locator), wait_seconds)
43
+ self.wait_until_not(
44
+ EC.presence_of_element_located(locator), wait_seconds
45
+ )
44
46
 
45
47
  def wait(self, method, wait_seconds=DEFAULT_WAIT_SECONDS):
46
48
  WebDriverWait(self.browser, wait_seconds).until(method)
@@ -78,33 +80,21 @@ class BasePage(object):
78
80
  return self.element_exists_by_id(pageName)
79
81
 
80
82
  def hover_over_resources_dropdown(self):
81
- resources_dropdown = self.browser.find_element_by_id(
82
- "teaching_resources_button"
83
+ resources_dropdown = self.browser.find_element(
84
+ By.ID, "teaching_resources_button"
83
85
  )
84
86
  hover = ActionChains(self.browser).move_to_element(resources_dropdown)
85
87
  hover.perform()
86
88
 
87
89
  def go_to_rapid_router_resources_page(self):
88
90
  self.hover_over_resources_dropdown()
89
- self.browser.find_element_by_id("rapid_router_resources_button").click()
90
- from .resources_page import ResourcesPage
91
-
92
- return ResourcesPage(self.browser)
93
-
94
- def go_to_kurono_resources_page(self):
95
- self.hover_over_resources_dropdown()
96
- self.browser.find_element_by_id("kurono_resources_button").click()
91
+ self.browser.find_element(
92
+ By.ID, "rapid_router_resources_button"
93
+ ).click()
97
94
  from .resources_page import ResourcesPage
98
95
 
99
96
  return ResourcesPage(self.browser)
100
97
 
101
- def go_to_kurono_teacher_dashboard_page(self):
102
- self.browser.find_element_by_id("games_button").click()
103
- self.browser.find_element_by_id("teacher_kurono_dashboard_button").click()
104
- from .kurono_teacher_dashboard_page import KuronoTeacherDashboardPage
105
-
106
- return KuronoTeacherDashboardPage(self.browser)
107
-
108
98
  def is_on_admin_login_page(self):
109
99
  return self.on_correct_page("administration_login")
110
100
 
@@ -119,22 +109,22 @@ class BasePage(object):
119
109
 
120
110
  def was_form_invalid(self, formID, error):
121
111
  errors = (
122
- self.browser.find_element_by_id(formID)
123
- .find_element_by_class_name("errorlist")
112
+ self.browser.find_element(By.ID, formID)
113
+ .find_element(By.CLASS_NAME, "errorlist")
124
114
  .text
125
115
  )
126
116
  return error in errors
127
117
 
128
118
  def is_dialog_showing(self):
129
119
  time.sleep(FADE_TIME)
130
- return self.browser.find_element_by_id("popup").is_displayed()
120
+ return self.browser.find_element(By.ID, "popup").is_displayed()
131
121
 
132
122
  def confirm_dialog(self):
133
- self.browser.find_element_by_id("confirm_button").click()
123
+ self.browser.find_element(By.ID, "confirm_button").click()
134
124
  time.sleep(FADE_TIME)
135
125
  return self
136
126
 
137
127
  def cancel_dialog(self):
138
- self.browser.find_element_by_id("cancel_button").click()
128
+ self.browser.find_element(By.ID, "cancel_button").click()
139
129
  time.sleep(FADE_TIME)
140
130
  return self
@@ -1,5 +1,7 @@
1
1
  from __future__ import absolute_import
2
2
 
3
+ from selenium.webdriver.common.by import By
4
+
3
5
  from . import home_page
4
6
  from .base_page import BasePage
5
7
 
@@ -7,9 +9,8 @@ from .base_page import BasePage
7
9
  class EmailVerificationNeededPage(BasePage):
8
10
  def __init__(self, browser):
9
11
  super(EmailVerificationNeededPage, self).__init__(browser)
10
-
11
12
  assert self.on_correct_page("emailVerificationNeeded_page")
12
13
 
13
14
  def return_to_home_page(self):
14
- self.browser.find_element_by_id("home_button").click()
15
+ self.browser.find_element(By.ID, "home_button").click()
15
16
  return home_page.HomePage(self.browser)