codeforlife-portal 6.43.1__tar.gz → 6.43.3__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 (567) hide show
  1. {codeforlife-portal-6.43.1/codeforlife_portal.egg-info → codeforlife-portal-6.43.3}/PKG-INFO +1 -1
  2. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3/codeforlife_portal.egg-info}/PKG-INFO +1 -1
  3. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/codeforlife_portal.egg-info/requires.txt +1 -1
  4. codeforlife-portal-6.43.3/portal/__init__.py +1 -0
  5. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_independent_student.py +23 -11
  6. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_views.py +11 -3
  7. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/home.py +16 -16
  8. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/registration.py +11 -20
  9. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/student/edit_account_details.py +8 -6
  10. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/student/play.py +25 -53
  11. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/teacher/dashboard.py +38 -22
  12. codeforlife-portal-6.43.1/portal/__init__.py +0 -1
  13. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/LICENSE.md +0 -0
  14. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/MANIFEST.in +0 -0
  15. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/README.md +0 -0
  16. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/codeforlife_portal.egg-info/SOURCES.txt +0 -0
  17. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/codeforlife_portal.egg-info/dependency_links.txt +0 -0
  18. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/codeforlife_portal.egg-info/not-zip-safe +0 -0
  19. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/codeforlife_portal.egg-info/top_level.txt +0 -0
  20. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/__init__.py +0 -0
  21. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/captcha.py +0 -0
  22. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/__init__.py +0 -0
  23. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/admin_access.py +0 -0
  24. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/basicauth.py +0 -0
  25. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/exceptionlogging.py +0 -0
  26. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/screentime_warning.py +0 -0
  27. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/security.py +0 -0
  28. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/middleware/session_timeout.py +0 -0
  29. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/apple-touch-icon-120x120.png +0 -0
  30. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/apple-touch-icon-152x152.png +0 -0
  31. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/apple-touch-icon-180x180.png +0 -0
  32. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/apple-touch-icon-76x76.png +0 -0
  33. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/apple-touch-icon.png +0 -0
  34. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/static/robots.txt +0 -0
  35. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/templates/deploy/csrf_failure.html +0 -0
  36. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/deploy/views.py +0 -0
  37. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/admin.py +0 -0
  38. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/app_settings.py +0 -0
  39. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/backends.py +0 -0
  40. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/beta.py +0 -0
  41. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/context_processors.py +0 -0
  42. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/__init__.py +0 -0
  43. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/add_game.py +0 -0
  44. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/admin.py +0 -0
  45. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/dotmailer.py +0 -0
  46. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/error_messages.py +0 -0
  47. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/invite_teacher.py +0 -0
  48. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/organisation.py +0 -0
  49. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/play.py +0 -0
  50. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/registration.py +0 -0
  51. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/forms/teach.py +0 -0
  52. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/handlers.py +0 -0
  53. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/__init__.py +0 -0
  54. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/captcha.py +0 -0
  55. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/decorators.py +0 -0
  56. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/password.py +0 -0
  57. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/ratelimit.py +0 -0
  58. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/regexes.py +0 -0
  59. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/helpers/request_handlers.py +0 -0
  60. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0001_squashed_0041_new_news.py +0 -0
  61. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0042_school_country.py +0 -0
  62. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0043_auto_20150430_0952.py +0 -0
  63. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0044_auto_20150430_0959.py +0 -0
  64. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0045_auto_20150430_1446.py +0 -0
  65. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0046_auto_20150723_1101.py +0 -0
  66. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0047_remove_userprofile_avatar.py +0 -0
  67. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0048_plural_management_frontnews.py +0 -0
  68. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0049_refactor_emailverifications.py +0 -0
  69. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0050_refactor_emailverifications_2.py +0 -0
  70. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0051_add_missing_ev_records.py +0 -0
  71. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0052_refactor_emailverifications_3.py +0 -0
  72. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0053_refactor_teacher_student_1.py +0 -0
  73. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0054_pending_join_request_can_be_blank.py +0 -0
  74. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0055_add_preview_user.py +0 -0
  75. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0056_remove_preview_user.py +0 -0
  76. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0057_delete_frontpagenews.py +0 -0
  77. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0058_move_to_common_models.py +0 -0
  78. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0059_move_email_verifications_to_common.py +0 -0
  79. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0060_delete_guardian.py +0 -0
  80. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0061_make_portaladmin_teacher.py +0 -0
  81. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/0062_verify_portaladmin.py +0 -0
  82. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/migrations/__init__.py +0 -0
  83. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/mixins/__init__.py +0 -0
  84. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/mixins/cron_mixin.py +0 -0
  85. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/models.py +0 -0
  86. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/permissions/__init__.py +0 -0
  87. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/permissions/is_cron_request_from_google.py +0 -0
  88. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/pipeline_compilers/__init__.py +0 -0
  89. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/pipeline_compilers/libsass_compiler.py +0 -0
  90. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
  91. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.svg +0 -0
  92. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
  93. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
  94. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
  95. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/10_years_anniversary.png +0 -0
  96. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/10x_logo.png +0 -0
  97. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/RR_logo_grass_background.png +0 -0
  98. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/RR_logo_green.svg +0 -0
  99. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/RR_logo_simple.png +0 -0
  100. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/about_us_cfl.jpg +0 -0
  101. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/about_us_hero.jpg +0 -0
  102. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/about_us_ocado.jpg +0 -0
  103. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/barefoot_logo.png +0 -0
  104. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/bcs_logo.png +0 -0
  105. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/clubs.png +0 -0
  106. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/coding_club_hero.jpg +0 -0
  107. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/coding_club_python_pack.png +0 -0
  108. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/colorboxImages/border.png +0 -0
  109. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/colorboxImages/controls.png +0 -0
  110. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/colorboxImages/loading.gif +0 -0
  111. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/colorboxImages/loading_background.png +0 -0
  112. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/colorboxImages/overlay.png +0 -0
  113. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/confirmation_tick.png +0 -0
  114. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/cross.png +0 -0
  115. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/dee.png +0 -0
  116. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/facebook.png +0 -0
  117. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/favicon.ico +0 -0
  118. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/get_involved_hero.png +0 -0
  119. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/gitbook.png +0 -0
  120. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/gitbook_space.png +0 -0
  121. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/github.png +0 -0
  122. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/github_hero.png +0 -0
  123. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/gla_logo.png +0 -0
  124. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/hamburger.png +0 -0
  125. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/help_and_support_hero.jpg +0 -0
  126. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/home_educate.png +0 -0
  127. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/home_educate_hero.jpg +0 -0
  128. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/home_learning_hero.jpg +0 -0
  129. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/home_play.png +0 -0
  130. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/home_play_hero.jpg +0 -0
  131. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/hope_logo.png +0 -0
  132. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icl_logo.png +0 -0
  133. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_controller.png +0 -0
  134. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_free.png +0 -0
  135. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_globe.png +0 -0
  136. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_piechart.png +0 -0
  137. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_step_by_step.png +0 -0
  138. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_tracking.png +0 -0
  139. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/icon_uk_flag.png +0 -0
  140. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kirsty.png +0 -0
  141. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_hero.jpg +0 -0
  142. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_landing_hero.png +0 -0
  143. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_logo.svg +0 -0
  144. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_logo_grey_background.svg +0 -0
  145. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_logo_mark.svg +0 -0
  146. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_resources_hero.jpg +0 -0
  147. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/kurono_story.png +0 -0
  148. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_cfl.png +0 -0
  149. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
  150. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_cfl_white_landscape.png +0 -0
  151. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_ocado.png +0 -0
  152. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_ocado_group.png +0 -0
  153. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_ocado_group.svg +0 -0
  154. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/logo_ocado_group_white.svg +0 -0
  155. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/mc_saatchi_logo.png +0 -0
  156. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/nigel.png +0 -0
  157. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/ocado-swirl.svg +0 -0
  158. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/oval_blue.svg +0 -0
  159. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/oval_pink.svg +0 -0
  160. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/oval_yellow.svg +0 -0
  161. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/paper_plane.png +0 -0
  162. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/phil.png +0 -0
  163. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/polygon_blue.svg +0 -0
  164. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/polygon_pink.svg +0 -0
  165. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/polygon_yellow.svg +0 -0
  166. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/pressure_cooker_logo.png +0 -0
  167. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rapid_router.png +0 -0
  168. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rapid_router_landing_hero.png +0 -0
  169. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rapidrouter.png +0 -0
  170. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/resources_hero.jpg +0 -0
  171. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/resources_montage.jpg +0 -0
  172. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/reuben.png +0 -0
  173. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rob.png +0 -0
  174. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rr_advanced.png +0 -0
  175. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rr_beginner.png +0 -0
  176. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/rr_intermediate.png +0 -0
  177. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/sadface.png +0 -0
  178. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/sharon_harrison.jpg +0 -0
  179. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/sian.png +0 -0
  180. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/teaching_resources_hero.jpg +0 -0
  181. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
  182. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
  183. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_educate_resources.png +0 -0
  184. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_intro_c4l.jpg +0 -0
  185. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
  186. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_play_kurono.png +0 -0
  187. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
  188. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/twitter.png +0 -0
  189. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/universities.png +0 -0
  190. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/wes.png +0 -0
  191. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/img/x_close_video.png +0 -0
  192. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/aimmoGame.js +0 -0
  193. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/bootstrap.min.js +0 -0
  194. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/carouselCards.js +0 -0
  195. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/common.js +0 -0
  196. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/independentLogin.js +0 -0
  197. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/independentRegistration.js +0 -0
  198. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/join_create_game_toggle.js +0 -0
  199. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/jquery.placeholder.js +0 -0
  200. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/levelControl.js +0 -0
  201. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/jquery-video-lightning.js +0 -0
  202. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/jquery.colorbox.js +0 -0
  203. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/jquery.easy-ticker.js +0 -0
  204. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/jquery.min.js +0 -0
  205. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/modernizr-build.js +0 -0
  206. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/lib/papaparse.min.js +0 -0
  207. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/organisation_manage.js +0 -0
  208. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/passwordStrength.js +0 -0
  209. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/play.js +0 -0
  210. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/resetPassword.js +0 -0
  211. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/riveted.min.js +0 -0
  212. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/school.js +0 -0
  213. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/sticky_subnav.js +0 -0
  214. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/studentLogin.js +0 -0
  215. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/teach_browser.js +0 -0
  216. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/teach_class.js +0 -0
  217. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/teacherEditStudent.js +0 -0
  218. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/js/teacherLogin.js +0 -0
  219. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_alerts.scss +0 -0
  220. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_badges.scss +0 -0
  221. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_breadcrumbs.scss +0 -0
  222. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_button-groups.scss +0 -0
  223. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_buttons.scss +0 -0
  224. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_carousel.scss +0 -0
  225. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_close.scss +0 -0
  226. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_code.scss +0 -0
  227. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_component-animations.scss +0 -0
  228. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_dropdowns.scss +0 -0
  229. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_forms.scss +0 -0
  230. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_glyphicons.scss +0 -0
  231. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_grid.scss +0 -0
  232. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_input-groups.scss +0 -0
  233. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_jumbotron.scss +0 -0
  234. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_labels.scss +0 -0
  235. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_list-group.scss +0 -0
  236. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_media.scss +0 -0
  237. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_mixins.scss +0 -0
  238. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_modals.scss +0 -0
  239. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_navbar.scss +0 -0
  240. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_navs.scss +0 -0
  241. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_normalize.scss +0 -0
  242. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_pager.scss +0 -0
  243. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_pagination.scss +0 -0
  244. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_panels.scss +0 -0
  245. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_popovers.scss +0 -0
  246. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_print.scss +0 -0
  247. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_progress-bars.scss +0 -0
  248. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_responsive-embed.scss +0 -0
  249. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_responsive-utilities.scss +0 -0
  250. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_scaffolding.scss +0 -0
  251. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_tables.scss +0 -0
  252. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_theme.scss +0 -0
  253. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_thumbnails.scss +0 -0
  254. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_tooltip.scss +0 -0
  255. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_type.scss +0 -0
  256. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_utilities.scss +0 -0
  257. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_variables.scss +0 -0
  258. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/_wells.scss +0 -0
  259. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_alerts.scss +0 -0
  260. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_background-variant.scss +0 -0
  261. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_border-radius.scss +0 -0
  262. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_breakpoints.scss +0 -0
  263. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_buttons.scss +0 -0
  264. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_center-block.scss +0 -0
  265. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_clearfix.scss +0 -0
  266. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_forms.scss +0 -0
  267. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_gradients.scss +0 -0
  268. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_grid-framework.scss +0 -0
  269. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_grid.scss +0 -0
  270. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_hide-text.scss +0 -0
  271. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_image.scss +0 -0
  272. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_labels.scss +0 -0
  273. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_list-group.scss +0 -0
  274. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_nav-divider.scss +0 -0
  275. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_nav-vertical-align.scss +0 -0
  276. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_opacity.scss +0 -0
  277. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_pagination.scss +0 -0
  278. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_panels.scss +0 -0
  279. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_progress-bar.scss +0 -0
  280. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_reset-filter.scss +0 -0
  281. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_reset-text.scss +0 -0
  282. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_resize.scss +0 -0
  283. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_responsive-visibility.scss +0 -0
  284. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_size.scss +0 -0
  285. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_tab-focus.scss +0 -0
  286. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_table-row.scss +0 -0
  287. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_text-emphasis.scss +0 -0
  288. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_text-overflow.scss +0 -0
  289. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_text-truncate.scss +0 -0
  290. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap/mixins/_vendor-prefixes.scss +0 -0
  291. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap.scss +0 -0
  292. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_mixins/_all.scss +0 -0
  293. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_mixins/_border-radius.scss +0 -0
  294. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_mixins/_box-shadow.scss +0 -0
  295. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_mixins/_hover.scss +0 -0
  296. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_mixins/_nav-divider.scss +0 -0
  297. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_partials/_dropdown.scss +0 -0
  298. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_partials/_glyphicons.scss +0 -0
  299. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_partials/_grid.scss +0 -0
  300. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_partials/_variables.scss +0 -0
  301. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_align.scss +0 -0
  302. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_background.scss +0 -0
  303. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_borders.scss +0 -0
  304. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_clearfix.scss +0 -0
  305. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_cursor.scss +0 -0
  306. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_display.scss +0 -0
  307. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_flex.scss +0 -0
  308. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_float.scss +0 -0
  309. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_position.scss +0 -0
  310. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_screenreaders.scss +0 -0
  311. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_sizing.scss +0 -0
  312. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_spacing.scss +0 -0
  313. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_text.scss +0 -0
  314. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/bootstrap_utilities/_visibility.scss +0 -0
  315. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/colorbox.scss +0 -0
  316. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_all.scss +0 -0
  317. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_animation.scss +0 -0
  318. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_breakpoints.scss +0 -0
  319. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_card_constants.scss +0 -0
  320. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_colours.scss +0 -0
  321. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_homepage_constants.scss +0 -0
  322. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_levels.scss +0 -0
  323. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_mixins.scss +0 -0
  324. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/modules/_spacing.scss +0 -0
  325. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_banners.scss +0 -0
  326. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_base.scss +0 -0
  327. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_buttons.scss +0 -0
  328. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_carousel.scss +0 -0
  329. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_footer.scss +0 -0
  330. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_forms.scss +0 -0
  331. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_grids.scss +0 -0
  332. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_header.scss +0 -0
  333. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_images.scss +0 -0
  334. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_popup.scss +0 -0
  335. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_progress-bars.scss +0 -0
  336. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_subnavs.scss +0 -0
  337. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_tables.scss +0 -0
  338. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_text.scss +0 -0
  339. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_ui-dialog.scss +0 -0
  340. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_utils.scss +0 -0
  341. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/partials/_videos.scss +0 -0
  342. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/sass/styles.scss +0 -0
  343. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
  344. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/static/portal/video/code for life .pdf +0 -0
  345. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/__init__.py +0 -0
  346. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/about.py +0 -0
  347. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/coding_club.py +0 -0
  348. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/help_and_support.py +0 -0
  349. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/home_learning.py +0 -0
  350. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/materials.py +0 -0
  351. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/play.py +0 -0
  352. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/student_aimmo_dashboard.py +0 -0
  353. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/teach.py +0 -0
  354. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/strings/teacher_resources.py +0 -0
  355. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/403.html +0 -0
  356. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/404.html +0 -0
  357. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/500.html +0 -0
  358. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/captcha/includes/js_v2_invisible.html +0 -0
  359. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/captcha/widget_v2_invisible.html +0 -0
  360. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/email.html +0 -0
  361. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/email.txt +0 -0
  362. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/about.html +0 -0
  363. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/base.html +0 -0
  364. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/base_no_userprofile.html +0 -0
  365. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/coding_club.html +0 -0
  366. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/contribute.html +0 -0
  367. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/dotmailer_consent_form.html +0 -0
  368. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/email_invitation_sent.html +0 -0
  369. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/email_style_template.html +0 -0
  370. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/email_verification_failed.html +0 -0
  371. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/email_verification_needed.html +0 -0
  372. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/form_shapes.html +0 -0
  373. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/getinvolved.html +0 -0
  374. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/home.html +0 -0
  375. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/home_learning.html +0 -0
  376. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/locked_out.html +0 -0
  377. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/locked_out_school_student.html +0 -0
  378. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/login/independent_student.html +0 -0
  379. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/login/student.html +0 -0
  380. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/login/student_class_code.html +0 -0
  381. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/login/teacher.html +0 -0
  382. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/mouseflow.html +0 -0
  383. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/aimmo_games_table.html +0 -0
  384. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/banner.html +0 -0
  385. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/benefits.html +0 -0
  386. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/card_list.html +0 -0
  387. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/character_list.html +0 -0
  388. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/delete_popup.html +0 -0
  389. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/footer.html +0 -0
  390. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/header.html +0 -0
  391. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/headline.html +0 -0
  392. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/hero_card.html +0 -0
  393. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/info_popup.html +0 -0
  394. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/invite_admin_teacher.html +0 -0
  395. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/popup.html +0 -0
  396. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/register_newsletter_tickbox.html +0 -0
  397. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/screentime_popup.html +0 -0
  398. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/service_unavailable_popup.html +0 -0
  399. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/session_popup.html +0 -0
  400. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/teacher_non_dashboard_subnav.html +0 -0
  401. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/partials/teacher_non_dashboard_subnav_account.html +0 -0
  402. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play/independent_student_dashboard.html +0 -0
  403. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play/student_aimmo_dashboard.html +0 -0
  404. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play/student_dashboard.html +0 -0
  405. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play/student_edit_account.html +0 -0
  406. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play/student_join_organisation.html +0 -0
  407. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/play.html +0 -0
  408. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/privacy_notice.html +0 -0
  409. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/register.html +0 -0
  410. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/reset_password.html +0 -0
  411. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/reset_password_confirm.html +0 -0
  412. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/reset_password_done.html +0 -0
  413. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/reset_password_email_sent.html +0 -0
  414. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/tag_manager/tag_manager_body.html +0 -0
  415. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/tag_manager/tag_manager_head.html +0 -0
  416. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/base_registering.html +0 -0
  417. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/class.html +0 -0
  418. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/dashboard.html +0 -0
  419. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/invited.html +0 -0
  420. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/onboarding_classes.html +0 -0
  421. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/onboarding_print.html +0 -0
  422. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/onboarding_school.html +0 -0
  423. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/onboarding_students.html +0 -0
  424. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_add_external_student.html +0 -0
  425. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_added_external_student.html +0 -0
  426. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -0
  427. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_dismiss_students.html +0 -0
  428. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_edit_class.html +0 -0
  429. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_edit_student.html +0 -0
  430. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_move_all_classes.html +0 -0
  431. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_move_students.html +0 -0
  432. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach/teacher_move_students_to_class.html +0 -0
  433. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/teach.html +0 -0
  434. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/portal/terms.html +0 -0
  435. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_base.html +0 -0
  436. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_wizard_actions.html +0 -0
  437. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_wizard_actions_enable_2fa.html +0 -0
  438. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_wizard_actions_submit.html +0 -0
  439. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_wizard_forms.html +0 -0
  440. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/_wizard_forms_token.html +0 -0
  441. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/backup_token.html +0 -0
  442. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/core/backup_tokens.html +0 -0
  443. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/core/login.html +0 -0
  444. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/core/setup.html +0 -0
  445. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/core/setup_complete.html +0 -0
  446. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/profile/disable.html +0 -0
  447. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/profile/profile.html +0 -0
  448. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templates/two_factor/setup_wizard_token.html +0 -0
  449. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/__init__.py +0 -0
  450. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/app_tags.py +0 -0
  451. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/banner_tags.py +0 -0
  452. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/benefits_tags.py +0 -0
  453. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/card_list_tags.py +0 -0
  454. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/character_list_tags.py +0 -0
  455. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/future.py +0 -0
  456. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/headline_tags.py +0 -0
  457. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/hero_card_tags.py +0 -0
  458. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/templatetags/table_tags.py +0 -0
  459. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/__init__.py +0 -0
  460. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/base_test.py +0 -0
  461. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/conftest.py +0 -0
  462. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/__init__.py +0 -0
  463. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_make_portaladmin_teacher.py +0 -0
  464. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_preview_user_remove.py +0 -0
  465. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_preview_users.py +0 -0
  466. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_remove_front_page_news.py +0 -0
  467. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_remove_guardian.py +0 -0
  468. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_use_common_models.py +0 -0
  469. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/migrations/test_migration_verify_portaladmin.py +0 -0
  470. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/__init__.py +0 -0
  471. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/__init__.py +0 -0
  472. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/admin/__init__.py +0 -0
  473. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -0
  474. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/admin/admin_data_page.py +0 -0
  475. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/admin/admin_map_page.py +0 -0
  476. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/base_page.py +0 -0
  477. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/email_verification_needed_page.py +0 -0
  478. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/forbidden_page.py +0 -0
  479. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/game_page.py +0 -0
  480. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/home_page.py +0 -0
  481. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/independent_login_page.py +0 -0
  482. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -0
  483. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/password_reset_form_page.py +0 -0
  484. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/password_reset_page.py +0 -0
  485. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play/__init__.py +0 -0
  486. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play/account_page.py +0 -0
  487. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play/dashboard_page.py +0 -0
  488. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play/join_school_or_club_page.py +0 -0
  489. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play/play_base_page.py +0 -0
  490. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/play_page.py +0 -0
  491. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/resources_page.py +0 -0
  492. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/signup_page.py +0 -0
  493. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/student_login_class_code.py +0 -0
  494. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/student_login_page.py +0 -0
  495. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/__init__.py +0 -0
  496. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +0 -0
  497. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +0 -0
  498. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/class_page.py +0 -0
  499. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/dashboard_page.py +0 -0
  500. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/dismiss_students_page.py +0 -0
  501. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/edit_student_page.py +0 -0
  502. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/move_class_page.py +0 -0
  503. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/move_classes_page.py +0 -0
  504. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +0 -0
  505. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/move_students_page.py +0 -0
  506. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +0 -0
  507. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +0 -0
  508. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +0 -0
  509. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/onboarding_students_page.py +0 -0
  510. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teach/teach_base_page.py +0 -0
  511. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/pageObjects/portal/teacher_login_page.py +0 -0
  512. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/selenium_test_case.py +0 -0
  513. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/snapshots/__init__.py +0 -0
  514. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/snapshots/snap_test_partials.py +0 -0
  515. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_2FA.py +0 -0
  516. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_admin.py +0 -0
  517. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_aimmo_dashboards.py +0 -0
  518. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_api.py +0 -0
  519. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_captcha_forms.py +0 -0
  520. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_class.py +0 -0
  521. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_daily_activities.py +0 -0
  522. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_emails.py +0 -0
  523. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_helper_methods.py +0 -0
  524. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_invite_teacher.py +0 -0
  525. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_middleware.py +0 -0
  526. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_newsletter_footer.py +0 -0
  527. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_organisation.py +0 -0
  528. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_partials.py +0 -0
  529. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_ratelimit.py +0 -0
  530. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_school_student.py +0 -0
  531. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_security.py +0 -0
  532. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_teacher.py +0 -0
  533. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/test_teacher_student.py +0 -0
  534. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/utils/__init__.py +0 -0
  535. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/utils/aimmo_games.py +0 -0
  536. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/utils/classes.py +0 -0
  537. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/tests/utils/messages.py +0 -0
  538. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/urls.py +0 -0
  539. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/__init__.py +0 -0
  540. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/about.py +0 -0
  541. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/admin.py +0 -0
  542. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/aimmo/__init__.py +0 -0
  543. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/aimmo/dashboard.py +0 -0
  544. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/api.py +0 -0
  545. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/cron/__init__.py +0 -0
  546. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/cron/user.py +0 -0
  547. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/dotmailer.py +0 -0
  548. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/email.py +0 -0
  549. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/legal.py +0 -0
  550. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/login/__init__.py +0 -0
  551. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/login/independent_student.py +0 -0
  552. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/login/student.py +0 -0
  553. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/login/teacher.py +0 -0
  554. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/organisation.py +0 -0
  555. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/play_landing_page.py +0 -0
  556. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/student/__init__.py +0 -0
  557. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/teach.py +0 -0
  558. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/teacher/__init__.py +0 -0
  559. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/teacher/teach.py +0 -0
  560. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/two_factor/__init__.py +0 -0
  561. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/two_factor/core.py +0 -0
  562. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/two_factor/form.py +0 -0
  563. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/views/two_factor/profile.py +0 -0
  564. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/portal/wsgi.py +0 -0
  565. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/pyproject.toml +0 -0
  566. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/setup.cfg +0 -0
  567. {codeforlife-portal-6.43.1 → codeforlife-portal-6.43.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 6.43.1
3
+ Version: 6.43.3
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.8
6
6
  Classifier: Framework :: Django
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 6.43.1
3
+ Version: 6.43.3
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.8
6
6
  Classifier: Framework :: Django
@@ -17,7 +17,7 @@ django-classy-tags==2.0.0
17
17
  libsass==0.23.0
18
18
  phonenumbers==8.12.12
19
19
  more-itertools==8.7.0
20
- cfl-common==6.43.1
20
+ cfl-common==6.43.3
21
21
  django-ratelimit==3.0.1
22
22
  django-preventconcurrentlogins==0.8.2
23
23
  django-csp==3.7
@@ -0,0 +1 @@
1
+ __version__ = "6.43.3"
@@ -16,7 +16,7 @@ from common.tests.utils.student import (
16
16
  create_independent_student,
17
17
  create_independent_student_directly,
18
18
  create_school_student_directly,
19
- signup_duplicate_independent_student_fail,
19
+ generate_independent_student_details,
20
20
  verify_email,
21
21
  )
22
22
  from common.tests.utils.teacher import signup_teacher_directly
@@ -169,7 +169,8 @@ class TestIndependentStudent(TestCase):
169
169
 
170
170
  # Class for Selenium tests. We plan to replace these and turn them into Cypress tests
171
171
  class TestIndependentStudentFrontend(BaseTest):
172
- def test_delete_indy_account(self):
172
+ @patch("portal.views.registration.send_dotdigital_email")
173
+ def test_delete_indy_account(self, mock_send_dotdigital_email: Mock):
173
174
  page = self.go_to_homepage()
174
175
  page, _, _, email, password = create_independent_student(page)
175
176
  page = page.independent_student_login(email, password)
@@ -214,27 +215,37 @@ class TestIndependentStudentFrontend(BaseTest):
214
215
  assert not User.objects.get(id=user_id).is_active
215
216
 
216
217
  # check if email has been sent
217
- assert len(mail.outbox) == 1
218
+ mock_send_dotdigital_email.assert_called_once_with(campaign_ids["delete_account"], ANY)
218
219
 
219
220
  def test_signup_without_newsletter(self):
220
221
  page = self.go_to_homepage()
221
222
  page, _, _, _, _ = create_independent_student(page)
222
223
  assert is_email_verified_message_showing(self.selenium)
223
224
 
224
- def test_signup_duplicate_email_failure(self):
225
+ @patch("portal.views.home.send_dotdigital_email")
226
+ def test_signup_duplicate_email_failure(self, mock_send_dotdigital_email):
225
227
  page = self.go_to_homepage()
226
228
  page, _, _, email, _ = create_independent_student(page)
227
229
  assert is_email_verified_message_showing(self.selenium)
228
230
 
229
- page = self.go_to_homepage()
230
- page, _, _, _, _ = signup_duplicate_independent_student_fail(page, duplicate_email=email)
231
+ page = self.go_to_homepage().go_to_signup_page()
232
+
233
+ name, username, email_address, password = generate_independent_student_details()
234
+ page = page.independent_student_signup(name, email, password=password, confirm_password=password)
235
+ page = page.return_to_home_page()
236
+
237
+ mock_send_dotdigital_email.assert_called_once_with(
238
+ campaign_ids["user_already_registered"], ANY, personalization_values=ANY
239
+ )
240
+
241
+ login_link = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["LOGIN_URL"]
231
242
 
232
- assert len(mail.outbox) == 1
233
- assert mail.outbox[0].subject == "Duplicate account"
243
+ page = email_utils.follow_duplicate_account_link_to_login(page, login_link, "independent")
234
244
 
235
245
  assert self.is_login_page(page)
236
246
 
237
- def test_signup_duplicate_email_with_teacher(self):
247
+ @patch("portal.views.home.send_dotdigital_email")
248
+ def test_signup_duplicate_email_with_teacher(self, mock_send_dotdigital_email: Mock):
238
249
  teacher_email, _ = signup_teacher_directly()
239
250
 
240
251
  page = self.go_to_homepage()
@@ -247,8 +258,9 @@ class TestIndependentStudentFrontend(BaseTest):
247
258
 
248
259
  page.return_to_home_page()
249
260
 
250
- assert len(mail.outbox) == 1
251
- assert mail.outbox[0].subject == "Duplicate account"
261
+ mock_send_dotdigital_email.assert_called_once_with(
262
+ campaign_ids["user_already_registered"], ANY, personalization_values=ANY
263
+ )
252
264
 
253
265
  def test_login_failure(self):
254
266
  page = self.go_to_homepage()
@@ -572,7 +572,8 @@ class TestViews(TestCase):
572
572
  assert response.status_code == 200
573
573
  assert response.context_data == EXPECTED_DATA_WITH_KURONO_GAME
574
574
 
575
- def test_delete_account(self):
575
+ @patch("portal.views.registration.send_dotdigital_email")
576
+ def test_delete_account(self, mock_send_dotdigital_email: Mock):
576
577
  email, password = signup_teacher_directly()
577
578
  u = User.objects.get(email=email)
578
579
  usrid = u.id
@@ -593,7 +594,7 @@ class TestViews(TestCase):
593
594
  response = c.post(url, {"password": "wrongPassword"})
594
595
 
595
596
  assert response.status_code == 302
596
- assert response.url == reverse("dashboard")
597
+ mock_send_dotdigital_email.assert_not_called()
597
598
 
598
599
  # user has not been anonymised
599
600
  u = User.objects.get(email=email)
@@ -604,6 +605,7 @@ class TestViews(TestCase):
604
605
  response = c.post(url, {"password": password, "unsubscribe_newsletter": "on"})
605
606
 
606
607
  assert response.status_code == 302
608
+ mock_send_dotdigital_email.assert_called_once()
607
609
  assert response.url == reverse("home")
608
610
 
609
611
  # user has been anonymised
@@ -611,7 +613,10 @@ class TestViews(TestCase):
611
613
  assert u.first_name == "Deleted"
612
614
  assert not u.is_active
613
615
 
614
- def test_delete_account_admin(self):
616
+ assert c.login(username=email, password=password) == False
617
+
618
+ @patch("portal.views.registration.send_dotdigital_email")
619
+ def test_delete_account_admin(self, mock_send_dotdigital_email: Mock):
615
620
  """test the passing of admin role after deletion of an admin account"""
616
621
 
617
622
  email1, password1 = signup_teacher_directly()
@@ -666,6 +671,7 @@ class TestViews(TestCase):
666
671
  # delete teacher1 account
667
672
  url = reverse("delete_account")
668
673
  c.post(url, {"password": password1})
674
+ mock_send_dotdigital_email.assert_called_once()
669
675
 
670
676
  # user has been anonymised
671
677
  u = User.objects.get(id=usrid1)
@@ -706,6 +712,7 @@ class TestViews(TestCase):
706
712
  # now delete teacher3 account
707
713
  url = reverse("delete_account")
708
714
  c.post(url, {"password": password3})
715
+ self.assertEqual(mock_send_dotdigital_email.call_count, 2)
709
716
 
710
717
  # 2 teachers left
711
718
  teachers = Teacher.objects.filter(school=school).order_by("new_user__last_name", "new_user__first_name")
@@ -738,6 +745,7 @@ class TestViews(TestCase):
738
745
 
739
746
  url = reverse("delete_account")
740
747
  c.post(url, {"password": password2})
748
+ self.assertEqual(mock_send_dotdigital_email.call_count, 3)
741
749
 
742
750
  # school should be anonymised
743
751
  school = School._base_manager.get(id=school_id)
@@ -1,13 +1,13 @@
1
1
  import logging
2
2
  import math
3
3
 
4
- from common import email_messages
5
4
  from common.helpers.emails import (
6
5
  NOTIFICATION_EMAIL,
7
6
  send_email,
8
7
  send_verification_email,
9
8
  )
10
- from common.models import Student, Teacher, DynamicElement, TotalActivity
9
+ from common.mail import campaign_ids, send_dotdigital_email
10
+ from common.models import DynamicElement, Student, Teacher, TotalActivity
11
11
  from common.permissions import logged_in_as_student, logged_in_as_teacher
12
12
  from common.utils import _using_two_factor
13
13
  from django.contrib import messages as messages
@@ -34,8 +34,7 @@ from portal.helpers.ratelimit import (
34
34
  from portal.strings.coding_club import CODING_CLUB_BANNER
35
35
  from portal.strings.home_learning import HOME_LEARNING_BANNER
36
36
  from portal.templatetags.app_tags import cloud_storage
37
- from portal.views.teacher.teach import DownloadType
38
- from portal.views.teacher.teach import count_student_pack_downloads_click
37
+ from portal.views.teacher.teach import DownloadType, count_student_pack_downloads_click
39
38
 
40
39
  LOGGER = logging.getLogger(__name__)
41
40
 
@@ -126,7 +125,7 @@ def process_signup_form(request, data):
126
125
  email = data["teacher_email"]
127
126
 
128
127
  if email and User.objects.filter(email=email).exists():
129
- email_message = email_messages.userAlreadyRegisteredEmail(request, email)
128
+
130
129
  is_email_ratelimited = is_ratelimited(
131
130
  request=request,
132
131
  group=RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP,
@@ -136,12 +135,13 @@ def process_signup_form(request, data):
136
135
  )
137
136
 
138
137
  if not is_email_ratelimited:
139
- send_email(
140
- NOTIFICATION_EMAIL,
138
+ send_dotdigital_email(
139
+ campaign_ids["user_already_registered"],
141
140
  [email],
142
- email_message["subject"],
143
- email_message["message"],
144
- email_message["subject"],
141
+ personalization_values={
142
+ "EMAIL": email,
143
+ "LOGIN_URL": request.build_absolute_uri(reverse("teacher_login")),
144
+ },
145
145
  )
146
146
  else:
147
147
  LOGGER.warn(f"Ratelimit teacher {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
@@ -164,7 +164,6 @@ def process_independent_student_signup_form(request, data):
164
164
  email = data["email"]
165
165
 
166
166
  if email and User.objects.filter(email=email).exists():
167
- email_message = email_messages.userAlreadyRegisteredEmail(request, email, is_independent_student=True)
168
167
  is_email_ratelimited = is_ratelimited(
169
168
  request=request,
170
169
  group=RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP,
@@ -174,12 +173,13 @@ def process_independent_student_signup_form(request, data):
174
173
  )
175
174
 
176
175
  if not is_email_ratelimited:
177
- send_email(
178
- NOTIFICATION_EMAIL,
176
+ send_dotdigital_email(
177
+ campaign_ids["user_already_registered"],
179
178
  [email],
180
- email_message["subject"],
181
- email_message["message"],
182
- email_message["subject"],
179
+ personalization_values={
180
+ "EMAIL": email,
181
+ "LOGIN_URL": request.build_absolute_uri(reverse("independent_student_login")),
182
+ },
183
183
  )
184
184
  else:
185
185
  LOGGER.warning(f"Ratelimit independent {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
@@ -1,24 +1,21 @@
1
1
  import ast
2
2
  import re
3
-
4
- from common.email_messages import accountDeletionEmail
5
- from portal.views.login import has_user_lockout_expired
6
-
7
- from django.contrib.auth.models import User
8
3
  from datetime import datetime
4
+
9
5
  from common.helpers.emails import (
10
- delete_contact,
11
6
  NOTIFICATION_EMAIL,
12
7
  PASSWORD_RESET_EMAIL,
8
+ delete_contact,
13
9
  send_email,
14
10
  )
15
- from common.models import Teacher, Student, DailyActivity
16
- from common.permissions import not_logged_in, not_fully_logged_in
17
-
11
+ from common.mail import campaign_ids, send_dotdigital_email
12
+ from common.models import DailyActivity, Student, Teacher
13
+ from common.permissions import not_fully_logged_in, not_logged_in
18
14
  from django.contrib import messages as messages
19
15
  from django.contrib.auth import get_user_model
20
- from django.contrib.auth.decorators import user_passes_test, login_required
16
+ from django.contrib.auth.decorators import login_required, user_passes_test
21
17
  from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
18
+ from django.contrib.auth.models import User
22
19
  from django.contrib.auth.tokens import default_token_generator
23
20
  from django.http import HttpResponseRedirect
24
21
  from django.shortcuts import render
@@ -35,14 +32,15 @@ from django.views.decorators.http import require_POST
35
32
  from deploy import captcha
36
33
  from portal import app_settings
37
34
  from portal.forms.registration import (
38
- TeacherPasswordResetForm,
39
- TeacherPasswordResetSetPasswordForm,
40
35
  StudentPasswordResetForm,
41
36
  StudentPasswordResetSetPasswordForm,
37
+ TeacherPasswordResetForm,
38
+ TeacherPasswordResetSetPasswordForm,
42
39
  )
43
40
  from portal.helpers.captcha import remove_captcha_from_form
44
41
  from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
45
42
  from portal.views.api import anonymise
43
+ from portal.views.login import has_user_lockout_expired
46
44
 
47
45
 
48
46
  @user_passes_test(not_logged_in, login_url=reverse_lazy("home"))
@@ -309,13 +307,6 @@ def delete_account(request):
309
307
  delete_contact(email)
310
308
 
311
309
  # send confirmation email
312
- message = accountDeletionEmail(request)
313
- send_email(
314
- NOTIFICATION_EMAIL,
315
- [email],
316
- message["subject"],
317
- message["message"],
318
- message["title"],
319
- )
310
+ send_dotdigital_email(campaign_ids["delete_account"], [email])
320
311
 
321
312
  return HttpResponseRedirect(reverse_lazy("home"))
@@ -1,5 +1,9 @@
1
- from common.email_messages import accountDeletionEmail
2
- from common.helpers.emails import NOTIFICATION_EMAIL, delete_contact, send_email, update_indy_email
1
+ from common.helpers.emails import (
2
+ NOTIFICATION_EMAIL,
3
+ delete_contact,
4
+ send_email,
5
+ update_indy_email,
6
+ )
3
7
  from common.models import Student
4
8
  from common.permissions import logged_in_as_student
5
9
  from django.contrib import messages as messages
@@ -7,17 +11,15 @@ from django.contrib.auth import logout
7
11
  from django.contrib.auth.decorators import login_required, user_passes_test
8
12
  from django.contrib.auth.mixins import LoginRequiredMixin
9
13
  from django.http import HttpResponseRedirect
14
+ from django.shortcuts import render
10
15
  from django.urls import reverse_lazy
11
16
  from django.views.generic.edit import FormView
12
- from django.shortcuts import render
13
17
 
14
- from portal.forms.play import StudentEditAccountForm, IndependentStudentEditAccountForm
18
+ from portal.forms.play import IndependentStudentEditAccountForm, StudentEditAccountForm
15
19
  from portal.forms.registration import DeleteAccountForm
16
-
17
20
  from portal.helpers.password import check_update_password
18
21
  from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
19
22
  from portal.views.api import anonymise
20
- from django.contrib import messages as messages
21
23
 
22
24
 
23
25
  def _get_form(self, form_class):
@@ -1,7 +1,7 @@
1
1
  from typing import Any, Dict, List, Optional
2
2
 
3
- from common import email_messages
4
3
  from common.helpers.emails import NOTIFICATION_EMAIL, send_email
4
+ from common.mail import campaign_ids, send_dotdigital_email
5
5
  from common.models import Student
6
6
  from common.permissions import (
7
7
  logged_in_as_independent_student,
@@ -22,9 +22,7 @@ from game.models import Attempt, Level
22
22
  from portal.forms.play import StudentJoinOrganisationForm
23
23
 
24
24
 
25
- class SchoolStudentDashboard(
26
- LoginRequiredNoErrorMixin, UserPassesTestMixin, TemplateView
27
- ):
25
+ class SchoolStudentDashboard(LoginRequiredNoErrorMixin, UserPassesTestMixin, TemplateView):
28
26
  template_name = "portal/play/student_dashboard.html"
29
27
  login_url = reverse_lazy("student_login_access_code")
30
28
 
@@ -50,16 +48,10 @@ class SchoolStudentDashboard(
50
48
  custom_levels = student.new_user.shared.filter(owner=teacher)
51
49
 
52
50
  if custom_levels:
53
- custom_levels_data = _compute_rapid_router_scores(
54
- student, custom_levels
55
- )
51
+ custom_levels_data = _compute_rapid_router_scores(student, custom_levels)
56
52
 
57
- context_data["total_custom_score"] = custom_levels_data[
58
- "total_score"
59
- ]
60
- context_data["total_custom_available_score"] = custom_levels_data[
61
- "total_available_score"
62
- ]
53
+ context_data["total_custom_score"] = custom_levels_data["total_score"]
54
+ context_data["total_custom_available_score"] = custom_levels_data["total_available_score"]
63
55
 
64
56
  # Get Kurono game info if the class has a game linked to it
65
57
  aimmo_game = klass.active_game
@@ -72,9 +64,7 @@ class SchoolStudentDashboard(
72
64
  return context_data
73
65
 
74
66
 
75
- class IndependentStudentDashboard(
76
- LoginRequiredNoErrorMixin, UserPassesTestMixin, TemplateView, FormView
77
- ):
67
+ class IndependentStudentDashboard(LoginRequiredNoErrorMixin, UserPassesTestMixin, TemplateView, FormView):
78
68
  template_name = "portal/play/independent_student_dashboard.html"
79
69
  login_url = reverse_lazy("independent_student_login")
80
70
 
@@ -91,9 +81,7 @@ class IndependentStudentDashboard(
91
81
  )
92
82
 
93
83
 
94
- def _compute_rapid_router_scores(
95
- student: Student, levels: List[Level] or QuerySet
96
- ) -> Dict[str, int]:
84
+ def _compute_rapid_router_scores(student: Student, levels: List[Level] or QuerySet) -> Dict[str, int]:
97
85
  """
98
86
  Finds Rapid Router progress and score data for a specific student and a specific
99
87
  set of levels. This is used to show quick score data to the student on their
@@ -112,9 +100,9 @@ def _compute_rapid_router_scores(
112
100
  num_completed = num_top_scores = total_available_score = 0
113
101
  total_score = 0.0
114
102
  # Get a QuerySet of best attempts for each level
115
- best_attempts = Attempt.objects.filter(
116
- level__in=levels, student=student, is_best_attempt=True
117
- ).select_related("level")
103
+ best_attempts = Attempt.objects.filter(level__in=levels, student=student, is_best_attempt=True).select_related(
104
+ "level"
105
+ )
118
106
 
119
107
  for level in levels:
120
108
  total_available_score += _get_max_score_for_level(level)
@@ -122,10 +110,7 @@ def _compute_rapid_router_scores(
122
110
  # For each level, compare best attempt's score with level's max score and
123
111
  # increment variables as needed
124
112
  if best_attempts:
125
- attempts_dict = {
126
- best_attempt.level.id: best_attempt
127
- for best_attempt in best_attempts
128
- }
113
+ attempts_dict = {best_attempt.level.id: best_attempt for best_attempt in best_attempts}
129
114
  for level in levels:
130
115
  attempt = attempts_dict.get(level.id)
131
116
 
@@ -155,12 +140,7 @@ def _get_max_score_for_level(level: Level) -> int:
155
140
  """
156
141
  return (
157
142
  10
158
- if level.id > 12
159
- and (
160
- level.disable_route_score
161
- or level.disable_algorithm_score
162
- or not level.episode
163
- )
143
+ if level.id > 12 and (level.disable_route_score or level.disable_algorithm_score or not level.episode)
164
144
  else 20
165
145
  )
166
146
 
@@ -207,31 +187,23 @@ def process_join_organisation_form(request_form, request, student):
207
187
  student.pending_class_request = request_form.klass
208
188
  student.save()
209
189
 
210
- email_message = email_messages.studentJoinRequestSentEmail(
211
- request,
212
- request_form.klass.teacher.school.name,
213
- request_form.klass.access_code,
214
- )
215
- send_email(
216
- NOTIFICATION_EMAIL,
190
+ send_dotdigital_email(
191
+ campaign_ids["student_join_request_sent"],
217
192
  [student.new_user.email],
218
- email_message["subject"],
219
- email_message["message"],
220
- email_message["subject"],
193
+ personalization_values={
194
+ "SCHOOL_CLUB_NAME": request_form.klass.teacher.school.name,
195
+ "ACCESS_CODE": request_form.klass.access_code,
196
+ },
221
197
  )
222
198
 
223
- email_message = email_messages.studentJoinRequestNotifyEmail(
224
- request,
225
- student.new_user.username,
226
- student.new_user.email,
227
- student.pending_class_request.access_code,
228
- )
229
- send_email(
230
- NOTIFICATION_EMAIL,
199
+ send_dotdigital_email(
200
+ campaign_ids["student_join_request_notification"],
231
201
  [student.pending_class_request.teacher.new_user.email],
232
- email_message["subject"],
233
- email_message["message"],
234
- email_message["subject"],
202
+ personalization_values={
203
+ "USERNAME": student.new_user.username,
204
+ "EMAIL": student.new_user.email,
205
+ "ACCESS_CODE": student.pending_class_request.access_code,
206
+ },
235
207
  )
236
208
 
237
209
  messages.success(
@@ -1,7 +1,6 @@
1
1
  from datetime import timedelta
2
2
  from uuid import uuid4
3
3
 
4
- from common import email_messages
5
4
  from common.helpers.emails import (
6
5
  INVITE_FROM,
7
6
  NOTIFICATION_EMAIL,
@@ -167,9 +166,21 @@ def dashboard_teacher_view(request, is_admin):
167
166
  )
168
167
 
169
168
  account_exists = User.objects.filter(email=invited_teacher_email).exists()
170
- message = email_messages.inviteTeacherEmail(request, school.name, token, account_exists)
171
- send_email(
172
- INVITE_FROM, [invited_teacher_email], message["subject"], message["message"], message["subject"]
169
+
170
+ registration_link = (
171
+ f"{request.build_absolute_uri(reverse('invited_teacher', kwargs={'token': token}))} "
172
+ )
173
+
174
+ campaign_id = (
175
+ campaign_ids["invite_teacher_with_account"]
176
+ if account_exists
177
+ else campaign_ids["invite_teacher_without_account"]
178
+ )
179
+
180
+ send_dotdigital_email(
181
+ campaign_id,
182
+ [invited_teacher_email],
183
+ personalization_values={"SCHOOL_NAME": school.name, "REGISTRATION_LINK": registration_link},
173
184
  )
174
185
 
175
186
  messages.success(
@@ -375,14 +386,10 @@ def organisation_kick(request, pk):
375
386
 
376
387
  messages.success(request, success_message)
377
388
 
378
- emailMessage = email_messages.kickedEmail(request, user.school.name)
379
-
380
- send_email(
381
- NOTIFICATION_EMAIL,
389
+ send_dotdigital_email(
390
+ campaign_ids["teacher_released"],
382
391
  [teacher.new_user.email],
383
- emailMessage["subject"],
384
- emailMessage["message"],
385
- emailMessage["subject"],
392
+ personalization_values={"SCHOOL_CLUB_NAME": user.school.name},
386
393
  )
387
394
 
388
395
  return HttpResponseRedirect(reverse_lazy("dashboard"))
@@ -537,15 +544,13 @@ def teacher_reject_student_request(request, pk):
537
544
 
538
545
  check_student_request_can_be_handled(request, student)
539
546
 
540
- emailMessage = email_messages.studentJoinRequestRejectedEmail(
541
- request, student.pending_class_request.teacher.school.name, student.pending_class_request.access_code
542
- )
543
- send_email(
544
- NOTIFICATION_EMAIL,
547
+ send_dotdigital_email(
548
+ campaign_ids["student_join_request_rejected"],
545
549
  [student.new_user.email],
546
- emailMessage["subject"],
547
- emailMessage["message"],
548
- emailMessage["subject"],
550
+ personalization_values={
551
+ "SCHOOL_CLUB_NAME": student.pending_class_request.teacher.school.name,
552
+ "ACCESS_CODE": student.pending_class_request.access_code,
553
+ },
549
554
  )
550
555
 
551
556
  student.pending_class_request = None
@@ -591,10 +596,21 @@ def resend_invite_teacher(request, token):
591
596
  teacher = Teacher.objects.filter(id=invite.from_teacher.id)[0]
592
597
 
593
598
  messages.success(request, "Teacher re-invited!")
594
- message = email_messages.inviteTeacherEmail(request, invite.school, token, not (invite.is_expired))
595
- send_email(
596
- INVITE_FROM, [invite.invited_teacher_email], message["subject"], message["message"], message["subject"]
599
+
600
+ registration_link = f"{request.build_absolute_uri(reverse('invited_teacher', kwargs={'token': token}))} "
601
+
602
+ campaign_id = (
603
+ campaign_ids["invite_teacher_with_account"]
604
+ if teacher.exists()
605
+ else campaign_ids["invite_teacher_without_account"]
597
606
  )
607
+
608
+ send_dotdigital_email(
609
+ campaign_id,
610
+ [invite.invited_teacher_email],
611
+ personalization_values={"SCHOOL_NAME": invite.school, "REGISTRATION_LINK": registration_link},
612
+ )
613
+
598
614
  return HttpResponseRedirect(reverse_lazy("dashboard"))
599
615
 
600
616
 
@@ -1 +0,0 @@
1
- __version__ = "6.43.1"