codeforlife-portal 7.4.9__tar.gz → 8.0.1__tar.gz

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.

Potentially problematic release.


This version of codeforlife-portal might be problematic. Click here for more details.

Files changed (559) hide show
  1. {codeforlife-portal-7.4.9/codeforlife_portal.egg-info → codeforlife-portal-8.0.1}/PKG-INFO +1 -1
  2. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1/codeforlife_portal.egg-info}/PKG-INFO +1 -1
  3. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/SOURCES.txt +2 -2
  4. codeforlife-portal-8.0.1/codeforlife_portal.egg-info/requires.txt +14 -0
  5. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/security.py +4 -5
  6. codeforlife-portal-8.0.1/portal/__init__.py +1 -0
  7. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/admin.py +26 -24
  8. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/play.py +2 -2
  9. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/registration.py +2 -2
  10. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/teach.py +2 -2
  11. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/decorators.py +18 -18
  12. {codeforlife-portal-7.4.9/portal/templates/captcha → codeforlife-portal-8.0.1/portal/templates/django_recaptcha}/includes/js_v2_invisible.html +3 -3
  13. {codeforlife-portal-7.4.9/portal/templates/captcha → codeforlife-portal-8.0.1/portal/templates/django_recaptcha}/widget_v2_invisible.html +2 -2
  14. codeforlife-portal-8.0.1/portal/templates/two_factor/core/login.html +70 -0
  15. codeforlife-portal-8.0.1/portal/templates/two_factor/core/setup.html +66 -0
  16. codeforlife-portal-8.0.1/portal/templates/two_factor/profile/profile.html +60 -0
  17. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_captcha_forms.py +2 -2
  18. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_middleware.py +32 -10
  19. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/urls.py +94 -88
  20. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/api.py +30 -16
  21. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/home.py +45 -15
  22. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/registration.py +3 -3
  23. codeforlife-portal-8.0.1/portal/views/two_factor/core.py +28 -0
  24. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/profile.py +2 -2
  25. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/setup.py +6 -13
  26. codeforlife-portal-7.4.9/codeforlife_portal.egg-info/requires.txt +0 -21
  27. codeforlife-portal-7.4.9/portal/__init__.py +0 -1
  28. codeforlife-portal-7.4.9/portal/templates/two_factor/core/login.html +0 -63
  29. codeforlife-portal-7.4.9/portal/templates/two_factor/core/setup.html +0 -57
  30. codeforlife-portal-7.4.9/portal/templates/two_factor/profile/profile.html +0 -42
  31. codeforlife-portal-7.4.9/portal/views/two_factor/core.py +0 -25
  32. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/LICENSE.md +0 -0
  33. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/MANIFEST.in +0 -0
  34. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/README.md +0 -0
  35. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/dependency_links.txt +0 -0
  36. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/not-zip-safe +0 -0
  37. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/top_level.txt +0 -0
  38. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/__init__.py +0 -0
  39. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/captcha.py +0 -0
  40. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/__init__.py +0 -0
  41. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/admin_access.py +0 -0
  42. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/basicauth.py +0 -0
  43. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/exceptionlogging.py +0 -0
  44. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/screentime_warning.py +0 -0
  45. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/session_timeout.py +0 -0
  46. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-120x120.png +0 -0
  47. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-152x152.png +0 -0
  48. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-180x180.png +0 -0
  49. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-76x76.png +0 -0
  50. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon.png +0 -0
  51. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/robots.txt +0 -0
  52. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/templates/deploy/csrf_failure.html +0 -0
  53. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/views.py +0 -0
  54. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/app_settings.py +0 -0
  55. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/backends.py +0 -0
  56. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/beta.py +0 -0
  57. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/context_processors.py +0 -0
  58. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/__init__.py +0 -0
  59. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/admin.py +0 -0
  60. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/dotmailer.py +0 -0
  61. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/error_messages.py +0 -0
  62. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/invite_teacher.py +0 -0
  63. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/organisation.py +0 -0
  64. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/handlers.py +0 -0
  65. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/__init__.py +0 -0
  66. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/captcha.py +0 -0
  67. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/password.py +0 -0
  68. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/ratelimit.py +0 -0
  69. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/regexes.py +0 -0
  70. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/request_handlers.py +0 -0
  71. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0001_squashed_0041_new_news.py +0 -0
  72. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0042_school_country.py +0 -0
  73. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0043_auto_20150430_0952.py +0 -0
  74. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0044_auto_20150430_0959.py +0 -0
  75. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0045_auto_20150430_1446.py +0 -0
  76. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0046_auto_20150723_1101.py +0 -0
  77. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0047_remove_userprofile_avatar.py +0 -0
  78. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0048_plural_management_frontnews.py +0 -0
  79. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0049_refactor_emailverifications.py +0 -0
  80. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0050_refactor_emailverifications_2.py +0 -0
  81. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0051_add_missing_ev_records.py +0 -0
  82. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0052_refactor_emailverifications_3.py +0 -0
  83. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0053_refactor_teacher_student_1.py +0 -0
  84. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0054_pending_join_request_can_be_blank.py +0 -0
  85. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0055_add_preview_user.py +0 -0
  86. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0056_remove_preview_user.py +0 -0
  87. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0057_delete_frontpagenews.py +0 -0
  88. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0058_move_to_common_models.py +0 -0
  89. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0059_move_email_verifications_to_common.py +0 -0
  90. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0060_delete_guardian.py +0 -0
  91. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0061_make_portaladmin_teacher.py +0 -0
  92. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0062_verify_portaladmin.py +0 -0
  93. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/__init__.py +0 -0
  94. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/mixins/__init__.py +0 -0
  95. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/mixins/cron_mixin.py +0 -0
  96. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/models.py +0 -0
  97. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/permissions/__init__.py +0 -0
  98. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/permissions/is_cron_request_from_google.py +0 -0
  99. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/pipeline_compilers/__init__.py +0 -0
  100. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/pipeline_compilers/libsass_compiler.py +0 -0
  101. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  102. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.svg +0 -0
  103. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  104. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  105. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  106. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/10_years_anniversary.png +0 -0
  107. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/10x_logo.png +0 -0
  108. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_grass_background.png +0 -0
  109. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_green.svg +0 -0
  110. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_simple.png +0 -0
  111. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_cfl.jpg +0 -0
  112. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_hero.jpg +0 -0
  113. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_ocado.jpg +0 -0
  114. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/barefoot_logo.png +0 -0
  115. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/bcs_logo.png +0 -0
  116. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/clubs.png +0 -0
  117. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/coding_club_hero.jpg +0 -0
  118. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/coding_club_python_pack.png +0 -0
  119. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/border.png +0 -0
  120. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/controls.png +0 -0
  121. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/loading.gif +0 -0
  122. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/loading_background.png +0 -0
  123. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/overlay.png +0 -0
  124. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/confirmation_tick.png +0 -0
  125. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/cross.png +0 -0
  126. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/dee.png +0 -0
  127. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/facebook.png +0 -0
  128. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/favicon.ico +0 -0
  129. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/get_involved_hero.png +0 -0
  130. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gitbook.png +0 -0
  131. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gitbook_space.png +0 -0
  132. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/github.png +0 -0
  133. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/github_hero.png +0 -0
  134. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gla_logo.png +0 -0
  135. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/hamburger.png +0 -0
  136. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/help_and_support_hero.jpg +0 -0
  137. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_educate.png +0 -0
  138. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_educate_hero.jpg +0 -0
  139. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_learning_hero.jpg +0 -0
  140. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_play.png +0 -0
  141. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_play_hero.jpg +0 -0
  142. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/hope_logo.png +0 -0
  143. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_1.png +0 -0
  144. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_2.png +0 -0
  145. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_3.png +0 -0
  146. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icl_logo.png +0 -0
  147. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_controller.png +0 -0
  148. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_free.png +0 -0
  149. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_globe.png +0 -0
  150. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_piechart.png +0 -0
  151. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_step_by_step.png +0 -0
  152. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_tracking.png +0 -0
  153. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_uk_flag.png +0 -0
  154. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/kirsty.png +0 -0
  155. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl.png +0 -0
  156. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_powered.svg +0 -0
  157. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
  158. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_white_landscape.png +0 -0
  159. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado.png +0 -0
  160. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group.png +0 -0
  161. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group.svg +0 -0
  162. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group_white.svg +0 -0
  163. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_python_den.svg +0 -0
  164. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/long_europe_map.png +0 -0
  165. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/mc_saatchi_logo.png +0 -0
  166. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/nigel.png +0 -0
  167. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/ocado-swirl.svg +0 -0
  168. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_blue.svg +0 -0
  169. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_pink.svg +0 -0
  170. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_yellow.svg +0 -0
  171. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/paper_plane.png +0 -0
  172. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/phil.png +0 -0
  173. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_blue.svg +0 -0
  174. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_pink.svg +0 -0
  175. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_yellow.svg +0 -0
  176. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/pressure_cooker_logo.png +0 -0
  177. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/python_den.png +0 -0
  178. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/python_den_banner.svg +0 -0
  179. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapid_router.png +0 -0
  180. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapid_router_landing_hero.png +0 -0
  181. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapidrouter.png +0 -0
  182. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/resources_hero.jpg +0 -0
  183. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/resources_montage.jpg +0 -0
  184. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/reuben.png +0 -0
  185. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rob.png +0 -0
  186. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_advanced.png +0 -0
  187. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_beginner.png +0 -0
  188. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_intermediate.png +0 -0
  189. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sadface.png +0 -0
  190. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sharon_harrison.jpg +0 -0
  191. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sian.png +0 -0
  192. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/teaching_resources_hero.jpg +0 -0
  193. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/ten_year_map_pin.svg +0 -0
  194. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
  195. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_educate_resources.png +0 -0
  196. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_intro_c4l.jpg +0 -0
  197. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
  198. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_python_den.png +0 -0
  199. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/twitter.png +0 -0
  200. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/universities.png +0 -0
  201. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/wes.png +0 -0
  202. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/bootstrap.min.js +0 -0
  203. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/carouselCards.js +0 -0
  204. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/common.js +0 -0
  205. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/independentLogin.js +0 -0
  206. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/independentRegistration.js +0 -0
  207. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/join_create_game_toggle.js +0 -0
  208. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/jquery.placeholder.js +0 -0
  209. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/levelControl.js +0 -0
  210. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery-video-lightning.js +0 -0
  211. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.colorbox.js +0 -0
  212. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.easy-ticker.js +0 -0
  213. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.min.js +0 -0
  214. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/modernizr-build.js +0 -0
  215. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/papaparse.min.js +0 -0
  216. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/organisation_manage.js +0 -0
  217. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/passwordStrength.js +0 -0
  218. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/play.js +0 -0
  219. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/resetPassword.js +0 -0
  220. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/riveted.min.js +0 -0
  221. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/school.js +0 -0
  222. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/sticky_subnav.js +0 -0
  223. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/studentLogin.js +0 -0
  224. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teach_browser.js +0 -0
  225. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teach_class.js +0 -0
  226. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teacherEditStudent.js +0 -0
  227. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teacherLogin.js +0 -0
  228. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/tenYearMap.js +0 -0
  229. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_alerts.scss +0 -0
  230. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_badges.scss +0 -0
  231. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_breadcrumbs.scss +0 -0
  232. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_button-groups.scss +0 -0
  233. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_buttons.scss +0 -0
  234. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_carousel.scss +0 -0
  235. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_close.scss +0 -0
  236. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_code.scss +0 -0
  237. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_component-animations.scss +0 -0
  238. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_dropdowns.scss +0 -0
  239. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_forms.scss +0 -0
  240. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_glyphicons.scss +0 -0
  241. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_grid.scss +0 -0
  242. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_input-groups.scss +0 -0
  243. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_jumbotron.scss +0 -0
  244. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_labels.scss +0 -0
  245. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_list-group.scss +0 -0
  246. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_media.scss +0 -0
  247. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_mixins.scss +0 -0
  248. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_modals.scss +0 -0
  249. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_navbar.scss +0 -0
  250. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_navs.scss +0 -0
  251. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_normalize.scss +0 -0
  252. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_pager.scss +0 -0
  253. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_pagination.scss +0 -0
  254. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_panels.scss +0 -0
  255. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_popovers.scss +0 -0
  256. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_print.scss +0 -0
  257. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_progress-bars.scss +0 -0
  258. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_responsive-embed.scss +0 -0
  259. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_responsive-utilities.scss +0 -0
  260. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_scaffolding.scss +0 -0
  261. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_tables.scss +0 -0
  262. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_theme.scss +0 -0
  263. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_thumbnails.scss +0 -0
  264. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_tooltip.scss +0 -0
  265. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_type.scss +0 -0
  266. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_utilities.scss +0 -0
  267. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_variables.scss +0 -0
  268. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_wells.scss +0 -0
  269. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_alerts.scss +0 -0
  270. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_background-variant.scss +0 -0
  271. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_border-radius.scss +0 -0
  272. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_breakpoints.scss +0 -0
  273. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_buttons.scss +0 -0
  274. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_center-block.scss +0 -0
  275. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_clearfix.scss +0 -0
  276. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_forms.scss +0 -0
  277. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_gradients.scss +0 -0
  278. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_grid-framework.scss +0 -0
  279. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_grid.scss +0 -0
  280. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_hide-text.scss +0 -0
  281. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_image.scss +0 -0
  282. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_labels.scss +0 -0
  283. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_list-group.scss +0 -0
  284. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_nav-divider.scss +0 -0
  285. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_nav-vertical-align.scss +0 -0
  286. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_opacity.scss +0 -0
  287. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_pagination.scss +0 -0
  288. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_panels.scss +0 -0
  289. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_progress-bar.scss +0 -0
  290. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_reset-filter.scss +0 -0
  291. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_reset-text.scss +0 -0
  292. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_resize.scss +0 -0
  293. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_responsive-visibility.scss +0 -0
  294. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_size.scss +0 -0
  295. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_tab-focus.scss +0 -0
  296. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_table-row.scss +0 -0
  297. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-emphasis.scss +0 -0
  298. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-overflow.scss +0 -0
  299. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-truncate.scss +0 -0
  300. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_vendor-prefixes.scss +0 -0
  301. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap.scss +0 -0
  302. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_all.scss +0 -0
  303. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_border-radius.scss +0 -0
  304. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_box-shadow.scss +0 -0
  305. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_hover.scss +0 -0
  306. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_nav-divider.scss +0 -0
  307. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_dropdown.scss +0 -0
  308. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_glyphicons.scss +0 -0
  309. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_grid.scss +0 -0
  310. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_variables.scss +0 -0
  311. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_align.scss +0 -0
  312. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_background.scss +0 -0
  313. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_borders.scss +0 -0
  314. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_clearfix.scss +0 -0
  315. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_cursor.scss +0 -0
  316. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_display.scss +0 -0
  317. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_flex.scss +0 -0
  318. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_float.scss +0 -0
  319. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_position.scss +0 -0
  320. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_screenreaders.scss +0 -0
  321. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_sizing.scss +0 -0
  322. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_spacing.scss +0 -0
  323. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_text.scss +0 -0
  324. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_visibility.scss +0 -0
  325. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/colorbox.scss +0 -0
  326. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_all.scss +0 -0
  327. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_animation.scss +0 -0
  328. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_breakpoints.scss +0 -0
  329. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_card_constants.scss +0 -0
  330. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_colours.scss +0 -0
  331. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_homepage_constants.scss +0 -0
  332. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_levels.scss +0 -0
  333. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_mixins.scss +0 -0
  334. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_spacing.scss +0 -0
  335. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_banners.scss +0 -0
  336. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_base.scss +0 -0
  337. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_buttons.scss +0 -0
  338. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_carousel.scss +0 -0
  339. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_footer.scss +0 -0
  340. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_forms.scss +0 -0
  341. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_grids.scss +0 -0
  342. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_header.scss +0 -0
  343. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_images.scss +0 -0
  344. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_popup.scss +0 -0
  345. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_progress-bars.scss +0 -0
  346. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_subnavs.scss +0 -0
  347. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_tables.scss +0 -0
  348. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_text.scss +0 -0
  349. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_ui-dialog.scss +0 -0
  350. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_utils.scss +0 -0
  351. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/styles.scss +0 -0
  352. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/video/code for life .pdf +0 -0
  353. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/__init__.py +0 -0
  354. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/about.py +0 -0
  355. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/coding_club.py +0 -0
  356. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/help_and_support.py +0 -0
  357. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/home_learning.py +0 -0
  358. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/materials.py +0 -0
  359. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/play.py +0 -0
  360. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/teach.py +0 -0
  361. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/teacher_resources.py +0 -0
  362. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/ten_year_map.py +0 -0
  363. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/403.html +0 -0
  364. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/404.html +0 -0
  365. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/500.html +0 -0
  366. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/email.html +0 -0
  367. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/email.txt +0 -0
  368. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/about.html +0 -0
  369. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/base.html +0 -0
  370. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/base_no_userprofile.html +0 -0
  371. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/coding_club.html +0 -0
  372. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/contribute.html +0 -0
  373. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/dotmailer_consent_form.html +0 -0
  374. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_invitation_sent.html +0 -0
  375. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_style_template.html +0 -0
  376. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_verification_failed.html +0 -0
  377. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_verification_needed.html +0 -0
  378. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/form_shapes.html +0 -0
  379. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/getinvolved.html +0 -0
  380. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/home.html +0 -0
  381. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/home_learning.html +0 -0
  382. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/locked_out.html +0 -0
  383. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/locked_out_school_student.html +0 -0
  384. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/independent_student.html +0 -0
  385. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/student.html +0 -0
  386. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/student_class_code.html +0 -0
  387. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/teacher.html +0 -0
  388. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/mouseflow.html +0 -0
  389. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/banner.html +0 -0
  390. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/benefits.html +0 -0
  391. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/card_list.html +0 -0
  392. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/character_list.html +0 -0
  393. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/delete_popup.html +0 -0
  394. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/donate_popup.html +0 -0
  395. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/footer.html +0 -0
  396. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/header.html +0 -0
  397. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/headline.html +0 -0
  398. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/hero_card.html +0 -0
  399. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/info_popup.html +0 -0
  400. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/invite_admin_teacher.html +0 -0
  401. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/popup.html +0 -0
  402. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/register_newsletter_tickbox.html +0 -0
  403. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/screentime_popup.html +0 -0
  404. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/service_unavailable_popup.html +0 -0
  405. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/session_popup.html +0 -0
  406. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/teacher_non_dashboard_subnav.html +0 -0
  407. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/teacher_non_dashboard_subnav_account.html +0 -0
  408. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_dashboard.html +0 -0
  409. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_edit_account.html +0 -0
  410. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_join_organisation.html +0 -0
  411. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play.html +0 -0
  412. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/privacy_notice.html +0 -0
  413. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/register.html +0 -0
  414. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password.html +0 -0
  415. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_confirm.html +0 -0
  416. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_done.html +0 -0
  417. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_email_sent.html +0 -0
  418. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/tag_manager/tag_manager_body.html +0 -0
  419. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/tag_manager/tag_manager_head.html +0 -0
  420. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/base_registering.html +0 -0
  421. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/class.html +0 -0
  422. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/dashboard.html +0 -0
  423. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/invited.html +0 -0
  424. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_classes.html +0 -0
  425. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_print.html +0 -0
  426. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_school.html +0 -0
  427. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_students.html +0 -0
  428. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_add_external_student.html +0 -0
  429. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_added_external_student.html +0 -0
  430. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_dismiss_students.html +0 -0
  431. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_edit_class.html +0 -0
  432. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_edit_student.html +0 -0
  433. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_all_classes.html +0 -0
  434. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_students.html +0 -0
  435. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_students_to_class.html +0 -0
  436. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach.html +0 -0
  437. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/ten_year_map.html +0 -0
  438. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/terms.html +0 -0
  439. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_base.html +0 -0
  440. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions.html +0 -0
  441. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions_enable_2fa.html +0 -0
  442. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions_submit.html +0 -0
  443. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_forms.html +0 -0
  444. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_forms_token.html +0 -0
  445. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/backup_token.html +0 -0
  446. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/core/backup_tokens.html +0 -0
  447. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/core/setup_complete.html +0 -0
  448. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/profile/disable.html +0 -0
  449. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/setup_wizard_token.html +0 -0
  450. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/__init__.py +0 -0
  451. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/app_tags.py +0 -0
  452. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/banner_tags.py +0 -0
  453. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/benefits_tags.py +0 -0
  454. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/card_list_tags.py +0 -0
  455. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/future.py +0 -0
  456. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/headline_tags.py +0 -0
  457. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/hero_card_tags.py +0 -0
  458. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/table_tags.py +0 -0
  459. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/__init__.py +0 -0
  460. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/base_test.py +0 -0
  461. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/conftest.py +0 -0
  462. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/__init__.py +0 -0
  463. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_make_portaladmin_teacher.py +0 -0
  464. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_preview_user_remove.py +0 -0
  465. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_preview_users.py +0 -0
  466. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_remove_front_page_news.py +0 -0
  467. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_remove_guardian.py +0 -0
  468. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_use_common_models.py +0 -0
  469. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_verify_portaladmin.py +0 -0
  470. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/__init__.py +0 -0
  471. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/__init__.py +0 -0
  472. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/__init__.py +0 -0
  473. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -0
  474. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_data_page.py +0 -0
  475. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_map_page.py +0 -0
  476. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/base_page.py +0 -0
  477. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/email_verification_needed_page.py +0 -0
  478. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/forbidden_page.py +0 -0
  479. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/game_page.py +0 -0
  480. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/home_page.py +0 -0
  481. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/independent_login_page.py +0 -0
  482. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/password_reset_form_page.py +0 -0
  483. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/password_reset_page.py +0 -0
  484. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/__init__.py +0 -0
  485. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/account_page.py +0 -0
  486. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/dashboard_page.py +0 -0
  487. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/join_school_or_club_page.py +0 -0
  488. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/play_base_page.py +0 -0
  489. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play_page.py +0 -0
  490. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/resources_page.py +0 -0
  491. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/signup_page.py +0 -0
  492. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/student_login_class_code.py +0 -0
  493. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/student_login_page.py +0 -0
  494. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/__init__.py +0 -0
  495. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +0 -0
  496. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +0 -0
  497. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/class_page.py +0 -0
  498. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/dashboard_page.py +0 -0
  499. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/dismiss_students_page.py +0 -0
  500. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/edit_student_page.py +0 -0
  501. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_class_page.py +0 -0
  502. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_classes_page.py +0 -0
  503. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +0 -0
  504. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_students_page.py +0 -0
  505. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +0 -0
  506. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +0 -0
  507. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +0 -0
  508. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_students_page.py +0 -0
  509. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/teach_base_page.py +0 -0
  510. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teacher_login_page.py +0 -0
  511. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/selenium_test_case.py +0 -0
  512. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/snapshots/__init__.py +0 -0
  513. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/snapshots/snap_test_partials.py +0 -0
  514. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_2FA.py +0 -0
  515. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_admin.py +0 -0
  516. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_api.py +0 -0
  517. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_class.py +0 -0
  518. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_emails.py +0 -0
  519. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_global_forms.py +0 -0
  520. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_helper_methods.py +0 -0
  521. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_independent_student.py +0 -0
  522. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_invite_teacher.py +0 -0
  523. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_organisation.py +0 -0
  524. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_partials.py +0 -0
  525. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_ratelimit.py +0 -0
  526. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_school_student.py +0 -0
  527. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_security.py +0 -0
  528. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_teacher.py +0 -0
  529. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_teacher_student.py +0 -0
  530. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_views.py +0 -0
  531. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/__init__.py +0 -0
  532. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/classes.py +0 -0
  533. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/messages.py +0 -0
  534. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/__init__.py +0 -0
  535. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/about.py +0 -0
  536. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/admin.py +0 -0
  537. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/cron/__init__.py +0 -0
  538. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/cron/user.py +0 -0
  539. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/dotmailer.py +0 -0
  540. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/email.py +0 -0
  541. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/legal.py +0 -0
  542. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/__init__.py +0 -0
  543. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/independent_student.py +0 -0
  544. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/student.py +0 -0
  545. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/teacher.py +0 -0
  546. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/organisation.py +0 -0
  547. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/play_landing_page.py +0 -0
  548. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/__init__.py +0 -0
  549. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/edit_account_details.py +0 -0
  550. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/play.py +0 -0
  551. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teach.py +0 -0
  552. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/__init__.py +0 -0
  553. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/dashboard.py +0 -0
  554. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/teach.py +0 -0
  555. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/__init__.py +0 -0
  556. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/form.py +0 -0
  557. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/wsgi.py +0 -0
  558. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/pyproject.toml +0 -0
  559. {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 7.4.9
3
+ Version: 8.0.1
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 7.4.9
3
+ Version: 8.0.1
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -349,8 +349,8 @@ portal/templates/404.html
349
349
  portal/templates/500.html
350
350
  portal/templates/email.html
351
351
  portal/templates/email.txt
352
- portal/templates/captcha/widget_v2_invisible.html
353
- portal/templates/captcha/includes/js_v2_invisible.html
352
+ portal/templates/django_recaptcha/widget_v2_invisible.html
353
+ portal/templates/django_recaptcha/includes/js_v2_invisible.html
354
354
  portal/templates/portal/about.html
355
355
  portal/templates/portal/base.html
356
356
  portal/templates/portal/base_no_userprofile.html
@@ -0,0 +1,14 @@
1
+ django-recaptcha==4.0.0
2
+ pyyaml==6.0.2
3
+ importlib-metadata==4.13.0
4
+ reportlab==3.6.13
5
+ django-formtools==2.5.1
6
+ django-otp==1.5.4
7
+ requests==2.32.2
8
+ django-treebeard==4.7.1
9
+ django-sekizai==4.1.0
10
+ django-classy-tags==4.1.0
11
+ phonenumbers==8.12.12
12
+ django-ratelimit==3.0.1
13
+ django-preventconcurrentlogins==0.8.2
14
+ setuptools==74.0.0
@@ -4,8 +4,8 @@ from django.middleware.security import SecurityMiddleware
4
4
  class CustomSecurityMiddleware(SecurityMiddleware):
5
5
  """
6
6
  Extends Django's Security Middleware.
7
- See https://docs.djangoproject.com/en/3.2/_modules/django/middleware/security/ for
8
- the source code, as well as https://docs.djangoproject.com/en/3.2/ref/middleware/#module-django.middleware.security
7
+ See https://docs.djangoproject.com/en/4.2/_modules/django/middleware/security/ for
8
+ the source code, as well as https://docs.djangoproject.com/en/4.2/ref/middleware/#module-django.middleware.security
9
9
  for docs on security middleware.
10
10
  """
11
11
 
@@ -13,10 +13,9 @@ class CustomSecurityMiddleware(SecurityMiddleware):
13
13
  """
14
14
  Extends the original security middleware to ensure the X-XSS-Protection header
15
15
  is set to 1.
16
+ https://docs.djangoproject.com/en/5.1/releases/4.0/#securitymiddleware-no-longer-sets-the-x-xss-protection-header
16
17
  """
17
18
  super().process_response(request, response)
18
-
19
- if self.xss_filter:
20
- response["X-XSS-Protection"] = "1"
19
+ response.headers.setdefault("X-XSS-Protection", "1; mode=block")
21
20
 
22
21
  return response
@@ -0,0 +1 @@
1
+ __version__ = "8.0.1"
@@ -12,7 +12,7 @@ from common.models import (
12
12
  UserProfile,
13
13
  )
14
14
  from django.contrib import admin
15
- from django.contrib.auth.admin import UserAdmin
15
+ from django.contrib.auth.admin import UserAdmin as _UserAdmin
16
16
  from django.contrib.auth.models import User
17
17
  from django.http import HttpResponse
18
18
  from import_export.admin import ExportActionMixin
@@ -172,38 +172,40 @@ class TotalActivityAdmin(admin.ModelAdmin, ExportActionMixin):
172
172
  return False
173
173
 
174
174
 
175
- def anonymise_user(user_admin, request, queryset):
176
- for user in queryset:
177
- anonymise(user)
175
+ _UserAdmin.list_display += ("date_joined", "id")
176
+ _UserAdmin.list_filter += ("date_joined",)
178
177
 
179
178
 
180
- def export_as_csv(self, request, queryset):
181
- meta = self.model._meta
182
- field_names = [
183
- field.name for field in meta.fields if field.name != "password"
184
- ]
179
+ class UserAdmin(_UserAdmin):
180
+ actions = ["anonymise_user", "export_as_csv"]
181
+ add_form = AdminUserCreationForm
182
+ change_password_form = AdminChangeUserPasswordForm
185
183
 
186
- response = HttpResponse(content_type="text/csv")
187
- response["Content-Disposition"] = "attachment; filename={}.csv".format(meta)
188
- writer = csv.writer(response)
184
+ def anonymise_user(self, request, queryset):
185
+ for user in queryset:
186
+ anonymise(user)
189
187
 
190
- writer.writerow(field_names)
191
- for obj in queryset:
192
- writer.writerow([getattr(obj, field) for field in field_names])
188
+ anonymise_user.short_description = "Anonymise selected users"
193
189
 
194
- return response
190
+ def export_as_csv(self, request, queryset):
191
+ meta = self.model._meta
192
+ field_names = [
193
+ field.name for field in meta.fields if field.name != "password"
194
+ ]
195
195
 
196
+ response = HttpResponse(content_type="text/csv")
197
+ response["Content-Disposition"] = "attachment; filename={}.csv".format(
198
+ meta
199
+ )
200
+ writer = csv.writer(response)
196
201
 
197
- anonymise_user.short_description = "Anonymise selected users"
198
- export_as_csv.short_description = "Export selected users data as CSV"
202
+ writer.writerow(field_names)
203
+ for obj in queryset:
204
+ writer.writerow([getattr(obj, field) for field in field_names])
199
205
 
206
+ return response
200
207
 
201
- UserAdmin.list_display += ("date_joined", "id")
202
- UserAdmin.list_filter += ("date_joined",)
203
- UserAdmin.add_form = AdminUserCreationForm
204
- UserAdmin.change_password_form = AdminChangeUserPasswordForm
205
- UserAdmin.actions.append(anonymise_user)
206
- UserAdmin.actions.append(export_as_csv)
208
+ export_as_csv.short_description = "Export selected users data as CSV"
207
209
 
208
210
 
209
211
  admin.site.register(Class, ClassAdmin)
@@ -1,8 +1,6 @@
1
1
  import re
2
2
  from datetime import timedelta, date
3
3
 
4
- from captcha.fields import ReCaptchaField
5
- from captcha.widgets import ReCaptchaV2Invisible
6
4
  from common.helpers.emails import send_verification_email
7
5
  from common.models import Class, Student, stripStudentName
8
6
  from common.permissions import logged_in_as_independent_student
@@ -10,6 +8,8 @@ from django import forms
10
8
  from django.contrib.auth import authenticate
11
9
  from django.contrib.auth.forms import AuthenticationForm
12
10
  from django.utils import timezone
11
+ from django_recaptcha.fields import ReCaptchaField
12
+ from django_recaptcha.widgets import ReCaptchaV2Invisible
13
13
 
14
14
  from portal.forms.error_messages import INVALID_LOGIN_MESSAGE
15
15
  from portal.helpers.password import PasswordStrength, form_clean_password
@@ -1,5 +1,3 @@
1
- from captcha.fields import ReCaptchaField
2
- from captcha.widgets import ReCaptchaV2Invisible
3
1
  from common.mail import campaign_ids, send_dotdigital_email
4
2
  from common.models import Student, Teacher
5
3
  from django import forms
@@ -10,6 +8,8 @@ from django.contrib.sites.shortcuts import get_current_site
10
8
  from django.urls import reverse_lazy
11
9
  from django.utils.encoding import force_bytes
12
10
  from django.utils.http import urlsafe_base64_encode
11
+ from django_recaptcha.fields import ReCaptchaField
12
+ from django_recaptcha.widgets import ReCaptchaV2Invisible
13
13
 
14
14
  from portal.helpers.password import PasswordStrength, form_clean_password
15
15
 
@@ -2,14 +2,14 @@ import itertools
2
2
  import re
3
3
  from builtins import map, range, str
4
4
 
5
- from captcha.fields import ReCaptchaField
6
- from captcha.widgets import ReCaptchaV2Invisible
7
5
  from common.helpers.emails import send_verification_email
8
6
  from common.models import Student, stripStudentName, UserSession, Teacher
9
7
  from django import forms
10
8
  from django.contrib.auth import authenticate
11
9
  from django.contrib.auth.forms import AuthenticationForm
12
10
  from django.contrib.auth.models import User
11
+ from django_recaptcha.fields import ReCaptchaField
12
+ from django_recaptcha.widgets import ReCaptchaV2Invisible
13
13
  from game.models import Episode
14
14
 
15
15
  from portal.forms.error_messages import INVALID_LOGIN_MESSAGE
@@ -1,28 +1,24 @@
1
1
  from __future__ import absolute_import
2
2
 
3
3
  import datetime
4
- import pytz
5
- import re
6
-
4
+ from functools import wraps
7
5
 
6
+ import pytz
8
7
  from common.models import Teacher, Student
9
8
  from django.contrib.auth import logout
10
9
  from django.shortcuts import render
11
- from functools import wraps
12
10
  from ratelimit import ALL, UNSAFE
13
11
 
14
12
  from portal.helpers.ratelimit import is_ratelimited
15
- from portal.templatetags.app_tags import is_logged_in
16
- from portal.views.registration import blocked_and_not_expired
17
- from portal.views.login import has_user_lockout_expired
18
- from portal.helpers.ratelimit import get_ratelimit_count_for_user
19
-
20
13
  from portal.helpers.request_handlers import get_access_code_from_request
14
+ from portal.templatetags.app_tags import is_logged_in
21
15
 
22
16
  __all__ = ["ratelimit"]
23
17
 
24
18
 
25
- def ratelimit(group=None, key=None, rate=None, method=ALL, block=False, is_teacher=True):
19
+ def ratelimit(
20
+ group=None, key=None, rate=None, method=ALL, block=False, is_teacher=True
21
+ ):
26
22
  """
27
23
  Ratelimit decorator, adding custom functionality to django-ratelimit's default
28
24
  decorator. On block, the user is logged out, redirected to the "locked out" page,
@@ -63,25 +59,29 @@ def ratelimit(group=None, key=None, rate=None, method=ALL, block=False, is_teach
63
59
 
64
60
  access_code = get_access_code_from_request(request)
65
61
  model_finder = model.objects.get
66
- # look for school student
67
- # if access code not found (AttributeError)
68
- # if student not found (IndexError)
69
- # move on to another try block
70
- # similar logic followed afterwards
62
+ # look for school student if access code not found
63
+ # (AttributeError) if student not found (IndexError) move
64
+ # on to another try block similar logic followed afterwards
71
65
  if access_code:
72
66
  user_to_lockout = model_finder(
73
67
  new_user__first_name=username,
74
68
  class_field__access_code=access_code, # extract the found text from regex
75
69
  )
76
- lockout_template = "portal/locked_out_school_student.html"
70
+ lockout_template = (
71
+ "portal/locked_out_school_student.html"
72
+ )
77
73
  # look for indy student or teacher
78
74
  else:
79
- user_to_lockout = model_finder(new_user__username=username)
75
+ user_to_lockout = model_finder(
76
+ new_user__username=username
77
+ )
80
78
  else:
81
79
  user_to_lockout = model.objects.get(new_user=request.user)
82
80
 
83
81
  if user_to_lockout:
84
- user_to_lockout.blocked_time = datetime.datetime.now(tz=pytz.utc)
82
+ user_to_lockout.blocked_time = datetime.datetime.now(
83
+ tz=pytz.utc
84
+ )
85
85
  user_to_lockout.save()
86
86
 
87
87
  if is_logged_in(request.user):
@@ -1,8 +1,8 @@
1
- {# This is adapted from django-recaptcha 2.0.5 to work on multiple reCAPTCHA's on the same page #}
2
- {# See verifyCaptcha_{{ widget_uuid}} for the edit #}
1
+ <!-- This is adapted from django-recaptcha 4.0.0 to work on multiple
2
+ reCAPTCHA's on the same page
3
+ See verifyCaptcha_{{ widget_uuid}} for the edit #} -->
3
4
  <script src="https://{{ recaptcha_domain }}/recaptcha/api.js{% if api_params %}?{{ api_params }}{% endif %}"></script>
4
5
  <script type="text/javascript">
5
-
6
6
  // Submit function to be called, after reCAPTCHA was successful.
7
7
  var onSubmit_{{ widget_uuid }} = function(token) {
8
8
  console.log("reCAPTCHA validated for 'data-widget-uuid=\"{{ widget_uuid }}\"'. Submitting form...")
@@ -1,5 +1,5 @@
1
- {# copied from django-recaptcha 2.0.5 #}
2
- {% include "captcha/includes/js_v2_invisible.html" %}
1
+ <!-- copied from django-recaptcha 4.0.0 -->
2
+ {% include "django_recaptcha/includes/js_v2_invisible.html" %}
3
3
  <div class="g-recaptcha"
4
4
  {% for name, value in widget.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}
5
5
  >
@@ -0,0 +1,70 @@
1
+ {# Overriden the original "two_factor" template to remove extending base template and slightly adjust style #}
2
+
3
+ {% load i18n %}
4
+ {% load two_factor_tags %}
5
+
6
+ {% block extra_media %}
7
+ {{ form.media }}
8
+ {% endblock %}
9
+
10
+ {% block content %}
11
+
12
+ <section class="row mx-0">
13
+ <span class="oval-blue login-shape-left"></span>
14
+ <span class="polygon-yellow login-shape-right"></span>
15
+ <div class="form--login is-flex form--register--teacher">
16
+ <div class="form col-xs-12 col-sm-8 col-md-8 col-lg-9 center-block">
17
+ <h4>{% block title %}{% trans "Welcome" %}{% endblock %}</h4>
18
+
19
+ {% if wizard.steps.current == 'auth' %}
20
+ <p>{% blocktrans %}Enter your credentials.{% endblocktrans %}</p>
21
+ {% elif wizard.steps.current == 'token' %}
22
+ <p>{{ device|as_verbose_action }}</p>
23
+ {% elif wizard.steps.current == 'backup' %}
24
+ <p>{% blocktrans trimmed %}Use this form for entering backup tokens for logging in.
25
+ These tokens have been generated for you to print and keep safe. Please
26
+ enter one of these backup tokens to log into your account.{% endblocktrans %}</p>
27
+ {% endif %}
28
+
29
+ <form action="" method="post">
30
+ {% block main_form_content %}
31
+ {% csrf_token %}
32
+ {% include "two_factor/_wizard_forms.html" %}
33
+
34
+ {# hidden submit button to enable [enter] key #}
35
+ <input type="submit" value="" hidden />
36
+
37
+ {% if other_devices %}
38
+ <p>{% trans "Or, alternatively, use one of your other authentication methods:" %}</p>
39
+ <p>
40
+ {% for other in other_devices %}
41
+ <button name="challenge_device" value="{{ other.persistent_id }}"
42
+ class="btn btn-secondary btn-block" type="submit">
43
+ {{ other|as_action }}
44
+ </button>
45
+ {% endfor %}</p>
46
+ {% endif %}
47
+
48
+ {% include "two_factor/_wizard_actions.html" %}
49
+ {% endblock %}
50
+ </form>
51
+
52
+ {% block 'backup_tokens' %}
53
+ {% if backup_tokens %}
54
+ <hr>
55
+ <div class="backup_tokens_form">
56
+ <form action="" method="post">
57
+ {% csrf_token %}
58
+ <p>{% trans "As a last resort, you can use a backup token:" %}</p>
59
+ <p>
60
+ <button name="wizard_goto_step" type="submit" value="backup"
61
+ class="button button--primary">{% trans "Use Backup Token" %}</button>
62
+ </p>
63
+ </form>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </section>
68
+ {% endif %}
69
+ {% endblock %}
70
+ {% endblock %}
@@ -0,0 +1,66 @@
1
+ {# Overriding the original "two_factor" template #}
2
+
3
+ {% extends "two_factor/_base_focus.html" %}
4
+ {% load i18n %}
5
+
6
+ {% block extra_media %}
7
+ {{ form.media }}
8
+ {% endblock %}
9
+
10
+ {% block content %}
11
+ <h4>{% block title %}{% trans "Enable Two-Factor Authentication" %}{% endblock %}</h4>
12
+ {% if wizard.steps.current == 'welcome' %}
13
+ <p>{% blocktrans trimmed %}You are about to take your account security to the
14
+ next level. Follow the steps in this wizard to enable two-factor
15
+ authentication.{% endblocktrans %}</p>
16
+ {% elif wizard.steps.current == 'method' %}
17
+ <p>{% blocktrans trimmed %}Please select which authentication method you would
18
+ like to use.{% endblocktrans %}</p>
19
+ {% elif wizard.steps.current == 'generator' %}
20
+ <p>{% blocktrans trimmed %}To start using a token generator, please use your
21
+ smartphone to scan the QR code below. For example, use Google
22
+ Authenticator.{% endblocktrans %}</p>
23
+ <p><img src="{{ QR_URL }}" alt="QR Code" class="bg-white"/></p>
24
+ <p>{% blocktrans trimmed %}Alternatively you can use the following secret to
25
+ set up TOTP in your authenticator or password manager manually.{% endblocktrans %}</p>
26
+ <p>{% translate "TOTP Secret:" %} <a href="{{ otpauth_url }}">{{ secret_key }}</a></p>
27
+ <p>{% blocktrans %}Then, enter the token generated by the app.{% endblocktrans %}</p>
28
+
29
+ {% elif wizard.steps.current == 'sms' %}
30
+ <p>{% blocktrans trimmed %}Please enter the phone number you wish to receive the
31
+ text messages on. This number will be validated in the next step.
32
+ {% endblocktrans %}</p>
33
+ {% elif wizard.steps.current == 'call' %}
34
+ <p>{% blocktrans trimmed %}Please enter the phone number you wish to be called on.
35
+ This number will be validated in the next step. {% endblocktrans %}</p>
36
+ {% elif wizard.steps.current == 'validation' %}
37
+ {% if challenge_succeeded %}
38
+ {% if device.method == 'call' %}
39
+ <p>{% blocktrans trimmed %}We are calling your phone right now, please enter the
40
+ digits you hear.{% endblocktrans %}</p>
41
+ {% elif device.method == 'sms' %}
42
+ <p>{% blocktrans trimmed %}We sent you a text message, please enter the tokens we
43
+ sent.{% endblocktrans %}</p>
44
+ {% endif %}
45
+ {% else %}
46
+ <p class="alert alert-warning" role="alert">{% blocktrans trimmed %}We've
47
+ encountered an issue with the selected authentication method. Please
48
+ go back and verify that you entered your information correctly, try
49
+ again, or use a different authentication method instead. If the issue
50
+ persists, contact the site administrator.{% endblocktrans %}</p>
51
+ {% endif %}
52
+ {% elif wizard.steps.current == 'yubikey' %}
53
+ <p>{% blocktrans trimmed %}To identify and verify your YubiKey, please insert a
54
+ token in the field below. Your YubiKey will be linked to your
55
+ account.{% endblocktrans %}</p>
56
+ {% endif %}
57
+
58
+ <form action="" method="post">{% csrf_token %}
59
+ {% include "two_factor/_wizard_forms.html" %}
60
+
61
+ {# hidden submit button to enable [enter] key #}
62
+ <input type="submit" value="" hidden />
63
+
64
+ {% include "two_factor/_wizard_actions.html" %}
65
+ </form>
66
+ {% endblock %}
@@ -0,0 +1,60 @@
1
+ {% extends "two_factor/_base.html" %}
2
+ {% load i18n %}
3
+ {% load two_factor_tags %}
4
+
5
+ {% block content %}
6
+ <h1>{% block title %}{% trans "Account Security" %}{% endblock %}</h1>
7
+
8
+ {% if default_device %}
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>
32
+ {% endif %}
33
+
34
+ <h2>{% trans "Backup Tokens" %}</h2>
35
+ <p>
36
+ {% blocktrans trimmed %}If you don't have any device with you, you can access
37
+ your account using backup tokens.{% endblocktrans %}
38
+ {% blocktrans trimmed count counter=backup_tokens %}
39
+ You have only one backup token remaining.
40
+ {% plural %}
41
+ You have {{ counter }} backup tokens remaining.
42
+ {% endblocktrans %}
43
+ </p>
44
+ <p><a href="{% url 'two_factor:backup_tokens' %}"
45
+ class="btn btn-info">{% trans "Show Codes" %}</a></p>
46
+
47
+ <h3>{% trans "Disable Two-Factor Authentication" %}</h3>
48
+ <p>{% blocktrans trimmed %}However we strongly discourage you to do so, you can
49
+ also disable two-factor authentication for your account.{% endblocktrans %}</p>
50
+ <p><a class="btn btn-secondary" href="{% url 'two_factor:disable' %}">
51
+ {% trans "Disable Two-Factor Authentication" %}</a></p>
52
+ {% else %}
53
+ <p>{% blocktrans trimmed %}Two-factor authentication is not enabled for your
54
+ account. Enable two-factor authentication for enhanced account
55
+ security.{% endblocktrans %}</p>
56
+ <p><a href="{% url 'two_factor:setup' %}" class="btn btn-primary">
57
+ {% trans "Enable Two-Factor Authentication" %}</a>
58
+ </p>
59
+ {% endif %}
60
+ {% endblock %}
@@ -1,7 +1,7 @@
1
- from captcha.fields import ReCaptchaField
2
- from captcha.widgets import ReCaptchaV2Invisible
3
1
  from django import forms
4
2
  from django.test import TestCase
3
+ from django_recaptcha.fields import ReCaptchaField
4
+ from django_recaptcha.widgets import ReCaptchaV2Invisible
5
5
 
6
6
  from portal.helpers.captcha import is_captcha_in_form, remove_captcha_from_forms
7
7
 
@@ -32,7 +32,9 @@ class TestAdminAccessMiddleware(TestCase):
32
32
  self.email, self.password = self._setup_user()
33
33
 
34
34
  self.monkeypatch = MonkeyPatch()
35
- self.monkeypatch.setattr("deploy.middleware.admin_access.MODULE_NAME", "test")
35
+ self.monkeypatch.setattr(
36
+ "deploy.middleware.admin_access.MODULE_NAME", "test"
37
+ )
36
38
 
37
39
  def _setup_user(self) -> Tuple[str, str]:
38
40
  email, password = signup_teacher_directly()
@@ -79,7 +81,11 @@ class TestAdminAccessMiddleware(TestCase):
79
81
  assert type(response) == HttpResponseRedirect
80
82
  assert response.url == "/teach/dashboard/"
81
83
 
82
- @mock.patch("deploy.middleware.admin_access.using_two_factor", return_value=True, autospec=True)
84
+ @mock.patch(
85
+ "deploy.middleware.admin_access.using_two_factor",
86
+ return_value=True,
87
+ autospec=True,
88
+ )
83
89
  def test_non_superuser_with_2FA_is_redirected(self, mock_using_two_factor):
84
90
  self.client.login(username=self.email, password=self.password)
85
91
 
@@ -91,8 +97,14 @@ class TestAdminAccessMiddleware(TestCase):
91
97
  assert type(response) == HttpResponseRedirect
92
98
  assert response.url == "/teach/dashboard/"
93
99
 
94
- @mock.patch("deploy.middleware.admin_access.using_two_factor", return_value=True, autospec=True)
95
- def test_superuser_with_2FA_can_access_admin_site(self, mock_using_two_factor):
100
+ @mock.patch(
101
+ "deploy.middleware.admin_access.using_two_factor",
102
+ return_value=True,
103
+ autospec=True,
104
+ )
105
+ def test_superuser_with_2FA_can_access_admin_site(
106
+ self, mock_using_two_factor
107
+ ):
96
108
  self._make_user_superuser()
97
109
 
98
110
  self.client.login(username=self.email, password=self.password)
@@ -118,7 +130,7 @@ class TestSecurityMiddleware(TestCase):
118
130
  assert response.headers["cache-control"] == "private"
119
131
  assert response.headers["x-content-type-options"] == "nosniff"
120
132
  assert response.headers["x-frame-options"] == "DENY"
121
- assert response.headers["x-xss-protection"] == "1"
133
+ assert response.headers["x-xss-protection"] == "1; mode=block"
122
134
 
123
135
 
124
136
  class TestSessionTimeoutMiddleware(TestCase):
@@ -132,7 +144,9 @@ class TestSessionTimeoutMiddleware(TestCase):
132
144
  self.email, self.password = self._setup_user()
133
145
 
134
146
  self.monkeypatch = MonkeyPatch()
135
- self.monkeypatch.setattr("deploy.middleware.session_timeout.SESSION_EXPIRY_TIME", 5)
147
+ self.monkeypatch.setattr(
148
+ "deploy.middleware.session_timeout.SESSION_EXPIRY_TIME", 5
149
+ )
136
150
 
137
151
  def _setup_user(self) -> Tuple[str, str]:
138
152
  email, password = signup_teacher_directly()
@@ -211,14 +225,18 @@ class TestScreentimeWarningMiddleware(TestCase):
211
225
  self.client.get("/")
212
226
  session = self.client.session
213
227
  assert "screentime_warning_timeout" in session
214
- previous_screentime_warning_timeout = session["screentime_warning_timeout"]
228
+ previous_screentime_warning_timeout = session[
229
+ "screentime_warning_timeout"
230
+ ]
215
231
 
216
232
  self.client.get("/")
217
233
  session = self.client.session
218
234
  assert "screentime_warning_timeout" in session
219
235
  new_screentime_warning_timeout = session["screentime_warning_timeout"]
220
236
 
221
- assert new_screentime_warning_timeout < previous_screentime_warning_timeout
237
+ assert (
238
+ new_screentime_warning_timeout < previous_screentime_warning_timeout
239
+ )
222
240
 
223
241
  # Check the reset_screentime_warning API resets the timeout
224
242
  url = reverse("reset_screentime_warning")
@@ -226,5 +244,9 @@ class TestScreentimeWarningMiddleware(TestCase):
226
244
  self.client.get("/")
227
245
  session = self.client.session
228
246
  assert "screentime_warning_timeout" in session
229
- renewed_screentime_warning_timeout = session["screentime_warning_timeout"]
230
- assert renewed_screentime_warning_timeout > new_screentime_warning_timeout
247
+ renewed_screentime_warning_timeout = session[
248
+ "screentime_warning_timeout"
249
+ ]
250
+ assert (
251
+ renewed_screentime_warning_timeout > new_screentime_warning_timeout
252
+ )