codeforlife-portal 5.33.5__py2.py3-none-any.whl → 8.9.9__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cfl_common/common/__init__.py +1 -0
- cfl_common/common/app_settings.py +66 -0
- cfl_common/common/apps.py +6 -0
- cfl_common/common/context_processors.py +9 -0
- cfl_common/common/csp_config.py +85 -0
- cfl_common/common/helpers/__init__.py +0 -0
- cfl_common/common/helpers/data_migration_loader.py +42 -0
- cfl_common/common/helpers/emails.py +393 -0
- cfl_common/common/helpers/generators.py +52 -0
- cfl_common/common/helpers/organisation.py +10 -0
- cfl_common/common/mail.py +201 -0
- cfl_common/common/migrations/0001_initial.py +240 -0
- cfl_common/common/migrations/0002_emailverification.py +55 -0
- cfl_common/common/migrations/0003_aimmocharacter.py +31 -0
- cfl_common/common/migrations/0004_add_aimmocharacters.py +17 -0
- cfl_common/common/migrations/0005_add_worksheets.py +8 -0
- cfl_common/common/migrations/0006_update_aimmo_character_image_path.py +17 -0
- cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +8 -0
- cfl_common/common/migrations/0008_unlock_worksheet_3.py +11 -0
- cfl_common/common/migrations/0009_add_blocked_time_to_teacher_and_student.py +24 -0
- cfl_common/common/migrations/0010_remove_teacher_title.py +18 -0
- cfl_common/common/migrations/0011_student_login_id.py +18 -0
- cfl_common/common/migrations/0012_usersession.py +39 -0
- cfl_common/common/migrations/0013_class_school.py +42 -0
- cfl_common/common/migrations/0014_login_type.py +29 -0
- cfl_common/common/migrations/0015_dailyactivity.py +31 -0
- cfl_common/common/migrations/0016_joinreleasestudent.py +42 -0
- cfl_common/common/migrations/0017_copy_email_to_username.py +18 -0
- cfl_common/common/migrations/0018_update_aimmo_character_image_path.py +15 -0
- cfl_common/common/migrations/0019_aimmocharacter_alt.py +16 -0
- cfl_common/common/migrations/0020_class_is_active_and_null_access_code.py +23 -0
- cfl_common/common/migrations/0021_school_is_active.py +28 -0
- cfl_common/common/migrations/0022_school_cleanup.py +29 -0
- cfl_common/common/migrations/0023_userprofile_aimmo_badges.py +22 -0
- cfl_common/common/migrations/0024_teacher_invited_by.py +25 -0
- cfl_common/common/migrations/0025_schoolteacherinvitation.py +47 -0
- cfl_common/common/migrations/0026_teacher_remove_join_request.py +22 -0
- cfl_common/common/migrations/0027_class_created_by.py +25 -0
- cfl_common/common/migrations/0028_coding_club_downloads.py +23 -0
- cfl_common/common/migrations/0029_dynamicelement.py +22 -0
- cfl_common/common/migrations/0030_add_maintenance_banner.py +25 -0
- cfl_common/common/migrations/0031_improve_admin_panel.py +56 -0
- cfl_common/common/migrations/0032_dailyactivity_level_control_submits.py +18 -0
- cfl_common/common/migrations/0033_password_reset_tracking_fields.py +23 -0
- cfl_common/common/migrations/0034_dailyactivity_daily_school_student_lockout_reset.py +18 -0
- cfl_common/common/migrations/0035_rename_lockout_fields.py +27 -0
- cfl_common/common/migrations/0036_rename_awaiting_email_verification_userprofile_is_verified.py +17 -0
- cfl_common/common/migrations/0037_migrate_email_verification.py +21 -0
- cfl_common/common/migrations/0038_delete_emailverification.py +16 -0
- cfl_common/common/migrations/0039_copy_email_to_username.py +18 -0
- cfl_common/common/migrations/0040_school_county.py +18 -0
- cfl_common/common/migrations/0041_populate_gb_counties.py +27 -0
- cfl_common/common/migrations/0042_totalactivity.py +25 -0
- cfl_common/common/migrations/0043_add_total_activity.py +30 -0
- cfl_common/common/migrations/0044_update_activity_models.py +33 -0
- cfl_common/common/migrations/0045_otp.py +23 -0
- cfl_common/common/migrations/0046_alter_school_country.py +19 -0
- cfl_common/common/migrations/0047_delete_school_postcode.py +16 -0
- cfl_common/common/migrations/0048_unique_school_names.py +42 -0
- cfl_common/common/migrations/0049_anonymise_orphan_users.py +29 -0
- cfl_common/common/migrations/0050_anonymise_orphan_schools.py +30 -0
- cfl_common/common/migrations/0051_verify_returning_users.py +26 -0
- cfl_common/common/migrations/0052_add_cse_fields.py +68 -0
- cfl_common/common/migrations/0053_clean_class_data.py +24 -0
- cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
- cfl_common/common/migrations/0055_alter_schoolteacherinvitation_token.py +18 -0
- cfl_common/common/migrations/0056_set_non_school_teachers_as_non_admins.py +25 -0
- cfl_common/common/migrations/0057_teacher_teacher__is_admin.py +19 -0
- cfl_common/common/migrations/0058_userprofile_google_refresh_token_and_more.py +24 -0
- cfl_common/common/migrations/__init__.py +0 -0
- cfl_common/common/models.py +557 -0
- cfl_common/common/permissions.py +84 -0
- cfl_common/common/tests/__init__.py +0 -0
- cfl_common/common/tests/test_migration_anonymise_orphan_schools.py +30 -0
- cfl_common/common/tests/test_migration_anonymise_orphan_users.py +30 -0
- cfl_common/common/tests/test_migration_blocked_time.py +15 -0
- cfl_common/common/tests/test_migration_remove_teacher_title.py +13 -0
- cfl_common/common/tests/test_migration_unique_school_names.py +33 -0
- cfl_common/common/tests/test_migration_verify_returning_users.py +59 -0
- cfl_common/common/tests/test_models.py +87 -0
- cfl_common/common/tests/utils/__init__.py +0 -0
- cfl_common/common/tests/utils/classes.py +38 -0
- cfl_common/common/tests/utils/email.py +67 -0
- cfl_common/common/tests/utils/organisation.py +41 -0
- cfl_common/common/tests/utils/student.py +123 -0
- cfl_common/common/tests/utils/teacher.py +73 -0
- cfl_common/common/tests/utils/user.py +27 -0
- cfl_common/common/utils.py +56 -0
- cfl_common/setup.py +61 -0
- codeforlife_portal-8.9.9.dist-info/METADATA +226 -0
- {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/RECORD +339 -241
- {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/WHEEL +1 -1
- codeforlife_portal-8.9.9.dist-info/licenses/LICENSE.md +3 -0
- {codeforlife_portal-5.33.5.dist-info → codeforlife_portal-8.9.9.dist-info}/top_level.txt +1 -0
- deploy/middleware/maintenance.py +25 -0
- deploy/middleware/screentime_warning.py +29 -0
- deploy/middleware/security.py +5 -6
- deploy/middleware/session_timeout.py +4 -2
- deploy/middleware/tmp_basic_auth.py +41 -0
- example_project/portal_test_settings.py +239 -0
- example_project/settings.py +156 -17
- example_project/urls.py +5 -6
- portal/__init__.py +1 -1
- portal/admin.py +142 -29
- portal/app_settings.py +8 -7
- portal/forms/dotmailer.py +6 -4
- portal/forms/invite_teacher.py +19 -10
- portal/forms/organisation.py +137 -68
- portal/forms/play.py +53 -98
- portal/forms/registration.py +70 -164
- portal/forms/teach.py +147 -121
- portal/handlers.py +1 -2
- portal/helpers/decorators.py +30 -10
- portal/helpers/password.py +86 -47
- portal/helpers/ratelimit.py +32 -15
- portal/helpers/regexes.py +5 -0
- portal/helpers/request_handlers.py +10 -0
- portal/migrations/0044_auto_20150430_0959.py +6 -2
- portal/mixins/__init__.py +1 -0
- portal/mixins/cron_mixin.py +12 -0
- portal/permissions/__init__.py +1 -0
- portal/permissions/is_cron_request_from_google.py +14 -0
- portal/static/portal/img/10_years_anniversary.png +0 -0
- portal/static/portal/img/RR_logo_grass_background.png +0 -0
- portal/static/portal/img/coding_club_hero.jpg +0 -0
- portal/static/portal/img/coding_club_python_pack.png +0 -0
- portal/static/portal/img/facebook.png +0 -0
- portal/static/portal/img/gitbook.png +0 -0
- portal/static/portal/img/howe_dell_1.png +0 -0
- portal/static/portal/img/howe_dell_2.png +0 -0
- portal/static/portal/img/howe_dell_3.png +0 -0
- portal/static/portal/img/logo_cfl.png +0 -0
- portal/static/portal/img/logo_cfl_powered.svg +35 -0
- portal/static/portal/img/logo_cfl_reminder_cards.jpg +0 -0
- portal/static/portal/img/logo_ocado_group.png +0 -0
- portal/static/portal/img/logo_python_den.svg +21 -0
- portal/static/portal/img/long_europe_map.png +0 -0
- portal/static/portal/img/python_den.png +0 -0
- portal/static/portal/img/python_den_banner.svg +26 -0
- portal/static/portal/img/rapid_router_landing_hero.png +0 -0
- portal/static/portal/img/rr_advanced.png +0 -0
- portal/static/portal/img/ten_year_map_pin.svg +1 -0
- portal/static/portal/img/thumbnail_educate_rapid_router.png +0 -0
- portal/static/portal/img/thumbnail_educate_resources.png +0 -0
- portal/static/portal/img/thumbnail_play_rapid_router.png +0 -0
- portal/static/portal/img/thumbnail_python_den.png +0 -0
- portal/static/portal/img/twitter.png +0 -0
- portal/static/portal/js/carouselCards.js +25 -0
- portal/static/portal/js/common.js +96 -1
- portal/static/portal/js/independentLogin.js +16 -0
- portal/static/portal/js/independentRegistration.js +86 -0
- portal/static/portal/js/levelControl.js +77 -0
- portal/static/portal/js/lib/jquery.min.js +2 -0
- portal/static/portal/js/organisation_manage.js +142 -14
- portal/static/portal/js/passwordStrength.js +154 -64
- portal/static/portal/js/resetPassword.js +23 -0
- portal/static/portal/js/riveted.min.js +238 -239
- portal/static/portal/js/school.js +13 -0
- portal/static/portal/js/studentLogin.js +16 -0
- portal/static/portal/js/teacherEditStudent.js +23 -0
- portal/static/portal/js/teacherLogin.js +16 -0
- portal/static/portal/js/tenYearMap.js +14 -0
- portal/static/portal/sass/colorbox.scss +0 -1
- portal/static/portal/sass/modules/_colours.scss +1 -0
- portal/static/portal/sass/modules/_levels.scss +1 -1
- portal/static/portal/sass/modules/_mixins.scss +21 -0
- portal/static/portal/sass/partials/_banners.scss +4 -177
- portal/static/portal/sass/partials/_buttons.scss +12 -15
- portal/static/portal/sass/partials/_carousel.scss +129 -0
- portal/static/portal/sass/partials/_footer.scss +21 -22
- portal/static/portal/sass/partials/_forms.scss +60 -5
- portal/static/portal/sass/partials/_grids.scss +34 -61
- portal/static/portal/sass/partials/_header.scss +28 -20
- portal/static/portal/sass/partials/_images.scss +292 -39
- portal/static/portal/sass/partials/_popup.scss +18 -15
- portal/static/portal/sass/partials/_tables.scss +12 -20
- portal/static/portal/sass/partials/_text.scss +6 -10
- portal/static/portal/sass/styles.scss +0 -1
- portal/static/portal/video/code for life .pdf +0 -0
- portal/strings/about.py +5 -0
- portal/strings/coding_club.py +9 -0
- portal/strings/play.py +6 -5
- portal/strings/teach.py +1 -1
- portal/strings/teacher_resources.py +2 -8
- portal/strings/ten_year_map.py +13 -0
- portal/templates/403.html +2 -2
- portal/templates/404.html +1 -1
- portal/templates/500.html +2 -2
- portal/templates/{captcha → django_recaptcha}/includes/js_v2_invisible.html +3 -3
- portal/templates/{captcha → django_recaptcha}/widget_v2_invisible.html +2 -2
- portal/templates/email.html +4 -2
- portal/templates/maintenance.html +34 -0
- portal/templates/portal/about.html +94 -62
- portal/templates/portal/base.html +176 -152
- portal/templates/portal/coding_club.html +100 -0
- portal/templates/portal/contribute.html +56 -52
- portal/templates/portal/email_invitation_sent.html +1 -1
- portal/templates/portal/email_style_template.html +374 -0
- portal/templates/portal/email_verification_failed.html +1 -1
- portal/templates/portal/email_verification_needed.html +9 -9
- portal/templates/portal/form_shapes.html +20 -8
- portal/templates/portal/getinvolved.html +6 -6
- portal/templates/portal/home.html +35 -10
- portal/templates/portal/home_learning.html +19 -19
- portal/templates/portal/locked_out.html +0 -1
- portal/templates/portal/locked_out_school_student.html +16 -0
- portal/templates/portal/login/independent_student.html +31 -15
- portal/templates/portal/login/student.html +10 -7
- portal/templates/portal/login/student_class_code.html +7 -4
- portal/templates/portal/login/teacher.html +34 -17
- portal/templates/portal/partials/banner.html +18 -4
- portal/templates/portal/partials/benefits.html +1 -1
- portal/templates/portal/partials/card_list.html +34 -24
- portal/templates/portal/partials/character_list.html +5 -5
- portal/templates/portal/partials/cookie_list.html +161 -0
- portal/templates/portal/partials/delete_popup.html +18 -0
- portal/templates/portal/partials/footer.html +57 -26
- portal/templates/portal/partials/header.html +118 -117
- portal/templates/portal/partials/hero_card.html +4 -3
- portal/templates/portal/partials/info_popup.html +3 -3
- portal/templates/portal/partials/invite_admin_teacher.html +23 -0
- portal/templates/portal/partials/popup.html +7 -2
- portal/templates/portal/partials/register_newsletter_tickbox.html +2 -5
- portal/templates/portal/partials/screentime_popup.html +14 -0
- portal/templates/portal/partials/service_unavailable_popup.html +17 -0
- portal/templates/portal/partials/session_popup.html +19 -0
- portal/templates/portal/play/student_dashboard.html +42 -29
- portal/templates/portal/play/student_edit_account.html +64 -9
- portal/templates/portal/play.html +61 -41
- portal/templates/portal/privacy_notice.html +697 -0
- portal/templates/portal/register.html +122 -92
- portal/templates/portal/reset_password.html +20 -40
- portal/templates/portal/reset_password_confirm.html +9 -4
- portal/templates/portal/reset_password_email_sent.html +15 -13
- portal/templates/portal/teach/base_registering.html +1 -1
- portal/templates/portal/teach/class.html +4 -6
- portal/templates/portal/teach/dashboard.html +212 -117
- portal/templates/portal/teach/invited.html +90 -0
- portal/templates/portal/teach/onboarding_classes.html +5 -3
- portal/templates/portal/teach/onboarding_print.html +1 -1
- portal/templates/portal/teach/onboarding_school.html +26 -139
- portal/templates/portal/teach/onboarding_students.html +1 -1
- portal/templates/portal/teach/teacher_dismiss_students.html +73 -55
- portal/templates/portal/teach/teacher_edit_class.html +168 -11
- portal/templates/portal/teach/teacher_edit_student.html +12 -5
- portal/templates/portal/teach/teacher_move_all_classes.html +25 -38
- portal/templates/portal/teach/teacher_move_students_to_class.html +1 -1
- portal/templates/portal/teach.html +61 -42
- portal/templates/portal/ten_year_map.html +147 -0
- portal/templates/portal/terms.html +191 -42
- portal/templates/two_factor/core/login.html +71 -59
- portal/templates/two_factor/core/setup.html +58 -49
- portal/templates/two_factor/profile/disable.html +1 -1
- portal/templates/two_factor/profile/profile.html +35 -17
- portal/templatetags/app_tags.py +59 -84
- portal/templatetags/card_list_tags.py +0 -4
- portal/tests/base_test.py +14 -3
- portal/tests/conftest.py +0 -15
- portal/tests/migrations/test_migration_make_portaladmin_teacher.py +2 -6
- portal/tests/migrations/test_migration_preview_users.py +3 -9
- portal/tests/migrations/test_migration_remove_guardian.py +1 -3
- portal/tests/migrations/test_migration_use_common_models.py +2 -6
- portal/tests/migrations/test_migration_verify_portaladmin.py +1 -3
- portal/tests/pageObjects/portal/admin/admin_base_page.py +0 -21
- portal/tests/pageObjects/portal/base_page.py +16 -26
- portal/tests/pageObjects/portal/email_verification_needed_page.py +3 -2
- portal/tests/pageObjects/portal/game_page.py +12 -19
- portal/tests/pageObjects/portal/home_page.py +13 -15
- portal/tests/pageObjects/portal/independent_login_page.py +13 -17
- portal/tests/pageObjects/portal/password_reset_form_page.py +20 -4
- portal/tests/pageObjects/portal/password_reset_page.py +25 -0
- portal/tests/pageObjects/portal/play/account_page.py +18 -27
- portal/tests/pageObjects/portal/play/dashboard_page.py +4 -4
- portal/tests/pageObjects/portal/play/join_school_or_club_page.py +8 -10
- portal/tests/pageObjects/portal/play/play_base_page.py +5 -3
- portal/tests/pageObjects/portal/signup_page.py +28 -59
- portal/tests/pageObjects/portal/student_login_class_code.py +6 -9
- portal/tests/pageObjects/portal/student_login_page.py +6 -8
- portal/tests/pageObjects/portal/teach/add_independent_student_to_class_page.py +3 -3
- portal/tests/pageObjects/portal/teach/added_independent_student_to_class_page.py +3 -1
- portal/tests/pageObjects/portal/teach/class_page.py +36 -13
- portal/tests/pageObjects/portal/teach/dashboard_page.py +43 -84
- portal/tests/pageObjects/portal/teach/dismiss_students_page.py +7 -5
- portal/tests/pageObjects/portal/teach/edit_student_page.py +10 -8
- portal/tests/pageObjects/portal/teach/move_class_page.py +5 -10
- portal/tests/pageObjects/portal/teach/move_classes_page.py +4 -2
- portal/tests/pageObjects/portal/teach/move_students_disambiguate_page.py +4 -2
- portal/tests/pageObjects/portal/teach/move_students_page.py +6 -13
- portal/tests/pageObjects/portal/teach/onboarding_classes_page.py +5 -3
- portal/tests/pageObjects/portal/teach/onboarding_organisation_page.py +11 -49
- portal/tests/pageObjects/portal/teach/onboarding_student_list_page.py +7 -12
- portal/tests/pageObjects/portal/teach/onboarding_students_page.py +4 -27
- portal/tests/pageObjects/portal/teach/teach_base_page.py +6 -4
- portal/tests/pageObjects/portal/teacher_login_page.py +10 -16
- portal/tests/selenium_test_case.py +3 -43
- portal/tests/snapshots/snap_test_partials.py +11 -165
- portal/tests/test_2FA.py +15 -33
- portal/tests/test_admin.py +15 -97
- portal/tests/test_api.py +212 -91
- portal/tests/test_captcha_forms.py +2 -2
- portal/tests/test_class.py +374 -24
- portal/tests/test_emails.py +83 -20
- portal/tests/{test_newsletter_footer.py → test_global_forms.py} +5 -5
- portal/tests/test_helper_methods.py +30 -0
- portal/tests/test_independent_student.py +255 -144
- portal/tests/test_invite_teacher.py +318 -10
- portal/tests/test_middleware.py +96 -9
- portal/tests/test_organisation.py +78 -262
- portal/tests/test_partials.py +0 -88
- portal/tests/test_ratelimit.py +218 -36
- portal/tests/test_school_student.py +35 -40
- portal/tests/test_security.py +12 -31
- portal/tests/test_teacher.py +425 -325
- portal/tests/test_teacher_student.py +103 -91
- portal/tests/test_views.py +900 -76
- portal/tests/utils/classes.py +2 -2
- portal/tests/utils/messages.py +13 -28
- portal/urls.py +235 -166
- portal/views/admin.py +0 -332
- portal/views/api.py +82 -48
- portal/views/cron/__init__.py +1 -0
- portal/views/cron/user.py +322 -0
- portal/views/dotmailer.py +9 -1
- portal/views/email.py +33 -77
- portal/views/google_analytics.py +28 -0
- portal/views/home.py +126 -97
- portal/views/legal.py +13 -0
- portal/views/login/independent_student.py +5 -5
- portal/views/login/student.py +51 -14
- portal/views/login/teacher.py +2 -6
- portal/views/organisation.py +20 -189
- portal/views/registration.py +97 -17
- portal/views/student/edit_account_details.py +99 -72
- portal/views/student/play.py +81 -62
- portal/views/teacher/dashboard.py +421 -149
- portal/views/teacher/teach.py +226 -177
- portal/views/two_factor/core.py +22 -19
- portal/views/two_factor/profile.py +2 -2
- codeforlife_portal-5.33.5.dist-info/LICENSE.md +0 -577
- codeforlife_portal-5.33.5.dist-info/METADATA +0 -38
- deploy/permissions.py +0 -2
- example_project/manage.py +0 -10
- portal/autoconfig.py +0 -141
- portal/csp_config.py +0 -60
- portal/forms/add_game.py +0 -33
- portal/helpers/location.py +0 -121
- portal/static/portal/img/kurono_hero.jpg +0 -0
- portal/static/portal/img/kurono_landing_hero.png +0 -0
- portal/static/portal/img/kurono_logo.svg +0 -1
- portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
- portal/static/portal/img/kurono_logo_mark.svg +0 -1
- portal/static/portal/img/kurono_resources_hero.jpg +0 -0
- portal/static/portal/img/kurono_story.png +0 -0
- portal/static/portal/img/ocado-swirl.svg +0 -22
- portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
- portal/static/portal/img/thumbnail_educate_resources_and_progress_tracking.png +0 -0
- portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
- portal/static/portal/img/thumbnail_play_kurono.png +0 -0
- portal/static/portal/img/x_close_video.png +0 -0
- portal/static/portal/js/aimmoGame.js +0 -106
- portal/static/portal/js/deleteWorkspaces.js +0 -14
- portal/static/portal/js/fuzzySchoolLookup.js +0 -46
- portal/static/portal/js/lib/jquery-3.5.1.min.js +0 -2
- portal/static/portal/js/lib/jquery-ui-1.12.1.min.js +0 -13
- portal/static/portal/sass/partials/_videos.scss +0 -10
- portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
- portal/strings/student_aimmo_dashboard.py +0 -6
- portal/templates/portal/admin/aggregated_data.html +0 -35
- portal/templates/portal/admin/map.html +0 -70
- portal/templates/portal/mouseflow.html +0 -9
- portal/templates/portal/partials/aimmo_games_table.html +0 -83
- portal/templates/portal/partials/register_over_required_age_tickbox.html +0 -9
- portal/templates/portal/play/independent_student_dashboard.html +0 -64
- portal/templates/portal/play/student_aimmo_dashboard.html +0 -63
- portal/templates/portal/privacy_policy.html +0 -483
- portal/templates/portal/reset_password_email.html +0 -9
- portal/templates/portal/teach/invite.html +0 -25
- portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
- portal/templates/portal/teach/teacher_resources.html +0 -68
- portal/templatetags/character_list_tags.py +0 -16
- portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
- portal/tests/pageObjects/portal/student_password_reset_form_page.py +0 -23
- portal/tests/pageObjects/portal/teach/onboarding_revoke_request_page.py +0 -20
- portal/tests/pageObjects/portal/teacher_password_reset_form_page.py +0 -23
- portal/tests/test_aimmo_dashboards.py +0 -172
- portal/tests/test_location.py +0 -217
- portal/tests/utils/aimmo_games.py +0 -30
- portal/views/aimmo/dashboard.py +0 -119
- portal/views/privacy_policy.py +0 -9
- portal/views/teacher/teacher_resources.py +0 -42
- {portal/views/aimmo → cfl_common}/__init__.py +0 -0
|
@@ -1,41 +1,59 @@
|
|
|
1
1
|
{% extends "two_factor/_base.html" %}
|
|
2
|
-
{% load
|
|
2
|
+
{% load i18n %}
|
|
3
|
+
{% load two_factor_tags %}
|
|
3
4
|
|
|
4
5
|
{% block content %}
|
|
5
|
-
<
|
|
6
|
+
<h1>{% block title %}{% trans "Account Security" %}{% endblock %}</h1>
|
|
6
7
|
|
|
7
8
|
{% if default_device %}
|
|
8
|
-
{%
|
|
9
|
-
|
|
10
|
-
{%
|
|
11
|
-
<
|
|
12
|
-
{%
|
|
13
|
-
|
|
9
|
+
<p>{% blocktrans with primary=default_device|as_action %}Primary method: {{ primary }}{% endblocktrans %}</p>
|
|
10
|
+
|
|
11
|
+
{% if available_phone_methods %}
|
|
12
|
+
<h2>{% trans "Backup Phone Numbers" %}</h2>
|
|
13
|
+
<p>{% blocktrans trimmed %}If your primary method is not available, we are able to
|
|
14
|
+
send backup tokens to the phone numbers listed below.{% endblocktrans %}</p>
|
|
15
|
+
{% if backup_phones %}
|
|
16
|
+
<ul>
|
|
17
|
+
{% for phone in backup_phones %}
|
|
18
|
+
<li>
|
|
19
|
+
{{ phone|as_action }}
|
|
20
|
+
<form method="post" action="{% url 'two_factor:phone_delete' phone.id %}"
|
|
21
|
+
onsubmit="return confirm({% trans 'Are you sure?' %})">
|
|
22
|
+
{% csrf_token %}
|
|
23
|
+
<button class="btn btn-sm btn-warning"
|
|
24
|
+
type="submit">{% trans "Unregister" %}</button>
|
|
25
|
+
</form>
|
|
26
|
+
</li>
|
|
27
|
+
{% endfor %}
|
|
28
|
+
</ul>
|
|
29
|
+
{% endif %}
|
|
30
|
+
<p><a href="{% url 'two_factor:phone_create' %}"
|
|
31
|
+
class="btn btn-info">{% trans "Add Phone Number" %}</a></p>
|
|
14
32
|
{% endif %}
|
|
15
33
|
|
|
16
|
-
<
|
|
34
|
+
<h2>{% trans "Backup Tokens" %}</h2>
|
|
17
35
|
<p>
|
|
18
|
-
{% blocktrans %}If you don't have any device with you, you can access
|
|
36
|
+
{% blocktrans trimmed %}If you don't have any device with you, you can access
|
|
19
37
|
your account using backup tokens.{% endblocktrans %}
|
|
20
|
-
{% blocktrans count counter=backup_tokens %}
|
|
38
|
+
{% blocktrans trimmed count counter=backup_tokens %}
|
|
21
39
|
You have only one backup token remaining.
|
|
22
40
|
{% plural %}
|
|
23
41
|
You have {{ counter }} backup tokens remaining.
|
|
24
42
|
{% endblocktrans %}
|
|
25
43
|
</p>
|
|
26
44
|
<p><a href="{% url 'two_factor:backup_tokens' %}"
|
|
27
|
-
class="
|
|
45
|
+
class="btn btn-info">{% trans "Show Codes" %}</a></p>
|
|
28
46
|
|
|
29
|
-
<
|
|
30
|
-
<p>{% blocktrans %}However we strongly discourage you to do so, you can
|
|
47
|
+
<h3>{% trans "Disable Two-Factor Authentication" %}</h3>
|
|
48
|
+
<p>{% blocktrans trimmed %}However we strongly discourage you to do so, you can
|
|
31
49
|
also disable two-factor authentication for your account.{% endblocktrans %}</p>
|
|
32
|
-
<p><a class="
|
|
50
|
+
<p><a class="btn btn-secondary" href="{% url 'two_factor:disable' %}">
|
|
33
51
|
{% trans "Disable Two-Factor Authentication" %}</a></p>
|
|
34
52
|
{% else %}
|
|
35
|
-
<p>{% blocktrans %}Two-factor authentication is not enabled for your
|
|
53
|
+
<p>{% blocktrans trimmed %}Two-factor authentication is not enabled for your
|
|
36
54
|
account. Enable two-factor authentication for enhanced account
|
|
37
55
|
security.{% endblocktrans %}</p>
|
|
38
|
-
<p><a href="{% url 'two_factor:setup' %}" class="
|
|
56
|
+
<p><a href="{% url 'two_factor:setup' %}" class="btn btn-primary">
|
|
39
57
|
{% trans "Enable Two-Factor Authentication" %}</a>
|
|
40
58
|
</p>
|
|
41
59
|
{% endif %}
|
portal/templatetags/app_tags.py
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
from aimmo.templatetags.players_utils import get_user_playable_games
|
|
2
|
-
from aimmo.worksheets import get_complete_worksheets, get_incomplete_worksheets
|
|
3
1
|
from common import app_settings as common_app_settings
|
|
4
|
-
from common.models import EmailVerification
|
|
5
|
-
from common.permissions import logged_in_as_teacher
|
|
6
2
|
from common.utils import using_two_factor
|
|
7
3
|
from django import template
|
|
8
4
|
from django.conf import settings
|
|
9
|
-
from django.contrib.auth.models import User
|
|
10
|
-
from django.core.exceptions import ObjectDoesNotExist
|
|
11
|
-
from django.shortcuts import reverse
|
|
12
|
-
from django.template.context import RequestContext
|
|
13
5
|
from django.template.defaultfilters import stringfilter
|
|
6
|
+
|
|
14
7
|
from portal import __version__, beta
|
|
15
8
|
|
|
16
9
|
register = template.Library()
|
|
@@ -23,33 +16,25 @@ def emaildomain(email):
|
|
|
23
16
|
|
|
24
17
|
|
|
25
18
|
@register.filter(name="has_2FA")
|
|
26
|
-
def has_2FA(
|
|
27
|
-
return using_two_factor(
|
|
19
|
+
def has_2FA(user):
|
|
20
|
+
return using_two_factor(user)
|
|
28
21
|
|
|
29
22
|
|
|
30
23
|
@register.filter(name="is_logged_in")
|
|
31
|
-
def is_logged_in(
|
|
24
|
+
def is_logged_in(user):
|
|
32
25
|
return (
|
|
33
|
-
|
|
34
|
-
and
|
|
35
|
-
and (
|
|
26
|
+
user
|
|
27
|
+
and user.is_authenticated
|
|
28
|
+
and (
|
|
29
|
+
not using_two_factor(user)
|
|
30
|
+
or (hasattr(user, "is_verified") and user.userprofile.is_verified)
|
|
31
|
+
)
|
|
36
32
|
)
|
|
37
33
|
|
|
38
34
|
|
|
39
35
|
@register.filter
|
|
40
|
-
def
|
|
41
|
-
|
|
42
|
-
verifications = EmailVerification.objects.filter(user=u)
|
|
43
|
-
latest_verification = verifications.latest("user")
|
|
44
|
-
except ObjectDoesNotExist:
|
|
45
|
-
return False
|
|
46
|
-
|
|
47
|
-
return latest_verification.verified
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@register.filter
|
|
51
|
-
def is_developer(u):
|
|
52
|
-
return not u.is_anonymous and u.userprofile.developer
|
|
36
|
+
def is_developer(user):
|
|
37
|
+
return not user.is_anonymous and user.userprofile.developer
|
|
53
38
|
|
|
54
39
|
|
|
55
40
|
@register.filter
|
|
@@ -63,98 +48,91 @@ def has_beta_access(request):
|
|
|
63
48
|
return beta.has_beta_access(request)
|
|
64
49
|
|
|
65
50
|
|
|
66
|
-
@register.inclusion_tag("portal/partials/aimmo_games_table.html", takes_context=True)
|
|
67
|
-
def games_table(context, base_url):
|
|
68
|
-
playable_games = get_user_playable_games(context, base_url)
|
|
69
|
-
|
|
70
|
-
playable_games["complete_worksheets"] = get_complete_worksheets()
|
|
71
|
-
playable_games["incomplete_worksheets"] = get_incomplete_worksheets()
|
|
72
|
-
|
|
73
|
-
return playable_games
|
|
74
|
-
|
|
75
|
-
|
|
76
51
|
@register.filter(name="make_into_username")
|
|
77
|
-
def make_into_username(
|
|
52
|
+
def make_into_username(user):
|
|
78
53
|
username = ""
|
|
79
|
-
if hasattr(
|
|
80
|
-
if hasattr(
|
|
81
|
-
username =
|
|
82
|
-
elif hasattr(
|
|
83
|
-
username =
|
|
54
|
+
if hasattr(user, "userprofile"):
|
|
55
|
+
if hasattr(user.userprofile, "student"):
|
|
56
|
+
username = user.first_name
|
|
57
|
+
elif hasattr(user.userprofile, "teacher"):
|
|
58
|
+
username = user.first_name + " " + user.last_name
|
|
84
59
|
|
|
85
60
|
return username
|
|
86
61
|
|
|
87
62
|
|
|
88
63
|
@register.filter(name="is_logged_in_as_teacher")
|
|
89
|
-
def is_logged_in_as_teacher(
|
|
90
|
-
return
|
|
64
|
+
def is_logged_in_as_teacher(user):
|
|
65
|
+
return (
|
|
66
|
+
is_logged_in(user)
|
|
67
|
+
and user.userprofile
|
|
68
|
+
and hasattr(user.userprofile, "teacher")
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@register.filter(name="is_logged_in_as_admin_teacher")
|
|
73
|
+
def is_logged_in_as_admin_teacher(user):
|
|
74
|
+
return is_logged_in_as_teacher(user) and user.userprofile.teacher.is_admin
|
|
91
75
|
|
|
92
76
|
|
|
93
77
|
@register.filter(name="is_logged_in_as_student")
|
|
94
|
-
def is_logged_in_as_student(
|
|
78
|
+
def is_logged_in_as_student(user):
|
|
95
79
|
return (
|
|
96
|
-
is_logged_in(
|
|
97
|
-
and
|
|
98
|
-
and hasattr(
|
|
99
|
-
and
|
|
80
|
+
is_logged_in(user)
|
|
81
|
+
and user.userprofile
|
|
82
|
+
and hasattr(user.userprofile, "student")
|
|
83
|
+
and user.userprofile.student.class_field is not None
|
|
100
84
|
)
|
|
101
85
|
|
|
102
86
|
|
|
103
87
|
@register.filter(name="is_independent_student")
|
|
104
|
-
def is_independent_student(
|
|
88
|
+
def is_independent_student(user):
|
|
105
89
|
return (
|
|
106
|
-
is_logged_in(
|
|
107
|
-
and
|
|
108
|
-
and hasattr(
|
|
109
|
-
and
|
|
90
|
+
is_logged_in(user)
|
|
91
|
+
and user.userprofile
|
|
92
|
+
and hasattr(user.userprofile, "student")
|
|
93
|
+
and user.userprofile.student.is_independent()
|
|
110
94
|
)
|
|
111
95
|
|
|
112
96
|
|
|
113
97
|
@register.filter(name="has_teacher_finished_onboarding")
|
|
114
|
-
def has_teacher_finished_onboarding(
|
|
115
|
-
teacher =
|
|
116
|
-
|
|
117
|
-
return (
|
|
118
|
-
is_logged_in_as_teacher(u)
|
|
119
|
-
and teacher.has_school()
|
|
120
|
-
and classes
|
|
121
|
-
and (classes.count() > 1 or classes[0].has_students())
|
|
122
|
-
)
|
|
98
|
+
def has_teacher_finished_onboarding(user):
|
|
99
|
+
teacher = user.userprofile.teacher
|
|
100
|
+
return is_logged_in_as_teacher(user) and teacher.has_school()
|
|
123
101
|
|
|
124
102
|
|
|
125
103
|
@register.filter(name="is_logged_in_as_school_user")
|
|
126
|
-
def is_logged_in_as_school_user(
|
|
104
|
+
def is_logged_in_as_school_user(user):
|
|
127
105
|
return (
|
|
128
|
-
is_logged_in(
|
|
129
|
-
and
|
|
106
|
+
is_logged_in(user)
|
|
107
|
+
and user.userprofile
|
|
130
108
|
and (
|
|
131
109
|
(
|
|
132
|
-
hasattr(
|
|
133
|
-
and
|
|
110
|
+
hasattr(user.userprofile, "student")
|
|
111
|
+
and user.userprofile.student.class_field is not None
|
|
134
112
|
)
|
|
135
|
-
or hasattr(
|
|
113
|
+
or hasattr(user.userprofile, "teacher")
|
|
136
114
|
)
|
|
137
115
|
)
|
|
138
116
|
|
|
139
117
|
|
|
140
118
|
@register.filter(name="get_user_status")
|
|
141
|
-
def get_user_status(
|
|
142
|
-
if is_logged_in_as_school_user(
|
|
143
|
-
if is_logged_in_as_teacher(
|
|
119
|
+
def get_user_status(user):
|
|
120
|
+
if is_logged_in_as_school_user(user):
|
|
121
|
+
if is_logged_in_as_teacher(user):
|
|
144
122
|
return "TEACHER"
|
|
145
123
|
else:
|
|
146
124
|
return "SCHOOL_STUDENT"
|
|
147
|
-
elif is_logged_in(
|
|
125
|
+
elif is_logged_in(user):
|
|
148
126
|
return "INDEPENDENT_STUDENT"
|
|
149
127
|
else:
|
|
150
128
|
return "UNTRACKED"
|
|
151
129
|
|
|
152
130
|
|
|
153
131
|
@register.filter(name="make_title_caps")
|
|
154
|
-
def make_title_caps(
|
|
155
|
-
if len(
|
|
156
|
-
|
|
157
|
-
return
|
|
132
|
+
def make_title_caps(string):
|
|
133
|
+
if len(string) > 0:
|
|
134
|
+
string = string[0].upper() + string[1:]
|
|
135
|
+
return string
|
|
158
136
|
|
|
159
137
|
|
|
160
138
|
@register.filter(name="cloud_storage")
|
|
@@ -168,9 +146,6 @@ def get_project_version():
|
|
|
168
146
|
return __version__
|
|
169
147
|
|
|
170
148
|
|
|
171
|
-
@register.
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
return reverse("teacher_aimmo_dashboard")
|
|
175
|
-
else:
|
|
176
|
-
return reverse("student_aimmo_dashboard")
|
|
149
|
+
@register.filter
|
|
150
|
+
def get_dict_item(dictionary, key):
|
|
151
|
+
return dictionary[key]
|
|
@@ -11,9 +11,5 @@ def card_list(context):
|
|
|
11
11
|
- image: the path to the card's image (top-half)
|
|
12
12
|
- title: the heading of the card
|
|
13
13
|
- description (optional): the text paragraph of the card
|
|
14
|
-
- thumbnail_text (optional): text to be shown as the thumbnail
|
|
15
|
-
- thumbnail_image (optional): the path to the image to be shown as the thumbnail
|
|
16
|
-
- button_text (optional): the text on the card's button
|
|
17
|
-
- button_link (optional): the link that the button redirects to
|
|
18
14
|
"""
|
|
19
15
|
return context["CARD_LIST"]
|
portal/tests/base_test.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import socket
|
|
2
2
|
import time
|
|
3
3
|
|
|
4
|
+
from django.contrib.sites.models import Site
|
|
4
5
|
from django.urls import reverse
|
|
5
6
|
|
|
6
7
|
from deploy import captcha
|
|
7
|
-
|
|
8
|
-
# Uncomment to use FireFox
|
|
9
|
-
# master_browser = webdriver.Firefox()
|
|
10
8
|
from portal.tests.pageObjects.portal.home_page import HomePage
|
|
11
9
|
from .selenium_test_case import SeleniumTestCase
|
|
12
10
|
|
|
@@ -41,3 +39,16 @@ class BaseTest(SeleniumTestCase):
|
|
|
41
39
|
else:
|
|
42
40
|
break
|
|
43
41
|
attempts += 1
|
|
42
|
+
|
|
43
|
+
def __call__(self, result=None):
|
|
44
|
+
self._set_site_to_local_domain()
|
|
45
|
+
return super().__call__(result)
|
|
46
|
+
|
|
47
|
+
def _set_site_to_local_domain(self):
|
|
48
|
+
"""
|
|
49
|
+
Sets the Site Django object to the local domain (locally, localhost:8000).
|
|
50
|
+
Needed to generate valid registration and password reset links in tests.
|
|
51
|
+
"""
|
|
52
|
+
current_site = Site.objects.get_current()
|
|
53
|
+
current_site.domain = f"{self.server_thread.host}:{self.server_thread.port}"
|
|
54
|
+
current_site.save()
|
portal/tests/conftest.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
|
-
from unittest.mock import MagicMock
|
|
3
2
|
|
|
4
3
|
import pytest
|
|
5
|
-
from aimmo.models import Game
|
|
6
4
|
from common.models import Class
|
|
7
5
|
from common.tests.utils.classes import create_class_directly
|
|
8
6
|
from common.tests.utils.organisation import create_organisation_directly
|
|
@@ -12,8 +10,6 @@ from common.tests.utils.student import (
|
|
|
12
10
|
)
|
|
13
11
|
from common.tests.utils.teacher import signup_teacher_directly
|
|
14
12
|
|
|
15
|
-
from .utils.aimmo_games import create_aimmo_game_directly
|
|
16
|
-
|
|
17
13
|
SchoolStudent = namedtuple("student", ["username", "password"])
|
|
18
14
|
IndependentStudent = namedtuple("independent_student", ["username", "password"])
|
|
19
15
|
TeacherLoginDetails = namedtuple("teacher", ["email", "password"])
|
|
@@ -41,14 +37,3 @@ def student1(db, class1) -> SchoolStudent:
|
|
|
41
37
|
def independent_student1(db) -> IndependentStudent:
|
|
42
38
|
username, password, _ = create_independent_student_directly()
|
|
43
39
|
return IndependentStudent(username, password)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@pytest.fixture
|
|
47
|
-
def aimmo_game1(db, class1) -> Game:
|
|
48
|
-
return create_aimmo_game_directly(klass=class1, worksheet_id=1)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@pytest.fixture(autouse=True)
|
|
52
|
-
def mock_game_manager(monkeypatch):
|
|
53
|
-
"""Mock GameManager for all tests."""
|
|
54
|
-
monkeypatch.setattr("aimmo.game_creator.GameManager", MagicMock())
|
|
@@ -4,9 +4,7 @@ import pytest
|
|
|
4
4
|
@pytest.mark.django_db
|
|
5
5
|
def test_portaladmin_has_teacher_profile(migrator):
|
|
6
6
|
migrator.apply_initial_migration(("portal", "0060_delete_guardian"))
|
|
7
|
-
new_state = migrator.apply_tested_migration(
|
|
8
|
-
("portal", "0061_make_portaladmin_teacher")
|
|
9
|
-
)
|
|
7
|
+
new_state = migrator.apply_tested_migration(("portal", "0061_make_portaladmin_teacher"))
|
|
10
8
|
|
|
11
9
|
User = new_state.apps.get_model("auth", "User")
|
|
12
10
|
UserProfile = new_state.apps.get_model("common", "UserProfile")
|
|
@@ -34,9 +32,7 @@ def test_portaladmin_has_teacher_profile(migrator):
|
|
|
34
32
|
assert portaladmin_class.teacher == portaladmin_teacher
|
|
35
33
|
|
|
36
34
|
portaladmin_student_user = User.objects.get(username="portaladmin student")
|
|
37
|
-
portaladmin_student_userprofile = UserProfile.objects.get(
|
|
38
|
-
user=portaladmin_student_user
|
|
39
|
-
)
|
|
35
|
+
portaladmin_student_userprofile = UserProfile.objects.get(user=portaladmin_student_user)
|
|
40
36
|
portaladmin_student = Student.objects.get(user=portaladmin_student_userprofile)
|
|
41
37
|
|
|
42
38
|
assert portaladmin_student.class_field == portaladmin_class
|
|
@@ -3,17 +3,11 @@ import pytest
|
|
|
3
3
|
|
|
4
4
|
@pytest.mark.django_db
|
|
5
5
|
def test_preview_user_field_added(migrator):
|
|
6
|
-
migrator.apply_initial_migration(
|
|
7
|
-
("portal", "0054_pending_join_request_can_be_blank")
|
|
8
|
-
)
|
|
6
|
+
migrator.apply_initial_migration(("portal", "0054_pending_join_request_can_be_blank"))
|
|
9
7
|
new_state = migrator.apply_tested_migration(("portal", "0055_add_preview_user"))
|
|
10
8
|
|
|
11
9
|
userprofile_model = new_state.apps.get_model("portal", "UserProfile")
|
|
12
|
-
assert userprofile_model._meta.get_field(
|
|
13
|
-
"preview_user"
|
|
14
|
-
).get_internal_type(), "BooleanField"
|
|
10
|
+
assert userprofile_model._meta.get_field("preview_user").get_internal_type(), "BooleanField"
|
|
15
11
|
|
|
16
12
|
school_model = new_state.apps.get_model("portal", "School")
|
|
17
|
-
assert school_model._meta.get_field(
|
|
18
|
-
"eligible_for_testing"
|
|
19
|
-
).get_internal_type(), "BooleanField"
|
|
13
|
+
assert school_model._meta.get_field("eligible_for_testing").get_internal_type(), "BooleanField"
|
|
@@ -3,9 +3,7 @@ import pytest
|
|
|
3
3
|
|
|
4
4
|
@pytest.mark.django_db
|
|
5
5
|
def test_guardian_model_removed(migrator):
|
|
6
|
-
migrator.apply_initial_migration(
|
|
7
|
-
("portal", "0059_move_email_verifications_to_common")
|
|
8
|
-
)
|
|
6
|
+
migrator.apply_initial_migration(("portal", "0059_move_email_verifications_to_common"))
|
|
9
7
|
new_state = migrator.apply_tested_migration(("portal", "0060_delete_guardian"))
|
|
10
8
|
|
|
11
9
|
model_names = [model._meta.db_table for model in new_state.apps.get_models()]
|
|
@@ -4,9 +4,7 @@ import pytest
|
|
|
4
4
|
@pytest.mark.django_db
|
|
5
5
|
def test_models_moved_to_common(migrator):
|
|
6
6
|
migrator.apply_initial_migration(("portal", "0057_delete_frontpagenews"))
|
|
7
|
-
new_state = migrator.apply_tested_migration(
|
|
8
|
-
("portal", "0058_move_to_common_models")
|
|
9
|
-
)
|
|
7
|
+
new_state = migrator.apply_tested_migration(("portal", "0058_move_to_common_models"))
|
|
10
8
|
|
|
11
9
|
model_names = [model._meta.db_table for model in new_state.apps.get_models()]
|
|
12
10
|
|
|
@@ -20,9 +18,7 @@ def test_models_moved_to_common(migrator):
|
|
|
20
18
|
@pytest.mark.django_db
|
|
21
19
|
def test_emailverification_moved_to_common(migrator):
|
|
22
20
|
migrator.apply_initial_migration(("portal", "0058_move_to_common_models"))
|
|
23
|
-
new_state = migrator.apply_tested_migration(
|
|
24
|
-
("portal", "0059_move_email_verifications_to_common")
|
|
25
|
-
)
|
|
21
|
+
new_state = migrator.apply_tested_migration(("portal", "0059_move_email_verifications_to_common"))
|
|
26
22
|
|
|
27
23
|
model_names = [model._meta.db_table for model in new_state.apps.get_models()]
|
|
28
24
|
|
|
@@ -18,9 +18,7 @@ def test_verify_portaladmin(migrator):
|
|
|
18
18
|
@pytest.mark.django_db
|
|
19
19
|
def test_verify_portaladmin_rollback(migrator):
|
|
20
20
|
migrator.apply_initial_migration(("portal", "0062_verify_portaladmin"))
|
|
21
|
-
new_state = migrator.apply_tested_migration(
|
|
22
|
-
("portal", "0061_make_portaladmin_teacher")
|
|
23
|
-
)
|
|
21
|
+
new_state = migrator.apply_tested_migration(("portal", "0061_make_portaladmin_teacher"))
|
|
24
22
|
|
|
25
23
|
User = new_state.apps.get_model("auth", "User")
|
|
26
24
|
EmailVerification = new_state.apps.get_model("common", "EmailVerification")
|
|
@@ -8,24 +8,3 @@ class AdminBasePage(BasePage):
|
|
|
8
8
|
def __init__(self, browser, live_server_url):
|
|
9
9
|
super(AdminBasePage, self).__init__(browser)
|
|
10
10
|
self.live_server_url = live_server_url
|
|
11
|
-
|
|
12
|
-
def go_to_admin_data_page_failure(self):
|
|
13
|
-
url = self.live_server_url + reverse("aggregated_data")
|
|
14
|
-
self.browser.get(url)
|
|
15
|
-
|
|
16
|
-
return ForbiddenPage(self.browser)
|
|
17
|
-
|
|
18
|
-
def go_to_admin_map_page_failure(self):
|
|
19
|
-
self._go_to_admin_map_page()
|
|
20
|
-
return ForbiddenPage(self.browser)
|
|
21
|
-
|
|
22
|
-
def go_to_admin_map_page(self):
|
|
23
|
-
self._go_to_admin_map_page()
|
|
24
|
-
|
|
25
|
-
from portal.tests.pageObjects.portal.admin.admin_map_page import AdminMapPage
|
|
26
|
-
|
|
27
|
-
return AdminMapPage(self.browser, self.live_server_url)
|
|
28
|
-
|
|
29
|
-
def _go_to_admin_map_page(self):
|
|
30
|
-
url = self.live_server_url + reverse("map")
|
|
31
|
-
self.browser.get(url)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
|
-
from builtins import object
|
|
4
3
|
import time
|
|
4
|
+
from builtins import object
|
|
5
5
|
|
|
6
6
|
from selenium.common.exceptions import TimeoutException
|
|
7
|
+
from selenium.webdriver.common.action_chains import ActionChains
|
|
7
8
|
from selenium.webdriver.common.by import By
|
|
8
9
|
from selenium.webdriver.support import expected_conditions as EC
|
|
9
10
|
from selenium.webdriver.support.ui import WebDriverWait
|
|
10
|
-
from selenium.webdriver.common.action_chains import ActionChains
|
|
11
11
|
|
|
12
|
-
FADE_TIME = 0.
|
|
12
|
+
FADE_TIME = 0.5
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class BasePage(object):
|
|
@@ -40,7 +40,9 @@ class BasePage(object):
|
|
|
40
40
|
self.wait(EC.presence_of_element_located(locator), wait_seconds)
|
|
41
41
|
|
|
42
42
|
def wait_for_absence(self, locator, wait_seconds=DEFAULT_WAIT_SECONDS):
|
|
43
|
-
self.wait_until_not(
|
|
43
|
+
self.wait_until_not(
|
|
44
|
+
EC.presence_of_element_located(locator), wait_seconds
|
|
45
|
+
)
|
|
44
46
|
|
|
45
47
|
def wait(self, method, wait_seconds=DEFAULT_WAIT_SECONDS):
|
|
46
48
|
WebDriverWait(self.browser, wait_seconds).until(method)
|
|
@@ -78,33 +80,21 @@ class BasePage(object):
|
|
|
78
80
|
return self.element_exists_by_id(pageName)
|
|
79
81
|
|
|
80
82
|
def hover_over_resources_dropdown(self):
|
|
81
|
-
resources_dropdown = self.browser.
|
|
82
|
-
"teaching_resources_button"
|
|
83
|
+
resources_dropdown = self.browser.find_element(
|
|
84
|
+
By.ID, "teaching_resources_button"
|
|
83
85
|
)
|
|
84
86
|
hover = ActionChains(self.browser).move_to_element(resources_dropdown)
|
|
85
87
|
hover.perform()
|
|
86
88
|
|
|
87
89
|
def go_to_rapid_router_resources_page(self):
|
|
88
90
|
self.hover_over_resources_dropdown()
|
|
89
|
-
self.browser.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return ResourcesPage(self.browser)
|
|
93
|
-
|
|
94
|
-
def go_to_kurono_resources_page(self):
|
|
95
|
-
self.hover_over_resources_dropdown()
|
|
96
|
-
self.browser.find_element_by_id("kurono_resources_button").click()
|
|
91
|
+
self.browser.find_element(
|
|
92
|
+
By.ID, "rapid_router_resources_button"
|
|
93
|
+
).click()
|
|
97
94
|
from .resources_page import ResourcesPage
|
|
98
95
|
|
|
99
96
|
return ResourcesPage(self.browser)
|
|
100
97
|
|
|
101
|
-
def go_to_kurono_teacher_dashboard_page(self):
|
|
102
|
-
self.browser.find_element_by_id("games_button").click()
|
|
103
|
-
self.browser.find_element_by_id("teacher_kurono_dashboard_button").click()
|
|
104
|
-
from .kurono_teacher_dashboard_page import KuronoTeacherDashboardPage
|
|
105
|
-
|
|
106
|
-
return KuronoTeacherDashboardPage(self.browser)
|
|
107
|
-
|
|
108
98
|
def is_on_admin_login_page(self):
|
|
109
99
|
return self.on_correct_page("administration_login")
|
|
110
100
|
|
|
@@ -119,22 +109,22 @@ class BasePage(object):
|
|
|
119
109
|
|
|
120
110
|
def was_form_invalid(self, formID, error):
|
|
121
111
|
errors = (
|
|
122
|
-
self.browser.
|
|
123
|
-
.
|
|
112
|
+
self.browser.find_element(By.ID, formID)
|
|
113
|
+
.find_element(By.CLASS_NAME, "errorlist")
|
|
124
114
|
.text
|
|
125
115
|
)
|
|
126
116
|
return error in errors
|
|
127
117
|
|
|
128
118
|
def is_dialog_showing(self):
|
|
129
119
|
time.sleep(FADE_TIME)
|
|
130
|
-
return self.browser.
|
|
120
|
+
return self.browser.find_element(By.ID, "popup").is_displayed()
|
|
131
121
|
|
|
132
122
|
def confirm_dialog(self):
|
|
133
|
-
self.browser.
|
|
123
|
+
self.browser.find_element(By.ID, "confirm_button").click()
|
|
134
124
|
time.sleep(FADE_TIME)
|
|
135
125
|
return self
|
|
136
126
|
|
|
137
127
|
def cancel_dialog(self):
|
|
138
|
-
self.browser.
|
|
128
|
+
self.browser.find_element(By.ID, "cancel_button").click()
|
|
139
129
|
time.sleep(FADE_TIME)
|
|
140
130
|
return self
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
|
+
from selenium.webdriver.common.by import By
|
|
4
|
+
|
|
3
5
|
from . import home_page
|
|
4
6
|
from .base_page import BasePage
|
|
5
7
|
|
|
@@ -7,9 +9,8 @@ from .base_page import BasePage
|
|
|
7
9
|
class EmailVerificationNeededPage(BasePage):
|
|
8
10
|
def __init__(self, browser):
|
|
9
11
|
super(EmailVerificationNeededPage, self).__init__(browser)
|
|
10
|
-
|
|
11
12
|
assert self.on_correct_page("emailVerificationNeeded_page")
|
|
12
13
|
|
|
13
14
|
def return_to_home_page(self):
|
|
14
|
-
self.browser.
|
|
15
|
+
self.browser.find_element(By.ID, "home_button").click()
|
|
15
16
|
return home_page.HomePage(self.browser)
|