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.
- {codeforlife-portal-7.4.9/codeforlife_portal.egg-info → codeforlife-portal-8.0.1}/PKG-INFO +1 -1
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1/codeforlife_portal.egg-info}/PKG-INFO +1 -1
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/SOURCES.txt +2 -2
- codeforlife-portal-8.0.1/codeforlife_portal.egg-info/requires.txt +14 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/security.py +4 -5
- codeforlife-portal-8.0.1/portal/__init__.py +1 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/admin.py +26 -24
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/play.py +2 -2
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/registration.py +2 -2
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/teach.py +2 -2
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/decorators.py +18 -18
- {codeforlife-portal-7.4.9/portal/templates/captcha → codeforlife-portal-8.0.1/portal/templates/django_recaptcha}/includes/js_v2_invisible.html +3 -3
- {codeforlife-portal-7.4.9/portal/templates/captcha → codeforlife-portal-8.0.1/portal/templates/django_recaptcha}/widget_v2_invisible.html +2 -2
- codeforlife-portal-8.0.1/portal/templates/two_factor/core/login.html +70 -0
- codeforlife-portal-8.0.1/portal/templates/two_factor/core/setup.html +66 -0
- codeforlife-portal-8.0.1/portal/templates/two_factor/profile/profile.html +60 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_captcha_forms.py +2 -2
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_middleware.py +32 -10
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/urls.py +94 -88
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/api.py +30 -16
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/home.py +45 -15
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/registration.py +3 -3
- codeforlife-portal-8.0.1/portal/views/two_factor/core.py +28 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/profile.py +2 -2
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/setup.py +6 -13
- codeforlife-portal-7.4.9/codeforlife_portal.egg-info/requires.txt +0 -21
- codeforlife-portal-7.4.9/portal/__init__.py +0 -1
- codeforlife-portal-7.4.9/portal/templates/two_factor/core/login.html +0 -63
- codeforlife-portal-7.4.9/portal/templates/two_factor/core/setup.html +0 -57
- codeforlife-portal-7.4.9/portal/templates/two_factor/profile/profile.html +0 -42
- codeforlife-portal-7.4.9/portal/views/two_factor/core.py +0 -25
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/LICENSE.md +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/MANIFEST.in +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/README.md +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/dependency_links.txt +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/not-zip-safe +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/top_level.txt +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/captcha.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/admin_access.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/basicauth.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/exceptionlogging.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/screentime_warning.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/middleware/session_timeout.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-120x120.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-152x152.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-180x180.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon-76x76.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/apple-touch-icon.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/static/robots.txt +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/templates/deploy/csrf_failure.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/deploy/views.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/app_settings.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/backends.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/beta.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/context_processors.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/admin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/dotmailer.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/error_messages.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/invite_teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/forms/organisation.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/handlers.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/captcha.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/password.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/ratelimit.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/regexes.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/helpers/request_handlers.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0001_squashed_0041_new_news.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0042_school_country.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0043_auto_20150430_0952.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0044_auto_20150430_0959.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0045_auto_20150430_1446.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0046_auto_20150723_1101.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0047_remove_userprofile_avatar.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0048_plural_management_frontnews.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0049_refactor_emailverifications.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0050_refactor_emailverifications_2.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0051_add_missing_ev_records.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0052_refactor_emailverifications_3.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0053_refactor_teacher_student_1.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0054_pending_join_request_can_be_blank.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0055_add_preview_user.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0056_remove_preview_user.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0057_delete_frontpagenews.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0058_move_to_common_models.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0059_move_email_verifications_to_common.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0060_delete_guardian.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0061_make_portaladmin_teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/0062_verify_portaladmin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/migrations/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/mixins/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/mixins/cron_mixin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/models.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/permissions/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/permissions/is_cron_request_from_google.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/pipeline_compilers/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/pipeline_compilers/libsass_compiler.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.eot +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.ttf +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/fonts/bootstrap/glyphicons-halflings-regular.woff2 +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/10_years_anniversary.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/10x_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_grass_background.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_green.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/RR_logo_simple.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_cfl.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/about_us_ocado.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/barefoot_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/bcs_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/clubs.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/coding_club_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/coding_club_python_pack.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/border.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/controls.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/loading.gif +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/loading_background.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/colorboxImages/overlay.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/confirmation_tick.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/cross.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/dee.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/facebook.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/favicon.ico +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/get_involved_hero.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gitbook.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gitbook_space.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/github.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/github_hero.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/gla_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/hamburger.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/help_and_support_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_educate.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_educate_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_learning_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_play.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/home_play_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/hope_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_1.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_2.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/howe_dell_3.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icl_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_controller.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_free.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_globe.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_piechart.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_step_by_step.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_tracking.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/icon_uk_flag.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/kirsty.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_powered.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_cfl_white_landscape.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_ocado_group_white.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/logo_python_den.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/long_europe_map.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/mc_saatchi_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/nigel.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/ocado-swirl.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_blue.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_pink.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/oval_yellow.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/paper_plane.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/phil.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_blue.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_pink.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/polygon_yellow.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/pressure_cooker_logo.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/python_den.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/python_den_banner.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapid_router.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapid_router_landing_hero.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rapidrouter.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/resources_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/resources_montage.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/reuben.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rob.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_advanced.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_beginner.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/rr_intermediate.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sadface.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sharon_harrison.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/sian.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/teaching_resources_hero.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/ten_year_map_pin.svg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_educate_resources.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_intro_c4l.jpg +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/thumbnail_python_den.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/twitter.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/universities.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/img/wes.png +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/bootstrap.min.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/carouselCards.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/common.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/independentLogin.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/independentRegistration.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/join_create_game_toggle.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/jquery.placeholder.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/levelControl.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery-video-lightning.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.colorbox.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.easy-ticker.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/jquery.min.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/modernizr-build.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/lib/papaparse.min.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/organisation_manage.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/passwordStrength.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/play.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/resetPassword.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/riveted.min.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/school.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/sticky_subnav.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/studentLogin.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teach_browser.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teach_class.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teacherEditStudent.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/teacherLogin.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/js/tenYearMap.js +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_alerts.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_badges.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_breadcrumbs.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_button-groups.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_buttons.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_carousel.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_close.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_code.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_component-animations.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_dropdowns.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_forms.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_glyphicons.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_grid.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_input-groups.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_jumbotron.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_labels.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_list-group.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_media.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_mixins.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_modals.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_navbar.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_navs.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_normalize.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_pager.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_pagination.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_panels.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_popovers.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_print.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_progress-bars.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_responsive-embed.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_responsive-utilities.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_scaffolding.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_tables.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_theme.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_thumbnails.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_tooltip.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_type.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_utilities.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_variables.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/_wells.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_alerts.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_background-variant.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_border-radius.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_breakpoints.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_buttons.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_center-block.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_clearfix.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_forms.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_gradients.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_grid-framework.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_grid.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_hide-text.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_image.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_labels.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_list-group.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_nav-divider.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_nav-vertical-align.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_opacity.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_pagination.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_panels.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_progress-bar.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_reset-filter.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_reset-text.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_resize.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_responsive-visibility.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_size.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_tab-focus.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_table-row.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-emphasis.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-overflow.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_text-truncate.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap/mixins/_vendor-prefixes.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_all.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_border-radius.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_box-shadow.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_hover.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_mixins/_nav-divider.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_dropdown.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_glyphicons.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_grid.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_partials/_variables.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_align.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_background.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_borders.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_clearfix.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_cursor.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_display.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_flex.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_float.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_position.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_screenreaders.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_sizing.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_spacing.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_text.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/bootstrap_utilities/_visibility.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/colorbox.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_all.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_animation.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_breakpoints.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_card_constants.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_colours.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_homepage_constants.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_levels.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_mixins.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/modules/_spacing.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_banners.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_base.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_buttons.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_carousel.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_footer.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_forms.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_grids.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_header.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_images.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_popup.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_progress-bars.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_subnavs.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_tables.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_text.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_ui-dialog.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/partials/_utils.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/sass/styles.scss +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/static/portal/video/code for life .pdf +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/about.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/coding_club.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/help_and_support.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/home_learning.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/materials.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/play.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/teach.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/teacher_resources.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/strings/ten_year_map.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/403.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/404.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/500.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/email.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/email.txt +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/about.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/base.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/base_no_userprofile.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/coding_club.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/contribute.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/dotmailer_consent_form.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_invitation_sent.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_style_template.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_verification_failed.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/email_verification_needed.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/form_shapes.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/getinvolved.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/home.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/home_learning.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/locked_out.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/locked_out_school_student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/independent_student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/student_class_code.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/login/teacher.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/mouseflow.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/banner.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/benefits.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/card_list.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/character_list.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/delete_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/donate_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/footer.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/header.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/headline.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/hero_card.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/info_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/invite_admin_teacher.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/register_newsletter_tickbox.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/screentime_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/service_unavailable_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/session_popup.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/teacher_non_dashboard_subnav.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/partials/teacher_non_dashboard_subnav_account.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_dashboard.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_edit_account.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play/student_join_organisation.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/play.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/privacy_notice.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/register.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_confirm.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_done.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/reset_password_email_sent.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/tag_manager/tag_manager_body.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/tag_manager/tag_manager_head.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/base_registering.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/class.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/dashboard.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/invited.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_classes.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_print.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_school.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/onboarding_students.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_add_external_student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_added_external_student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_dismiss_students.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_edit_class.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_edit_student.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_all_classes.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_students.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach/teacher_move_students_to_class.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/teach.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/ten_year_map.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/portal/terms.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_base.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions_enable_2fa.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_actions_submit.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_forms.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/_wizard_forms_token.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/backup_token.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/core/backup_tokens.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/core/setup_complete.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/profile/disable.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templates/two_factor/setup_wizard_token.html +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/app_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/banner_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/benefits_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/card_list_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/future.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/headline_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/hero_card_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/templatetags/table_tags.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/base_test.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/conftest.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_make_portaladmin_teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_preview_user_remove.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_preview_users.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_remove_front_page_news.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_remove_guardian.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_use_common_models.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/migrations/test_migration_verify_portaladmin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_data_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/admin/admin_map_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/base_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/email_verification_needed_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/forbidden_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/game_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/home_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/independent_login_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/password_reset_form_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/password_reset_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/account_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/dashboard_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/join_school_or_club_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play/play_base_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/play_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/resources_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/signup_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/student_login_class_code.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/student_login_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/class_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/dashboard_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/dismiss_students_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/edit_student_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_class_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_classes_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/move_students_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/onboarding_students_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teach/teach_base_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/pageObjects/portal/teacher_login_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/selenium_test_case.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/snapshots/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/snapshots/snap_test_partials.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_2FA.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_admin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_api.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_class.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_emails.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_global_forms.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_helper_methods.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_independent_student.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_invite_teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_organisation.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_partials.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_ratelimit.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_school_student.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_security.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_teacher_student.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/test_views.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/classes.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/tests/utils/messages.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/about.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/admin.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/cron/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/cron/user.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/dotmailer.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/email.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/legal.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/independent_student.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/student.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/login/teacher.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/organisation.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/play_landing_page.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/edit_account_details.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/student/play.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teach.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/dashboard.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/teacher/teach.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/__init__.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/views/two_factor/form.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/portal/wsgi.py +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/pyproject.toml +0 -0
- {codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/setup.cfg +0 -0
{codeforlife-portal-7.4.9 → codeforlife-portal-8.0.1}/codeforlife_portal.egg-info/SOURCES.txt
RENAMED
|
@@ -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/
|
|
353
|
-
portal/templates/
|
|
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/
|
|
8
|
-
the source code, as well as https://docs.djangoproject.com/en/
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
anonymise(user)
|
|
175
|
+
_UserAdmin.list_display += ("date_joined", "id")
|
|
176
|
+
_UserAdmin.list_filter += ("date_joined",)
|
|
178
177
|
|
|
179
178
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
]
|
|
179
|
+
class UserAdmin(_UserAdmin):
|
|
180
|
+
actions = ["anonymise_user", "export_as_csv"]
|
|
181
|
+
add_form = AdminUserCreationForm
|
|
182
|
+
change_password_form = AdminChangeUserPasswordForm
|
|
185
183
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
def anonymise_user(self, request, queryset):
|
|
185
|
+
for user in queryset:
|
|
186
|
+
anonymise(user)
|
|
189
187
|
|
|
190
|
-
|
|
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
|
-
|
|
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
|
-
|
|
198
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
|
68
|
-
#
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
2
|
-
|
|
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
|
-
|
|
2
|
-
{% include "
|
|
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(
|
|
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(
|
|
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(
|
|
95
|
-
|
|
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(
|
|
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[
|
|
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
|
|
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[
|
|
230
|
-
|
|
247
|
+
renewed_screentime_warning_timeout = session[
|
|
248
|
+
"screentime_warning_timeout"
|
|
249
|
+
]
|
|
250
|
+
assert (
|
|
251
|
+
renewed_screentime_warning_timeout > new_screentime_warning_timeout
|
|
252
|
+
)
|