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,5 +1,5 @@
1
1
  {% extends 'portal/teach/base_registering.html' %}
2
- {% load staticfiles %}
2
+ {% load static %}
3
3
  {% load app_tags %}
4
4
 
5
5
  {% block content %}
@@ -1,52 +1,10 @@
1
1
  {% extends "portal/teach/base_registering.html" %}
2
- {% load staticfiles %}
2
+ {% load static %}
3
3
  {% load app_tags %}
4
4
 
5
5
  {% block content %}
6
- <script type="text/javascript" src="{% static 'portal/js/fuzzySchoolLookup.js' %}"></script>
7
- <script>
8
- var FUZZY_NAME_FIELD_ID = "{{ join_form.fuzzy_name.auto_id }}";
9
- var CHOSEN_ORG_FIELD_ID = "{{ join_form.chosen_org.auto_id }}";
10
- var FUZZY_ORG_LOOKUP_URL = "{% url 'organisation_fuzzy_lookup' %}";
11
- </script>
12
-
13
6
  <div id="onboarding_organisation_page"></div>
14
7
 
15
- {% if teacher.pending_join_request %}
16
- <div id="onboarding_revoke_request_page"></div>
17
-
18
- <div class="background container">
19
- <div class="row">
20
- <div class="form col-sm-12">
21
- <h4>Join an existing school or club</h4>
22
-
23
- <p class="text-danger">
24
- <b>
25
- You have a pending request to join {{ teacher.pending_join_request.name }}, {{ teacher.pending_join_request.postcode }}.<br>
26
- Once the administrator of your school or club has approved your request, you will be able to continue.
27
- </b>
28
- </p>
29
-
30
- <p>
31
- Please note: You may only have one request to join a school or club at a time. If you wish to join
32
- another school or club, you must withdraw your pending request first.
33
- </p>
34
-
35
- <form id="revoke_form" method="post" class="p-0">
36
-
37
- {% csrf_token %}
38
-
39
- <div class="section group">
40
- <button class="button button--primary" type="submit"
41
- name="revoke_join_request">Withdraw request
42
- </button>
43
- </div>
44
-
45
- </form>
46
- </div>
47
- </div>
48
- </div>
49
- {% else %}
50
8
  {% if teacher.school %}
51
9
  <div class="background background--primary">
52
10
  <div class="form col-sm-8 col-center">
@@ -60,28 +18,7 @@
60
18
  <div class="background container">
61
19
  <div class="row">
62
20
  <div class="form col-sm-12">
63
- <div id="create-header">
64
- <div class="d-flex justify-content-between align-items-end">
65
- <h4>Create a school or club</h4>
66
- <a id="join-button" class="button button--secondary button--secondary--dark" href="#join" aria-controls="join" role="tab" data-toggle="tab">
67
- <div class="d-flex align-items-center">
68
- <div>Join an existing school</div>
69
- <span class="iconify ml-3" data-icon="mdi:arrow-right"></span>
70
- </div>
71
- </a>
72
- </div>
73
- </div>
74
- <div id="join-header" class="hidden">
75
- <div class="d-flex justify-content-between align-items-end">
76
- <h4>Join an existing school or club</h4>
77
- <a id="create-button" class="button button--secondary button--secondary--dark" href="#create" aria-controls="create" role="tab" data-toggle="tab">
78
- <div class="d-flex align-items-center">
79
- <span class="iconify mr-3" data-icon="mdi:arrow-left"></span>
80
- <div>Create a school or club</div>
81
- </div>
82
- </a>
83
- </div>
84
- </div>
21
+ <h4>Create a school or club</h4>
85
22
 
86
23
  <p class="mb-3">Progress &lt; 1 of 4 &gt;</p>
87
24
  <div class="progress">
@@ -89,91 +26,41 @@
89
26
  <span class="sr-only">25% Complete</span>
90
27
  </div>
91
28
  </div>
29
+ <p>As the first person from your school or club to register for Code for Life, by default, you become the
30
+ organisation's administrator.</p>
92
31
 
93
- <div class="tab-content">
94
- <div role="tabpanel" class="tab-pane active" id="create">
95
- <p>As the first person from your school or club to register for Code for Life, by default, you become the organisation's administrator.</p>
32
+ <form id="form-create-organisation" method="post">
96
33
 
97
- <form id="form-create-organisation" method="post">
98
-
99
- {% csrf_token %}
100
-
101
- {{ create_form.non_field_errors }}
34
+ {% csrf_token %}
102
35
 
103
- {% for field in create_form %}
104
- <div class="row form--row">
105
- <div class="form--row__input col-sm-6 col-xs-12">
106
- <div class="input--icon">
107
- {{ field }}
108
- {% if not field == create_form.country %}
109
- <span class="iconify" data-icon="mdi:domain"></span>
110
- {% endif %}
111
- </div>
112
- <small>{{ field.help_text }}</small>
113
- {{ field.errors }}
114
- </div>
115
- </div>
116
- {% endfor %}
36
+ {{ create_form.non_field_errors }}
117
37
 
118
- <div class="section group">
119
- <button type="submit" class="button button--primary" name="create_organisation">Create school or club</button>
38
+ {% for field in create_form %}
39
+ <div id="form-row-{{ field.name }}" class="row form--row">
40
+ <div class="form--row__input col-sm-6 col-xs-12">
41
+ <div class="input--icon">
42
+ {{ field }}
43
+ {% if not field == create_form.country and not field == create_form.county %}
44
+ <span class="iconify" data-icon="mdi:domain"></span>
45
+ {% endif %}
120
46
  </div>
121
-
122
- </form>
47
+ <small>{{ field.help_text }}</small>
48
+ {{ field.errors }}
49
+ </div>
123
50
  </div>
51
+ {% endfor %}
124
52
 
125
- <div role="tabpanel" class="tab-pane" id="join">
126
- <p>You can search for your school or club by name and/or postcode below. A request will be sent to the school or club administrator for processing.</p>
127
- <form id="form-join-organisation" method="post">
128
-
129
- {% csrf_token %}
130
-
131
- {{ join_form.non_field_errors }}
132
-
133
- <div class="row form--row">
134
- <div class="form--row__input col-md-6 col-sm-9 col-xs-12">
135
- <div class="input--icon">
136
- {{ join_form.fuzzy_name }}
137
- <span class="iconify" data-icon="mdi:magnify"></span>
138
- </div>
139
- <small>{{ join_form.fuzzy_name.help_text }}</small>
140
- {{ join_form.fuzzy_name.errors }}
141
- </div>
142
- </div>
143
- <div class="row form--row">
144
- <div class="form--row__input col-md-6 col-sm-9 col-xs-12">
145
- <div class="input--icon">
146
- {{ join_form.chosen_org }}
147
- </div>
148
- <small>{{ join_form.chosen_org.help_text }}</small>
149
- {{ join_form.chosen_org.errors }}
150
- </div>
151
- </div>
152
-
153
- <div class="section group">
154
- <button type="submit" class="button button--primary" name="join_organisation">Join school or club</button>
155
- </div>
156
-
157
- </form>
53
+ <div class="section group">
54
+ <button type="submit" class="button button--primary" name="create_organisation" id="create_organisation_button">Create school or club</button>
158
55
  </div>
159
- </div>
56
+
57
+ </form>
160
58
  </div>
161
59
  </div>
162
60
  </div>
163
-
164
- <script>
165
- $('#join-button').on('show.bs.tab', function() {
166
- // hide create header and show join header
167
- $('#create-header').addClass('hidden')
168
- $('#join-header').removeClass('hidden')
169
- })
170
- $('#create-button').on('show.bs.tab', function() {
171
- // hide join header and show create header
172
- $('#join-header').addClass('hidden')
173
- $('#create-header').removeClass('hidden')
174
- })
175
- </script>
176
- {% endif %}
177
61
  {% endif %}
178
62
 
63
+ <script type="text/javascript"
64
+ src="{% static 'portal/js/school.js' %}"></script>
65
+
179
66
  {% endblock content %}
@@ -1,5 +1,5 @@
1
1
  {% extends 'portal/teach/base_registering.html' %}
2
- {% load staticfiles %}
2
+ {% load static %}
3
3
  {% load app_tags %}
4
4
 
5
5
  {% block content %}
@@ -8,77 +8,95 @@
8
8
  {% block content %}
9
9
  <div id="dismiss_students_page"></div>
10
10
 
11
- <section class="background container">
12
- <h4>Release student from class {{ class.name }} ({{ class.access_code }})</h4><br>
13
- </section>
11
+ <div class="background container">
12
+ <section>
13
+ <h4>Release student from class {{ class.name }} ({{ class.access_code }})</h4>
14
+ </section>
15
+ <p><a href="{% url 'view_class' class.access_code %}" class="button--menu button--menu--enabled">< Back to Edit class</a></p>
16
+ <p>Convert students into independent students.</p>
17
+ <h5>Students to release from school</h5>
14
18
 
15
- <div class="background">
16
- <div class="container">
17
- <p><a href="{% url 'view_class' class.access_code %}" class="button--menu button--menu--enabled">&lt; Back to Edit class</a></p>
18
- <p>Convert students into independent students.</p>
19
- <h4>Students to release from school</h4>
19
+ <p>You are about to remove students from your class and set them up as independent students. Neither you nor
20
+ your school will be able to manage them once you have submitted this request.</p>
20
21
 
21
- <p>You are about to remove students from your class and set them up as independent students. Neither you nor your school will
22
- be able to manage them once you have submitted this request.</p>
22
+ <p>Email addresses are required for independent student accounts. If a student is too young to own an email
23
+ address, a parent or guardian's email address will be required.</p>
23
24
 
24
- <p>You may want to change the username for these students to something more memorable. The students will then log in with
25
- these new usernames via the <a href="{% url 'independent_student_login' %}" target="_blank">independent student login</a>. Their passwords will stay the same.
26
- Independent students do not need to provide a class access code.</p>
25
+ <p>The email address will have to be validated through a verification email before the student can log in.
26
+ The email has to be unique and not used for other accounts in Code for Life.
27
+ <b>Make sure you type the correct email, as otherwise we may not be able to recover the account.</b>
28
+ </p>
27
29
 
28
- <p>Please also set and confirm email addresses for the students. Email addresses are required for independent student accounts.
29
- If a student is too young to own an email address, a parent or guardian's email address will be required. These email addresses will
30
- have to be validated through a verification email before the student can log in. More than one student can be registered to the same email address.</p>
30
+ <p>The students will then log in with their email via the
31
+ <a href="{% url 'independent_student_login' %}" target="_blank">independent student login</a>. Their passwords
32
+ will stay the same. Independent students do not need to provide a class access code.</p>
31
33
 
32
- <form method="POST">
34
+ <form method="POST">
33
35
 
34
- {% csrf_token %}
36
+ {% csrf_token %}
35
37
 
36
- {{ formset.management_form }}
37
- {{ formset.non_form_errors }}
38
+ {{ formset.management_form }}
39
+ {{ formset.non_form_errors }}
38
40
 
39
- {% for form in formset %}
40
- <div class="background">
41
- <div class="row form--row">
42
- <div class="form--row__input col-sm-6">
43
- <div class="input--icon">
44
- {{ form.orig_name }}
45
- </div>
46
- <p><small>{{ form.orig_name.help_text }}</small></p>
41
+ {% for form in formset %}
42
+ <div class="background">
43
+ <div class="row form--row">
44
+ <div class="form--row__input col-sm-6">
45
+ <div class="input--icon">
46
+ {{ form.orig_name }}
47
47
  </div>
48
- <div class="col-sm-6">
49
- <div class="input--icon">
50
- {{ form.name }} <span class="iconify" data-icon="mdi:account-outline"></span>
51
- </div>
52
- <p><small>{{ form.name.help_text }}</small></p>
53
- {{ form.name.errors }}
48
+ <p><small>{{ form.orig_name.help_text }}</small></p>
49
+ </div>
50
+ <div class="col-sm-6">
51
+ <div class="input--icon">
52
+ {{ form.name }} <span class="iconify" data-icon="mdi:account-outline"></span>
54
53
  </div>
54
+ <p><small>{{ form.name.help_text }}</small></p>
55
+ </div>
56
+ </div>
57
+ <div class="row form--row">
58
+ <div class="col-sm-6">
59
+ {{ form.orig_name.errors }}
55
60
  </div>
56
- <div class="row form--row">
57
- <div class="col-sm-6">
58
- <div class="input--icon">
59
- {{ form.email }} <span class="iconify" data-icon="mdi:email-outline"></span>
60
- </div>
61
- <p><small>{{ form.email.help_text }}</small></p>
62
- {{ form.email.errors }}
61
+ <div class="col-sm-6">
62
+ {{ form.name.errors }}
63
+ </div>
64
+ </div>
65
+ <div class="row form--row">
66
+ <div class="col-sm-6">
67
+ <div class="input--icon mt-3">
68
+ {{ form.email }} <span class="iconify" data-icon="mdi:email-outline"></span>
63
69
  </div>
64
- <div class="col-sm-6">
65
- <div class="input--icon">
66
- {{ form.confirm_email }} <span class="iconify" data-icon="mdi:email-outline"></span>
67
- </div>
68
- <p><small>{{ form.confirm_email.help_text }}</small></p>
69
- {{ form.email.confirm_errors }}
70
+ <p><small>{{ form.email.help_text }}</small></p>
71
+ </div>
72
+ <div class="col-sm-6">
73
+ <div class="input--icon mt-3">
74
+ {{ form.confirm_email }} <span class="iconify" data-icon="mdi:email-outline"></span>
70
75
  </div>
76
+ <p><small>{{ form.confirm_email.help_text }}</small></p>
71
77
  </div>
72
78
  </div>
73
- {% endfor %}
74
-
75
- <div class="button-group">
76
- <a id="cancel_button" class="button button--secondary button--secondary--dark" href="{% url 'view_class' class.access_code %}">Cancel</a>
77
- <button id="dismiss_button" type="submit" name="submit_dismiss" class="button button--primary button--primary--danger button--icon">Remove student <span class="iconify" data-icon="ic:outline-person-remove"></span>
78
- </button>
79
+ <div class="row form--row">
80
+ <div class="col-sm-6">
81
+ {{ form.email.errors }}
82
+ </div>
83
+ <div class="col-sm-6">
84
+ {{ form.confirm_email.errors }}
85
+ </div>
79
86
  </div>
80
- </form>
81
- </div>
87
+ {{ form.non_field_errors }}
88
+ </div>
89
+ {% endfor %}
90
+
91
+ <div class="button-group">
92
+ <a id="cancel_button" class="button button--secondary button--secondary--dark"
93
+ href="{% url 'view_class' class.access_code %}">Cancel</a>
94
+ <button id="dismiss_button" type="submit" name="submit_dismiss"
95
+ class="button button--primary button--primary--danger button--icon">Remove student
96
+ <span class="iconify" data-icon="ic:outline-person-remove"></span>
97
+ </button>
98
+ </div>
99
+ </form>
82
100
  </div>
83
101
 
84
102
  {% endblock %}
@@ -1,24 +1,48 @@
1
1
  {% extends 'portal/base.html' %}
2
+ {% load static %}
3
+ {% load app_tags %}
2
4
 
3
5
  {% block subNav %}
4
6
  {% include "portal/partials/teacher_non_dashboard_subnav.html" %}
5
7
  {% endblock subNav %}
6
8
 
9
+ {% block scripts %}
10
+ {{ block.super }}
11
+ <script type="text/javascript" src="{% static 'portal/js/levelControl.js' %}"></script>
12
+ <script>
13
+ // Uncheck the checkboxes that correspond to the already-locked levels
14
+ $(document).ready(function(){
15
+ const lockedLevelsIds = {{ locked_levels }};
16
+ const lockedWorksheetIds = {{ locked_worksheet_ids }};
17
+
18
+ lockedLevelsIds.forEach(function(lockedLevelId) {
19
+ const selector = `[value="level:${lockedLevelId}"]`;
20
+ $(selector).click();
21
+ })
22
+ lockedWorksheetIds.forEach(function(lockedWorksheetId) {
23
+ const selector = `[value="worksheet:${lockedWorksheetId}"]`;
24
+ $(selector).click();
25
+ })
26
+ })
27
+ </script>
28
+ {% endblock scripts %}
29
+
7
30
  {% block content %}
8
31
  <div id="teach_edit_class_page"></div>
9
32
 
10
- <div class="background">
33
+ <div class="background container">
34
+ <section>
35
+ <h4>Additional settings for class {{ class.name }} ({{ class.access_code }})</h4>
36
+ </section>
37
+ <p>
38
+ <a id="return_to_class_button" href="{% url 'view_class' class.access_code %}" class="button--menu button--menu--enabled">&lt; Back to Edit Class</a>
39
+ </p>
40
+ <p>You may change the name of the class, or change permissions to allow external requests from independent
41
+ students to join this class. You may also transfer the class to another teacher, or change permissions to
42
+ allow pupils to see their classmates' progress.</p>
43
+ </div>
44
+ <div class="background background--primary">
11
45
  <div class="container">
12
- <section>
13
- <h4>Additional settings for class {{ class.name }} ({{ class.access_code }})</h4>
14
- </section>
15
- <p>
16
- <a id="return_to_class_button" href="{% url 'view_class' class.access_code %}" class="button--menu button--menu--enabled">&lt; Back to Edit Class</a>
17
- </p>
18
- <p>You may change the name of the class, or change permissions to allow external requests from independent
19
- students to join this class. You may also transfer the class to another teacher, or change permissions to
20
- allow pupils to see their classmates' progress.</p>
21
-
22
46
  <form method="post" class="pb-3">
23
47
  {% csrf_token %}
24
48
 
@@ -69,6 +93,139 @@
69
93
  </div>
70
94
  </div>
71
95
 
96
+ <div class="background container">
97
+ <h5>Levels access settings</h5>
98
+ <p>You may control access to levels here by selecting what you wish to display to the students.</p>
99
+
100
+ <form method="post">
101
+ {% csrf_token %}
102
+
103
+ {{ level_control_form.non_field_errors }}
104
+
105
+ <div id="episodes">
106
+ <div class="panel-intro d-flex align-items-center justify-content-between">
107
+ <h6>Rapid Router levels</h6>
108
+ <label class="pr-5 mb-0 mr-5">
109
+ <input type="checkbox" id="select-all-blockly-levels">
110
+ </label>
111
+ </div>
112
+ {% for episode in blockly_episodes %}
113
+ {% with episode.id|stringformat:"s" as episode_id %}
114
+ {% with "episode"|add:episode_id as episode_index %}
115
+ <div class="panel">
116
+ <div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
117
+ <div class="d-flex align-items-center justify-content-end" data-toggle="collapse"
118
+ data-target="#collapse-{{episode.id}}" aria-expanded="false"
119
+ aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
120
+ <p class="episode-title flex-grow-1">{{episode.name}}</p>
121
+ <span>Levels {{episode.first_level}}-{{episode.last_level}}</span>
122
+ <div class="episode_range_text collapsed d-flex align-items-center justify-content-end"
123
+ data-toggle="collapse" data-target="#collapse-{{episode.id}}"
124
+ aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
125
+ <label class="mb-0" for="select-all-episode-levels">
126
+ <input type="checkbox" value="{{ episode_index }}" id="select-all-blockly-levels-{{ episode.id }}">
127
+ </label>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
132
+ <div class="panel-body d-flex justify-content-between">
133
+ <div class="d-flex flex-grow-1 flex-column justify-content-between">
134
+ {% for level in episode.levels %}
135
+ <p>{{level.name}}: {{level.title.strip | safe}}</p>
136
+ {% endfor %}
137
+ </div>
138
+ <div class="form__checkbox flex-column justify-content-between p-0">
139
+ {% for input in level_control_form|get_dict_item:episode_index %}
140
+ <div class="form__checkbox-input p-0">
141
+ {{ input }}
142
+ </div>
143
+ {% endfor %}
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ {% endwith %}
149
+ {% endwith %}
150
+ {% endfor %}
151
+ <div class="panel-intro d-flex align-items-center justify-content-between">
152
+ <h6>Python Den levels</h6>
153
+ <label class="pr-5 mb-0 mr-5">
154
+ <input type="checkbox" id="select-all-python-levels">
155
+ </label>
156
+ </div>
157
+ {% for episode in python_episodes %}
158
+ {% with episode.id|stringformat:"s" as episode_id %}
159
+ {% with "episode"|add:episode_id as episode_index %}
160
+ <div class="panel">
161
+ <div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
162
+ <div class="d-flex align-items-center justify-content-end" data-toggle="collapse"
163
+ data-target="#collapse-{{episode.id}}" aria-expanded="false"
164
+ aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
165
+ <p class="episode-title flex-grow-1">{{episode.name}}</p>
166
+ {% if episode.levels %}
167
+ {% if episode.first_level > 1009 %}
168
+ <span>Levels {{episode.first_level|stringformat:"i"|slice:"2:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}</span>
169
+ {% else %}
170
+ {% if episode.last_level > 1009 %}
171
+ <span>Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}</span>
172
+ {% else %}
173
+ <span>Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"3:4"}}</span>
174
+ {% endif %}
175
+ {% endif %}
176
+ {% endif %}
177
+ <div class="episode_range_text collapsed d-flex align-items-center justify-content-end"
178
+ data-toggle="collapse" data-target="#collapse-{{episode.id}}"
179
+ aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
180
+ <label class="mb-0" for="select-all-episode-levels">
181
+ <input type="checkbox" value="{{ episode_index }}" id="select-all-python-levels-{{ episode.id }}">
182
+ </label>
183
+ </div>
184
+ </div>
185
+ </div>
186
+ <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
187
+ <div class="panel-body d-flex justify-content-between">
188
+ <div class="d-flex flex-grow-1 flex-column justify-content-between">
189
+ {% for level in episode.levels %}
190
+ {% for worksheet in episode.worksheets %}
191
+ {% if worksheet.before_level == level.id %}
192
+ <p>{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</p>
193
+ {% endif %}
194
+ {% endfor %}
195
+ {% if level.name < 1010 %}
196
+ <p>{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</p>
197
+ {% else %}
198
+ <p>{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</p>
199
+ {% endif %}
200
+ {% endfor %}
201
+ {% for worksheet in episode.worksheets %}
202
+ {% if not worksheet.before_level %}
203
+ <p>{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</p>
204
+ {% endif %}
205
+ {% endfor %}
206
+ </div>
207
+ <div class="form__checkbox flex-column justify-content-between p-0">
208
+ {% for input in level_control_form|get_dict_item:episode_index %}
209
+ <div class="form__checkbox-input p-0">
210
+ {{ input }}
211
+ </div>
212
+ {% endfor %}
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ {% endwith %}
218
+ {% endwith %}
219
+ {% endfor %}
220
+ </div>
221
+
222
+ <div class="button-group">
223
+ <button id="lock_levels_button" class="button button--primary" type="submit" name="level_control_submit">
224
+ Save level settings</button>
225
+ </div>
226
+ </form>
227
+ </div>
228
+
72
229
  <div class="background background--primary">
73
230
  <div class="container">
74
231
  <h5>Transfer class to another teacher</h5>
@@ -1,4 +1,5 @@
1
1
  {% extends 'portal/base.html' %}
2
+ {% load static %}
2
3
 
3
4
  {% block subNav %}
4
5
  {% include "portal/partials/teacher_non_dashboard_subnav.html" %}
@@ -39,7 +40,7 @@
39
40
 
40
41
  <p>You can set this student's password. Setting the password will also regenerate their direct access link.</p>
41
42
 
42
- <form method="post">
43
+ <form id="edit-student-password-form" method="post">
43
44
 
44
45
  {% csrf_token %}
45
46
 
@@ -49,16 +50,20 @@
49
50
  {{ password_form.non_field_errors }}
50
51
 
51
52
  <div class="row form-row">
52
- <div class="form--row__input col-sm-6 col-md-6">
53
- {{ password_form.password }}
53
+ <div class="form--row col-sm-6 col-md-6">
54
+ <div class="input--icon">
55
+ {{ password_form.password }} <span id="password-field-icon" class="iconify" data-icon="material-symbols:visibility-off"></span>
56
+ </div>
54
57
  {{ password_form.password.errors }}
55
58
  <small>{{ password_form.password.help_text}}</small>
56
59
  </div>
57
60
  </div>
58
61
 
59
62
  <div class="row form-row">
60
- <div class="form--row__input col-sm-6 col-md-6">
61
- {{ password_form.confirm_password }}
63
+ <div class="form--row col-sm-6 col-md-6">
64
+ <div class="input--icon">
65
+ {{ password_form.confirm_password }} <span id="confirm-password-field-icon" class="iconify" data-icon="material-symbols:visibility-off"></span>
66
+ </div>
62
67
  {{ password_form.confirm_password.errors }}
63
68
  <small>{{ password_form.confirm_password.help_text }}</small>
64
69
  </div>
@@ -68,4 +73,6 @@
68
73
  </div>
69
74
  </div>
70
75
 
76
+ <script type="text/javascript" src="{% static 'portal/js/teacherEditStudent.js' %}"></script>
77
+
71
78
  {% endblock %}