cfl-common 5.3.0__py3-none-any.whl → 8.9.15__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-8.9.15.dist-info/METADATA +47 -0
- cfl_common-8.9.15.dist-info/RECORD +99 -0
- {cfl_common-5.3.0.dist-info → cfl_common-8.9.15.dist-info}/WHEEL +1 -1
- common/app_settings.py +35 -5
- common/csp_config.py +85 -0
- common/fixtures/aimmo_characters.json +30 -30
- common/fixtures/aimmo_characters2.json +1 -1
- common/fixtures/aimmo_characters3.json +35 -0
- common/helpers/data_migration_loader.py +3 -4
- common/helpers/emails.py +228 -108
- common/helpers/generators.py +1 -1
- common/helpers/organisation.py +10 -0
- common/mail.py +201 -0
- common/migrations/0002_emailverification.py +1 -3
- common/migrations/0005_add_worksheets.py +2 -13
- common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +2 -14
- common/migrations/0008_unlock_worksheet_3.py +1 -6
- common/migrations/0011_student_login_id.py +3 -3
- common/migrations/0012_usersession.py +39 -0
- common/migrations/0013_class_school.py +42 -0
- common/migrations/0014_login_type.py +29 -0
- common/migrations/0015_dailyactivity.py +31 -0
- common/migrations/0016_joinreleasestudent.py +42 -0
- common/migrations/0017_copy_email_to_username.py +18 -0
- common/migrations/0018_update_aimmo_character_image_path.py +15 -0
- common/migrations/0019_aimmocharacter_alt.py +16 -0
- common/migrations/0020_class_is_active_and_null_access_code.py +23 -0
- common/migrations/0021_school_is_active.py +28 -0
- common/migrations/0022_school_cleanup.py +29 -0
- common/migrations/0023_userprofile_aimmo_badges.py +22 -0
- common/migrations/0024_teacher_invited_by.py +25 -0
- common/migrations/0025_schoolteacherinvitation.py +47 -0
- common/migrations/0026_teacher_remove_join_request.py +22 -0
- common/migrations/0027_class_created_by.py +25 -0
- common/migrations/0028_coding_club_downloads.py +23 -0
- common/migrations/0029_dynamicelement.py +22 -0
- common/migrations/0030_add_maintenance_banner.py +25 -0
- common/migrations/0031_improve_admin_panel.py +56 -0
- common/migrations/0032_dailyactivity_level_control_submits.py +18 -0
- common/migrations/0033_password_reset_tracking_fields.py +23 -0
- common/migrations/0034_dailyactivity_daily_school_student_lockout_reset.py +18 -0
- common/migrations/0035_rename_lockout_fields.py +27 -0
- common/migrations/0036_rename_awaiting_email_verification_userprofile_is_verified.py +17 -0
- common/migrations/0037_migrate_email_verification.py +21 -0
- common/migrations/0038_delete_emailverification.py +16 -0
- common/migrations/0039_copy_email_to_username.py +18 -0
- common/migrations/0040_school_county.py +18 -0
- common/migrations/0041_populate_gb_counties.py +27 -0
- common/migrations/0042_totalactivity.py +25 -0
- common/migrations/0043_add_total_activity.py +30 -0
- common/migrations/0044_update_activity_models.py +33 -0
- common/migrations/0045_otp.py +23 -0
- common/migrations/0046_alter_school_country.py +19 -0
- common/migrations/0047_delete_school_postcode.py +16 -0
- common/migrations/0048_unique_school_names.py +42 -0
- common/migrations/0049_anonymise_orphan_users.py +29 -0
- common/migrations/0050_anonymise_orphan_schools.py +30 -0
- common/migrations/0051_verify_returning_users.py +26 -0
- common/migrations/0052_add_cse_fields.py +68 -0
- common/migrations/0053_clean_class_data.py +24 -0
- common/migrations/0054_delete_aimmo_models.py +20 -0
- common/migrations/0055_alter_schoolteacherinvitation_token.py +18 -0
- common/migrations/0056_set_non_school_teachers_as_non_admins.py +25 -0
- common/migrations/0057_teacher_teacher__is_admin.py +19 -0
- common/migrations/0058_userprofile_google_refresh_token_and_more.py +24 -0
- common/models.py +347 -63
- common/permissions.py +20 -8
- common/static/common/img/RR_logo.svg +336 -0
- common/static/common/img/brain.svg +1 -0
- common/templates/common/onetrust_cookies_consent_notice.html +6 -6
- common/tests/test_migration_anonymise_orphan_schools.py +30 -0
- common/tests/test_migration_anonymise_orphan_users.py +30 -0
- common/tests/test_migration_blocked_time.py +3 -11
- common/tests/test_migration_remove_teacher_title.py +1 -3
- common/tests/test_migration_unique_school_names.py +33 -0
- common/tests/test_migration_verify_returning_users.py +59 -0
- common/tests/test_models.py +49 -43
- common/tests/utils/classes.py +1 -3
- common/tests/utils/email.py +11 -49
- common/tests/utils/organisation.py +10 -14
- common/tests/utils/student.py +14 -67
- common/tests/utils/teacher.py +16 -38
- common/tests/utils/user.py +1 -3
- cfl_common-5.3.0.dist-info/METADATA +0 -20
- cfl_common-5.3.0.dist-info/RECORD +0 -48
- common/email_messages.py +0 -218
- common/fixtures/unlock_worksheet3.json +0 -20
- common/fixtures/worksheets.json +0 -98
- common/fixtures/worksheets2.json +0 -110
- common/tests/test_migration_aimmo_characters.py +0 -31
- common/tests/test_migration_worksheets.py +0 -49
- {cfl_common-5.3.0.dist-info → cfl_common-8.9.15.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.91 423.62"><defs><style>.d{fill:#f9c5db;}.e{fill:#fff;}.f{fill:#666;}.g{fill:#db5d90;}.h{fill:#afafaf;}.i{fill:#5b5a5b;}.j{opacity:.2;}</style></defs><g id="a"/><g id="b"><path class="d" d="M442.29,190.69c-4.39-18.43-13.61-35.22-22.63-51.72-2.21-4.04-4.38-8.11-6.49-12.2-.07-.13-.15-.37-.24-.62-.09-.56-.22-1.26-.27-1.5-.35-1.67-.71-3.47-.94-5.22,.17,.84,.17-2.04,.07-3.29-.21-2.8-.49-5.71-1.13-8.45-1.27-5.43-4.12-9.99-7.23-14.49-2.25-3.27-4.6-6.48-6.59-9.92-.51-.88-.98-1.79-1.46-2.69-.01-.03-.03-.06-.04-.09-.1-.52-.3-1.36-.42-1.68,0-.08,0-.15,0-.24-.25-7.47-1.39-15.18-3.36-22.4-4.34-15.9-13.85-30.79-29.48-37.38-10.06-4.25-21.31-5.05-31.65-1.16-5.07,1.91-9.75,4.4-14.44,7.09-.67,.38-1.33,.76-2,1.14-.09-.07-.17-.13-.24-.18-.89-.7-1.77-1.4-2.66-2.09-4.9-3.81-9.64-7.47-15.34-10-12.16-5.41-25.49-7.1-38.72-7.13-6-3.36-12.68-5.63-20.27-6.29-19.81-1.71-35.07,9.1-50.05,19.98-1.84,.87-3.65,1.79-5.43,2.76-11.73-2.88-23.23-6.51-35.37-7.64-16.82-1.56-32.38,3.66-45.25,14.38-5.58,4.65-10.45,10.7-14,17.38-11.73-2.99-24.82-.3-33.89,8.54-2.85,2.78-5.27,6.15-6.98,9.75-.74,1.55-1.52,3.11-2.19,4.69-6.99,3.63-13.43,6.54-18.48,13.08-5.54,7.17-8.17,15.32-9.36,24.21-.58,4.3-.78,8.52-.87,12.85-.03,1.77-.06,3.54-.14,5.32-.05,1.17-.2,2.35-.22,3.52,0,.05,0,.07,0,.11-.02,.05-.03,.09-.05,.16-.27,.86-1.49,4.85-.87,3.73-.57,1.18-1.24,2.31-1.87,3.45-2.45,4.43-4.95,9.05-6.21,13.98-2.6,10.17-.92,20.53,1.19,30.62,1.99,9.53,5.06,19.27,9.72,28.06-.18,.57-.32,1.16-.42,1.77-2.48,14.32-4.41,28.45-1.82,42.89,2.62,14.62,11.3,25.55,22.21,35.04,2.12,1.85,4.25,3.69,6.2,5.72,.6,.63,3.12,4.22,1.03,.93,.88,1.38,1.76,2.72,2.57,4.15,3.65,6.37,7.45,12.39,12.6,17.71,5.44,5.63,12.04,12.23,19.71,14.34,1.1,.3,2.19,.49,3.27,.58,1.27,1.04,2.59,2.03,3.93,3,.49,1.1,1.04,2.17,1.63,3.23,2.77,4.92,7.75,7.89,13.06,8.76,.6,.65,1.2,1.31,1.79,1.97,3.76,4.21,7.45,8.48,11.09,12.8,1.53,1.81,3.04,3.64,4.52,5.49,.29,.36,1.27,1.64,1.56,2,.5,.66,.99,1.33,1.48,2,3.11,4.29,6.03,8.73,8.6,13.37,5.42,9.78,8.61,19.81,17.84,26.94,10.02,7.75,22.28,10.02,34.59,11.32,12.11,1.27,25.35,.72,34.91-7.83,21.04-18.81,.59-49.34-14.08-65.08-8.43-9.04-18.2-16.49-28.57-23.08,9.77-2.69,18.56-7.88,24.67-16.9,2.18-3.21,3.76-6.87,4.87-10.57,.23-.78,.41-1.57,.57-2.36,1.78-1.12,3.91-2.13,5.26-3.14,4.02-3.01,7.77-6.12,11.24-9.74,4.61-4.8,6.41-12.13,4.66-18.46,2.6-.17,5.2-.64,7.81-1.01,9.57-1.35,19.14-2.8,28.66-4.47,18.7-3.27,37.29-7.36,55.41-13.08,12.41-3.92,24.3-9.45,36.49-14.02,4.91,.32,9.79-1.21,13.52-4.49,.5-.14,.99-.29,1.49-.42,17.65-4.73,36.7,1.28,53.41-7.59,4.09-2.17,7.51-5.13,10.14-8.66,7.9-3.99,12.07-12.5,9.92-21.51Zm-161.74-110.32c.03-.22,.05-.45,.08-.71,.06,.04,.01,.32-.08,.71Zm-116.35,174.2l-.05-.28c.14,.03,.27,.05,.41,.07-.12,.07-.24,.14-.36,.21Zm217.74-50.6c0,.43,0,.86,.03,1.28-.22,0-.44,.02-.66,.03,.21-.44,.42-.87,.63-1.31ZM313.52,25.5s-.03-.02,0,0h0ZM43.06,70.85c-.27,.26-.42,.24,0,0h0Zm160.22,227.41c-.17,.09-.71,.52-1.66,1.28,.47-.68,1.21-1.3,2.08-1.89-.13,.21-.27,.41-.42,.61Z"/><path class="f" d="M151.43,412.81c-21.81-28.05-42.03-56.46-67.07-81.79l.29-.41c22.02,15.35,39.34,36.47,53.86,58.84,4.84,7.49,9.37,15.17,13.38,23.14l-.45,.22h0Z"/><path class="f" d="M137.94,258.21c17.21,15.87,21.48,40.05,4.62,57.96-8.03,8.83-18.23,15.19-28.93,20.23-1.05,.49-2.13,.96-3.3,1.43-.68,.12-1.32,.3-1.87,.36-30.97,3.76-53.28-17.65-62.97-45.27l2.16,2.23c-.95-.43-1.69-.81-2.51-1.23-14.65-7.92-28.03-20.03-34-35.9-3.7-9.79-3.97-20.93-1.03-30.81l.49,.1c-1.11,5.8-1.49,11.76-.59,17.61,3.02,21.31,20.64,37.47,39.34,46.21l.16,.07,.06,.16c2.39,6.17,5.35,12.12,9.04,17.59,3.64,5.46,8.13,10.45,13.32,14.47,10.28,7.99,24.34,11.99,36.99,9.88,14.78-6.28,30.14-15.16,38.07-29.65,5.83-11.05,4.01-24.66-2.15-35.19-2.02-3.56-4.43-6.94-7.24-9.9l.35-.36h0Z"/><path class="f" d="M27.46,222.17c-8.91-6.16-15.79-14.98-20.61-24.63-15.83-30.94-2.67-67.45,23.43-88.04l.37,.33c-3.06,3.58-7.03,8.52-9.64,12.33-19.27,27.09-22.14,59.5-3.07,87.55,2.88,4.34,6.14,8.46,9.86,12.09l-.33,.37h0Z"/><path class="f" d="M22.29,119.02c-3.79-12.15-4.93-27.75,2.01-39.02,2.02-3.31,5.16-6.1,8.75-7.72,2.72-1.24,5.28-2.55,7.75-4.04,4.52-2.89,8.94-6.32,11.66-10.9,.44-1.01,1.09-1.78,1.7-2.61,7.74-9.88,20.64-13.83,30.48-4.47l-.27,.42c-7.43-4.82-16.18-4.26-22.64,1.9-2.02,1.85-3.81,4.01-5.19,6.35-.5,1.23-1.54,2.88-2.46,4.08-2.88,3.82-6.63,6.9-10.64,9.45-5.14,3.49-11.89,4.55-15.37,10.16-6.63,10.14-6.39,24.65-5.28,36.34l-.49,.07h0Z"/><path class="f" d="M101.06,97.94c-16.06-4.22-25.06-17.92-19.42-34.18,3.35-9.68,8.2-19.07,14.86-26.9,7.87-9.22,18.31-16.7,30.21-19.57,7.99-1.66,16.54-.12,23.9,2.21,5.9,1.98,11.57,4.42,16.77,7.71l-.21,.45c-5.53-2.37-11.31-4.21-17.17-5.54-5.85-1.35-11.9-2.06-17.86-1.54-19.17,2.75-34.69,19.81-42.92,36.44-1.4,2.91-3.37,7.3-4.37,10.37-2.09,6.36-1.5,13.63,2.44,19.16,3.38,4.92,8.47,8.6,13.93,10.92l-.17,.47h0Z"/><path class="f" d="M222.86,8.58c-20.62-.37-39.77,10.41-49.37,28.44-4.75,8.27-7.95,17.74-6.82,27.2,1.23,9.55,6.94,18.16,14.57,23.91,4.25,4.33,10.56,7.19,16.69,6.2,.72-.1,2.24-.35,2.97-.45,3.74,5.24,4.49,13.15-.44,17.83-.56,.59-1.23,1.06-1.82,1.58l-.34-.37c.51-.57,1.08-1.09,1.54-1.7,3.55-4.25,2.88-10.56-.25-14.86l.33,.11c-7.4,2.48-16.1-.49-21.36-5.5-13.67-9.24-20.29-25.92-15.53-41.88,4.54-15.12,14.77-28.97,29.08-36.04,9.5-4.65,20.36-6.44,30.84-4.94l-.09,.49h0Z"/><path class="f" d="M208.82,29.72c3.06-6.17,8.58-11.41,15.39-13.1,2.3-.67,4.72-.73,7.11-.68l-.77,.11c16.73-7,45.75-16.61,61.69-4.02,7.33,5.02,15.97,7.39,23.17,12.95,4.68,3.47,8.18,8.46,10.46,13.78,1.22,3.08,2.03,5.92,2.74,9.13,.71,3.17,1.3,7.92,1.74,11.16,.83,5.5,1.47,11.05,2.98,16.39,.04,.11,.06,.12,.08,.18l.03,.08v.04l.12,.23c.58,1.26,.96,2.72,1.27,3.99,1.87,8.86,3.6,21.66-2.41,29.43-1.54,1.93-4.03,3.42-6.55,3.93-.42,.12-.86,.19-1.3,.35-16.56,5.08-47.28,23.42-63.2,11.85-6.73-4.79-10.14-12.9-11.28-20.77-.78-6.24-.79-12.78,2.13-18.55l2.06,2.61c-2.85,.53-5.61,.37-8.39-.26-8.19-1.76-13.79-8.51-16.56-16.05l.46-.2c.8,1.65,1.73,3.49,2.78,5.01,3.07,4.79,7.98,8.53,13.64,9.53,2.69,.52,5.51,.46,8.14-.19-1.47,2.7-1.91,5.86-2.05,8.95-.25,8.56,1.87,17.79,7.81,24.18,3.98,4.42,9.75,6.23,15.6,5.58,11.62-1.15,22.5-6.08,33.19-10.54,5.41-2.24,10.71-4.85,16.43-6.3,1.33-.34,2.51-1.12,3.38-2.19,4.89-6.41,2.84-20.94,.33-28.21-2.14-5.93-2.56-12.25-3.53-18.42-.41-3.14-.94-7.72-1.61-10.81-1.55-7.71-4.88-15.51-11.3-20.37-4.54-3.65-10.02-5.9-15.15-8.62-3.91-1.96-7.52-4.61-11.12-7.04-11.31-6.02-26.41-3-38.37-.24-5.68,1.43-11.3,3.16-16.76,5.24-2.22-.14-4.47-.2-6.64,.34-6.51,1.35-11.99,6.1-15.28,11.76l-.44-.23h0Z"/><path class="f" d="M311.48,27.06c7.57-7.87,18.84-16.99,30.49-16.05,19.31,2.51,43.75,14.12,48.92,34.68,2.45,10.77,3.61,23.1-1.2,33.42l.56-2.4c.1,1.11,.37,2.25,.78,3.27,.7,1.67,1.64,2.83,3.15,3.59,2.07,.77,4.18,1.3,6.27,2.21,10.93,4.24,17.68,15.08,15.89,26.8-1.25,10.43-9.13,19.74-18.77,22.96l-.21-.45c2.92-1.43,5.63-3.28,7.95-5.55,9.36-8.81,11.67-25.51,1.81-34.8-2.35-2.21-5.2-3.83-8.23-4.98-3.02-1.32-6.58-1.49-9.14-3.79-2.58-2.27-3.91-5.6-4.27-8.97-.02-.13,0-.14,.06-.25,3.97-9.4,2.6-20.19,.56-29.93-3.84-15.21-18.86-24.21-32.65-29.45-4.77-1.63-9.71-3.37-14.79-3.43-5.09,.17-9.93,2.26-14.35,4.67-4.45,2.49-8.65,5.48-12.5,8.81l-.34-.37h0Z"/><path class="f" d="M359.05,101.57c13.08,1.53,24.07,11.47,26.11,24.71,.67,3.96,.78,8.16,1.35,12.13,1.07,7.82,2.37,15.62,4.23,23.29,1.25,6.09,3.42,11.85,4.34,17.9,2.43,14.92-1.95,31.82-15.54,40.1-1.26,.74-2.86,1.69-4.15,2.37-11.26,5.92-28.2,16.39-39.67,21.84-3.69,1.7-7.55,3.38-11.68,3.84l-.09-.49c3.87-.87,7.44-2.86,10.92-4.83,13.81-8.27,26.97-17.62,40.96-25.61,10.81-6.29,15.41-18.47,14.87-30.57-.02-8.12-3.05-15.71-4.56-23.57-2.06-9.87-3.46-19.9-3.93-29.97,.25-15.5-8.16-26.76-23.25-30.64l.09-.49h0Z"/><path class="f" d="M408.01,132.23c6.68-3.19,14.64-.21,18.26,6.23,1.17,1.85,2.09,4.26,2.89,6.27,1.48,3.8,2.98,8.11,4.41,11.95,2.12,6.22,4.76,13.86,6.71,20.1,1.85,5.6,3.4,11.49,3.76,17.45,.28,4.71,.02,10.32-2.47,14.72-2.31,3.88-4.61,7.65-7.83,11.03-8.16,9.08-21.38,12.19-33.04,10.72l-.02-.5c8.38-.47,16.91-2.31,23.87-7.15,6.1-4.2,10.11-10.66,13.43-17.15,2.27-6.27,1.15-13.21-.15-19.59-2.42-9.3-6.87-23.16-9.55-32.51-1.22-3.7-2.83-10.58-4.58-14.01-2.71-5.92-9.27-8.91-15.53-7.09l-.16-.47h0Z"/><path class="f" d="M221.65,273.51c2.26,9.89-2.86,20.36-10.84,26.3-8.02,5.94-18.74,7.75-28.08,4.56l-.02-.5c2.02-.15,4.73-.37,6.68-.71,13.4-1.78,25.65-10.16,30.09-23.24,.76-2.09,1.38-4.26,1.67-6.45l.5,.04h0Z"/><path class="f" d="M200.07,300.72c3.54,4.74,5.27,12.19,.36,16.88-1.33,1.29-2.95,2.41-4.44,3.5-8.96,6.27-19.78,11.25-31.01,10.18-8.27-.2-18.35-1.37-22.86-9.37-1.38-2.44-2.16-5.13-2.46-7.88l.47-.17c2.37,6.69,7.42,11.59,14.64,12.33,3.36,.49,6.8,.35,10.25,.37,3.47,.14,6.78-.08,10.12-.96,7.46-1.85,14.5-5.27,21.05-9.25,.7-.44,1.46-.88,2.1-1.42,4.09-3.36,2.96-9.61,1.32-14l.46-.2h0Z"/><path class="f" d="M176.12,326.86c24.94,11.54,50.15,41.47,49.33,70.03l-.49,.09c-4.51-21.44-17.93-39.76-32.96-55.19-5.11-5.13-10.46-10.07-16.17-14.53l.3-.4h0Z"/><path class="f" d="M137.61,234.31c-12.87-5.26-28.97-12.85-41.88-7.04-1.34,.62-3.31,1.96-4.59,2.75-11.69,7.35-22.74,15.2-34.81,22.2l-.34-.37c5.77-5.42,11.8-10.57,18.04-15.44,4.67-3.67,9.46-7.19,14.4-10.49,1.66-1.08,3.28-2.22,5.1-3.14,3.65-1.77,7.74-2.47,11.74-2.33,12.02,.6,23.14,6.48,32.65,13.46l-.31,.4h0Z"/><path class="f" d="M90.49,123.12c6.33,13.05,6.79,31.3-5.1,41.5-10.92,8.88-24.57,16.5-39.18,15.65-4.18-.4-8.44-1.75-11.45-4.52l.24-.44c6.92,3.68,15.23,2.4,22.36-.05,7.28-2.54,14.04-6.47,20.3-10.98,3.08-2.25,6.3-4.46,8.52-7.63,4.53-6.27,5.59-14.37,5.32-21.95-.14-3.85-.61-7.72-1.49-11.46l.48-.13h0Z"/><path class="f" d="M76.79,174.22c3.7,1.29,6.73,4.02,9.14,7.02,7.21,9.2,8.66,21.88,5.65,32.96l-.13-1.32c.12,.93,.23,1.85,.32,2.79,.25,2.86,.4,5.72,.17,8.61l-.48,.15c-1.04-3.12-2.49-7.38-3.46-10.47,1.28-13.81-1.06-29.39-11.54-39.35l.31-.39h0Z"/><path class="f" d="M161.1,151.64c18.17-8.77,42.86,4.98,40,26.29l-.49,.11c-1.08-4.19-2.72-8.24-5.15-11.81-6.15-9.08-17.16-13.47-27.83-14.07-2.16-.15-4.34-.19-6.48-.02l-.06-.5h0Z"/><path class="f" d="M195.26,197.53c9.79-9.84,24.22-14.13,37.94-13.48,1.11,.1,3.32,.32,4.42,.46,7.16,1.13,14.35,2.25,21.07,5.18,1.06,.51,2.08,1.12,2.81,2.1,1.44,1.78,1.05,4.71-.91,5.97l-4.67-6.12c4.01-2.82,8.54-4.73,13.23-6.02,4.5-1.22,9.21-1.75,13.86-1.45l.08,.49c-6.59,1.14-13.01,3.31-18.85,6.56-1.93,1.09-3.84,2.29-5.53,3.67l-.52-.68c-.19,.12-.03,.28-.13,.16-.82-.7-2-.99-3.03-1.34-3.93-1.17-8-1.9-12.05-2.61-5.43-.94-10.83-1.83-16.31-1.67-10.9,.26-21.85,3.41-31.11,9.19l-.29-.41h0Z"/><path class="f" d="M280.33,149.53c21.07,10.79,41.84,14.23,63.49,3.14,4.86-2.38,9.69-5.07,14.86-7l.29,.41-8.8,6.36c-8.7,6.56-19.03,11.36-30.03,11.98-14.62,.82-29.2-4.98-40.14-14.52l.34-.37h0Z"/><path class="f" d="M181.26,213.67c9.93,6.09,14.18,19.54,8.98,30.15-2.37,5.24-6.32,9.39-10.53,13.13-.7,.55-2.55,1.99-3.24,2.52-.76,.57-2.62,1.68-3.41,2.24-8.4,4.91-18.22,8-27.95,7.45l-.08-.49c7.4-1.54,14.6-4.36,21.17-8.09,2.82-1.6,5.82-3.63,8.32-5.7,6.91-5.72,13.87-13.25,13.91-22.75,.06-6.69-3.05-13.21-7.53-18.09l.35-.36h0Z"/><path class="f" d="M167.22,124.02c16.67-8.3,39.6-10.49,56.5-1.46,1.18,.63,2.62,1.58,3.71,2.33,6.81,5.05,13.4,10.22,19.4,16.43l-.27,.42-9.05-5.51c-3.22-1.95-10.39-6.51-13.52-8.33-1.47-.86-3.13-1.66-4.7-2.3-13.13-5.17-27.76-4.86-41.56-2.99-3.49,.48-6.97,1.08-10.39,1.89l-.13-.48h0Z"/><path class="g" d="M340.25,209.52c-25.34,51.85-74.22,96.17-129.16,52.06-5.91-4.68-11.34-9.88-16.4-15.37,16.15,14.34,36.02,27.42,58.32,26.95,29.45-1,49.96-26.56,62.8-50.65,3.26-6.21,6.29-12.71,8.64-19.29,1.48-4.46,6.3-6.88,10.76-5.4,4.81,1.56,7.2,7.13,5.03,11.69h0Z"/><path class="g" d="M450.9,222.82c-3.86,14.01-12.5,26.41-23.37,35.88-8.87,7.57-19.71,13.2-30.75,16.3-38.57,10.56-80.42-1.74-116.27-16.32,22.35,6.65,45.15,11.56,68.41,12.15,1.99,0,6.67-.07,8.57-.09,1.81-.07,6.59-.45,8.5-.58l5.59-.75c17.07-2.47,33.77-9.13,45.66-21.69,7.23-7.71,12.77-17.29,14.99-27.65,.57-5.45,5.76-9.39,11.19-8.31,5.12,.99,8.48,5.94,7.49,11.06h0Z"/><g><path class="e" d="M328.57,220.35c-.65,0-1.3-.03-1.94-.08-16.21-1.28-28.15-18.25-26.61-37.84,1.47-18.67,14.76-33.29,30.26-33.29,.65,0,1.3,.03,1.94,.08,16.21,1.28,28.15,18.25,26.61,37.84-1.47,18.67-14.76,33.29-30.26,33.29Z"/><path class="h" d="M330.28,147.64v3h0c.6,0,1.22,.02,1.82,.07,15.39,1.21,26.71,17.46,25.23,36.23-1.41,17.89-14.04,31.91-28.76,31.91-.61,0-1.22-.02-1.83-.07-15.39-1.21-26.71-17.46-25.23-36.23,1.41-17.89,14.04-31.91,28.76-31.91v-3m0,0c-16.21,0-30.21,15.05-31.75,34.67-1.61,20.45,10.92,38.11,27.98,39.46,.69,.05,1.38,.08,2.06,.08,16.21,0,30.21-15.05,31.75-34.67,1.61-20.45-10.92-38.11-27.98-39.46-.69-.05-1.38-.08-2.06-.08h0Z"/></g><ellipse class="i" cx="334.82" cy="199.39" rx="13.2" ry="9.39" transform="translate(39 453.06) rotate(-71.39)"/><g><path class="e" d="M446.3,231.11c-1.21,0-2.43-.1-3.63-.29-15.09-2.39-25.01-19.17-22.12-37.41,2.62-16.55,15.08-29.03,28.97-29.03,1.21,0,2.43,.1,3.63,.29,15.09,2.39,25.01,19.17,22.12,37.41-2.62,16.55-15.08,29.03-28.97,29.03Z"/><path class="h" d="M449.52,165.88h0c1.13,0,2.27,.09,3.39,.27,14.27,2.26,23.63,18.27,20.87,35.7-2.51,15.83-14.33,27.77-27.49,27.77-1.13,0-2.27-.09-3.39-.27-14.27-2.26-23.63-18.27-20.87-35.7,2.51-15.83,14.33-27.76,27.49-27.77m0-3c-14.48,0-27.67,12.76-30.45,30.3-3.02,19.09,7.44,36.61,23.37,39.13,1.29,.2,2.58,.3,3.86,.3,14.48,0,27.67-12.76,30.45-30.3,3.02-19.09-7.44-36.61-23.37-39.13-1.29-.2-2.58-.3-3.86-.3h0Z"/></g><ellipse class="i" cx="446.51" cy="209.6" rx="12.44" ry="8.84" transform="translate(78.46 537.99) rotate(-66.89)"/></g><g id="c"><g class="j"><polygon class="e" points="329.42 118.98 367.62 124.71 301.63 213.52 283.04 209.6 267.19 191.08 329.42 118.98"/></g><g class="j"><polygon class="e" points="265.79 162.67 265.79 110.28 280.5 109.04 306.96 113.1 265.79 162.67"/></g><g class="j"><polygon class="e" points="469.91 148.92 504.3 154.03 444.89 233.05 428.16 229.56 413.89 213.08 469.91 148.92"/></g><g><path d="M510.06,159.47c-1.72-6.02-6.83-10.58-13.04-11.65l-69.11-14.88c-.07-.01-.14-.03-.21-.04-.22-.04-.87-.14-1.8-.2,.43-.03,.68-.02,.68-.02l-63.81-15.39s.09,.05,.14,.08c-.13-.02-.26-.06-.39-.08l-81.21-13.19c-.51-.08-3-.45-6.09-.21-.4-.09-.8-.14-1.22-.12-3.73,.15-92.16,3.94-158.51,31.15-1.6,.65-2.74,2.09-3.03,3.79-.17,.98-3.97,24.18,5.96,42.8,2.22,4.17,5,7.83,8.25,10.88,.7,.66,1.58,1.1,2.53,1.28,1.15,.21,2.92,.46,4.89,.46,3.22,0,6.94-.67,9.21-3.26,1.08-1.23,2.68-3.9,1.36-7.97-.85-2.63-3.66-4.03-6.29-3.18-1.97,.64-3.27,2.41-3.43,4.37-.72,.04-1.62,.02-2.51-.06-1.99-2.08-3.73-4.5-5.18-7.22-6.52-12.22-5.86-27.59-5.26-33.71,49.43-19.59,112.16-26.35,139.12-28.46-.19,.94-.32,1.95-.32,3.07v66.73c0,.12,0,.24,.01,.36,.06,.88,1.75,21.62,20.3,29.43,11.43,4.81,43.5,6.74,68.38,7.52,.28,0,.55,.01,.82,.01,11.7,0,21.98-7.74,25.19-19.07l.23-.84c3.05-11.22,3.54-40.64,3.62-51.05,1.2-3.01,3.1-4.63,5.93-6.52,7.68-5.14,18.12-2.75,22.92,5.14,.42,.69,.82,1.4,1.21,2.11v53.78c0,.1,0,.21,.01,.31,.06,.79,1.55,19.46,18.05,26.51,10.37,4.43,37.17,6.13,57.82,6.78,.25,0,.49,.01,.74,.01,10.42,0,19.58-6.98,22.43-17.2l.2-.74c3.21-11.98,3.23-47.01,3.23-49.25,.02-.85,.04-5.71-1.84-12.26Zm-140.69-12.46s0,.09,0,.13c.02,11.06-.54,41.98-3.28,52.06l-.21,.75c-2.03,7.17-8.61,12.03-16.08,11.78-33.48-1.04-57.11-3.49-64.81-6.74-12.31-5.19-14.03-19.14-14.19-20.79V117.69c0-1.77,.62-2.3,.88-2.52,1.65-1.41,5.77-1.54,8.03-1.19l81.22,13.19c3.23,.53,5.9,2.83,6.78,5.87,1.83,6.29,1.67,13.9,1.67,13.97Zm133.58,24.48c0,.06,0,.12,0,.19,.01,9.98-.49,37.88-2.93,46.98l-.18,.67c-1.8,6.47-7.66,10.83-14.26,10.63-27.7-.87-47.6-3.08-54.59-6.07-10.96-4.68-12.48-17.3-12.62-18.78v-59.99c0-1.64,.57-2.12,.81-2.33,1.44-1.23,4.99-1.36,6.97-1.06l69.08,14.87c.07,.02,.14,.03,.21,.04,2.86,.47,5.22,2.55,6.01,5.3,1.6,5.58,1.49,9.53,1.49,9.55Z"/><path d="M431.58,118.93c2.88-2.73,6.23-4.98,9.71-6.86,10.9-6.05,23.5-5.13,33.14,2.88,1.88,2.01,4.26,4.78,6,7.27,1.74,2.53,3.65,5.26,4.1,8.34,.03,.36,.57,.4,.66,.06,1.36-5.31-1.24-10.84-3.68-15.43-1-1.64-1.88-3.43-3.32-4.86-3.2-3.28-7.29-6.04-11.99-7.63-13.51-4.78-29.72,2.7-35.13,15.74l-.04,.11c-.15,.32,.31,.63,.55,.37Z"/><path d="M297.47,90.2c2.88-2.73,6.23-4.98,9.71-6.86,10.9-6.05,23.5-5.13,33.14,2.88,1.88,2.01,4.26,4.78,6,7.27,1.74,2.53,3.65,5.26,4.1,8.34,.03,.36,.57,.4,.66,.06,1.36-5.31-1.24-10.84-3.68-15.43-1-1.64-1.88-3.43-3.32-4.86-3.2-3.28-7.29-6.04-11.99-7.63-13.51-4.78-29.72,2.7-35.13,15.74l-.04,.11c-.15,.32,.31,.63,.55,.37Z"/></g><path class="d" d="M246.7,141.54s-45.89-33.79-87.25-15.71c-41.36,18.08-12.08,29.13-12.08,29.13l39-19.62,60.33,6.21Z"/></g></svg>
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
<!-- OneTrust Cookies Consent Notice start for codeforlife.education -->
|
|
2
2
|
{% if module_name == "default" %}
|
|
3
|
-
<script type="text/javascript" src="https://cdn-ukwest.onetrust.com/consent/
|
|
4
|
-
<script src="https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="
|
|
3
|
+
<script type="text/javascript" src="https://cdn-ukwest.onetrust.com/consent/5da42396-cb12-4493-8d04-5179033cfbad/OtAutoBlock.js" ></script>
|
|
4
|
+
<script src="https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="5da42396-cb12-4493-8d04-5179033cfbad" ></script>
|
|
5
5
|
<script type="text/javascript">
|
|
6
|
-
|
|
6
|
+
function OptanonWrapper() { }
|
|
7
7
|
</script>
|
|
8
8
|
{% elif cookie_management_enabled %}
|
|
9
|
-
<script type="text/javascript" src="https://cdn-ukwest.onetrust.com/consent/
|
|
10
|
-
<script src="https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="
|
|
9
|
+
<script type="text/javascript" src="https://cdn-ukwest.onetrust.com/consent/5da42396-cb12-4493-8d04-5179033cfbad-test/OtAutoBlock.js" ></script>
|
|
10
|
+
<script src="https://cdn-ukwest.onetrust.com/scripttemplates/otSDKStub.js" type="text/javascript" charset="UTF-8" data-domain-script="5da42396-cb12-4493-8d04-5179033cfbad-test" ></script>
|
|
11
11
|
<script type="text/javascript">
|
|
12
|
-
|
|
12
|
+
function OptanonWrapper() { }
|
|
13
13
|
</script>
|
|
14
14
|
{% endif %}
|
|
15
15
|
<!-- OneTrust Cookies Consent Notice end for codeforlife.education -->
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from django_test_migrations.migrator import Migrator
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@pytest.mark.django_db
|
|
6
|
+
def test_migration_anonymise_orphan_schools(migrator: Migrator):
|
|
7
|
+
state = migrator.apply_initial_migration(
|
|
8
|
+
("common", "0049_anonymise_orphan_users")
|
|
9
|
+
)
|
|
10
|
+
User = state.apps.get_model("auth", "User")
|
|
11
|
+
UserProfile = state.apps.get_model("common", "UserProfile")
|
|
12
|
+
Teacher = state.apps.get_model("common", "Teacher")
|
|
13
|
+
School = state.apps.get_model("common", "School")
|
|
14
|
+
|
|
15
|
+
orphan_school = School.objects.create(name="OrphanSchool")
|
|
16
|
+
teacher_school = School.objects.create(name="TeacherSchool")
|
|
17
|
+
|
|
18
|
+
teacher_user = User.objects.create_user("TeacherUser", password="password")
|
|
19
|
+
teacher_userprofile = UserProfile.objects.create(user=teacher_user)
|
|
20
|
+
Teacher.objects.create(
|
|
21
|
+
user=teacher_userprofile, new_user=teacher_user, school=teacher_school
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
migrator.apply_tested_migration(("common", "0050_anonymise_orphan_schools"))
|
|
25
|
+
|
|
26
|
+
def assert_school_anonymised(pk: int, anonymised: bool):
|
|
27
|
+
assert School.objects.get(pk=pk).is_active != anonymised
|
|
28
|
+
|
|
29
|
+
assert_school_anonymised(orphan_school.pk, True)
|
|
30
|
+
assert_school_anonymised(teacher_school.pk, False)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from django_test_migrations.migrator import Migrator
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@pytest.mark.django_db
|
|
6
|
+
def test_migration_anonymise_orphan_users(migrator: Migrator):
|
|
7
|
+
state = migrator.apply_initial_migration(
|
|
8
|
+
("common", "0048_unique_school_names")
|
|
9
|
+
)
|
|
10
|
+
User = state.apps.get_model("auth", "User")
|
|
11
|
+
UserProfile = state.apps.get_model("common", "UserProfile")
|
|
12
|
+
Teacher = state.apps.get_model("common", "Teacher")
|
|
13
|
+
Student = state.apps.get_model("common", "Student")
|
|
14
|
+
|
|
15
|
+
orphan_user = User.objects.create_user("OrphanUser", password="password")
|
|
16
|
+
teacher_user = User.objects.create_user("TeacherUser", password="password")
|
|
17
|
+
student_user = User.objects.create_user("StudentUser", password="password")
|
|
18
|
+
teacher_userprofile = UserProfile.objects.create(user=teacher_user)
|
|
19
|
+
student_userprofile = UserProfile.objects.create(user=student_user)
|
|
20
|
+
Teacher.objects.create(user=teacher_userprofile, new_user=teacher_user)
|
|
21
|
+
Student.objects.create(user=student_userprofile, new_user=student_user)
|
|
22
|
+
|
|
23
|
+
migrator.apply_tested_migration(("common", "0049_anonymise_orphan_users"))
|
|
24
|
+
|
|
25
|
+
def assert_user_anonymised(pk: int, anonymised: bool):
|
|
26
|
+
assert User.objects.get(pk=pk).is_active != anonymised
|
|
27
|
+
|
|
28
|
+
assert_user_anonymised(orphan_user.pk, True)
|
|
29
|
+
assert_user_anonymised(teacher_user.pk, False)
|
|
30
|
+
assert_user_anonymised(student_user.pk, False)
|
|
@@ -4,20 +4,12 @@ import pytest
|
|
|
4
4
|
@pytest.mark.django_db
|
|
5
5
|
def test_blocked_time_added(migrator):
|
|
6
6
|
migrator.apply_initial_migration(("common", "0008_unlock_worksheet_3"))
|
|
7
|
-
new_state = migrator.apply_tested_migration(
|
|
8
|
-
("common", "0009_add_blocked_time_to_teacher_and_student")
|
|
9
|
-
)
|
|
7
|
+
new_state = migrator.apply_tested_migration(("common", "0009_add_blocked_time_to_teacher_and_student"))
|
|
10
8
|
|
|
11
9
|
teacher_model = new_state.apps.get_model("common", "Teacher")
|
|
12
10
|
|
|
13
|
-
assert (
|
|
14
|
-
teacher_model._meta.get_field("blocked_time").get_internal_type()
|
|
15
|
-
== "DateTimeField"
|
|
16
|
-
)
|
|
11
|
+
assert teacher_model._meta.get_field("blocked_time").get_internal_type() == "DateTimeField"
|
|
17
12
|
|
|
18
13
|
student_model = new_state.apps.get_model("common", "Student")
|
|
19
14
|
|
|
20
|
-
assert (
|
|
21
|
-
student_model._meta.get_field("blocked_time").get_internal_type()
|
|
22
|
-
== "DateTimeField"
|
|
23
|
-
)
|
|
15
|
+
assert student_model._meta.get_field("blocked_time").get_internal_type() == "DateTimeField"
|
|
@@ -4,9 +4,7 @@ from django.db.models.query import QuerySet
|
|
|
4
4
|
|
|
5
5
|
@pytest.mark.django_db
|
|
6
6
|
def test_teacher_title_removed(migrator):
|
|
7
|
-
old_state = migrator.apply_initial_migration(
|
|
8
|
-
("common", "0009_add_blocked_time_to_teacher_and_student")
|
|
9
|
-
)
|
|
7
|
+
old_state = migrator.apply_initial_migration(("common", "0009_add_blocked_time_to_teacher_and_student"))
|
|
10
8
|
Teacher = old_state.apps.get_model("common", "Teacher")
|
|
11
9
|
assert hasattr(Teacher, "title")
|
|
12
10
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from django_test_migrations.migrator import Migrator
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@pytest.mark.django_db
|
|
6
|
+
def test_migration_unique_school_names(migrator: Migrator):
|
|
7
|
+
state = migrator.apply_initial_migration(
|
|
8
|
+
("common", "0047_delete_school_postcode")
|
|
9
|
+
)
|
|
10
|
+
School = state.apps.get_model("common", "School")
|
|
11
|
+
|
|
12
|
+
school_name = "ExampleSchool"
|
|
13
|
+
School.objects.bulk_create(
|
|
14
|
+
[
|
|
15
|
+
School(name=school_name),
|
|
16
|
+
School(name=school_name),
|
|
17
|
+
School(name=f"{school_name} 1"),
|
|
18
|
+
]
|
|
19
|
+
)
|
|
20
|
+
school_ids = list(
|
|
21
|
+
School.objects.order_by("-id")[:3].values_list("id", flat=True)
|
|
22
|
+
)
|
|
23
|
+
school_ids.reverse()
|
|
24
|
+
|
|
25
|
+
migrator.apply_tested_migration(("common", "0048_unique_school_names"))
|
|
26
|
+
School = state.apps.get_model("common", "School")
|
|
27
|
+
|
|
28
|
+
def assert_school_name(index: int, name: str):
|
|
29
|
+
assert School.objects.get(id=school_ids[index]).name == name
|
|
30
|
+
|
|
31
|
+
assert_school_name(0, school_name)
|
|
32
|
+
assert_school_name(1, f"{school_name} 2")
|
|
33
|
+
assert_school_name(2, f"{school_name} 1")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from django_test_migrations.migrator import Migrator
|
|
5
|
+
|
|
6
|
+
from portal.views.api import __anonymise_user
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.mark.django_db
|
|
10
|
+
def test_migration_verify_returning_users(migrator: Migrator):
|
|
11
|
+
state = migrator.apply_initial_migration(
|
|
12
|
+
("common", "0050_anonymise_orphan_schools")
|
|
13
|
+
)
|
|
14
|
+
User = state.apps.get_model("auth", "User")
|
|
15
|
+
UserProfile = state.apps.get_model("common", "UserProfile")
|
|
16
|
+
|
|
17
|
+
returning_user = User.objects.create_user(
|
|
18
|
+
"ReturningUser",
|
|
19
|
+
password="password",
|
|
20
|
+
last_login=datetime.now(tz=timezone.utc),
|
|
21
|
+
)
|
|
22
|
+
returning_userprofile = UserProfile.objects.create(user=returning_user)
|
|
23
|
+
|
|
24
|
+
non_returning_user = User.objects.create_user(
|
|
25
|
+
"NonReturningUser", password="password"
|
|
26
|
+
)
|
|
27
|
+
non_returning_userprofile = UserProfile.objects.create(
|
|
28
|
+
user=non_returning_user
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
anonymised_returning_user = User.objects.create_user(
|
|
32
|
+
"AnonReturningUser",
|
|
33
|
+
password="password",
|
|
34
|
+
last_login=datetime.now(tz=timezone.utc),
|
|
35
|
+
)
|
|
36
|
+
anonymised_returning_userprofile = UserProfile.objects.create(
|
|
37
|
+
user=anonymised_returning_user
|
|
38
|
+
)
|
|
39
|
+
__anonymise_user(anonymised_returning_user)
|
|
40
|
+
|
|
41
|
+
anonymised_non_returning_user = User.objects.create_user(
|
|
42
|
+
"AnonNonReturningUser", password="password"
|
|
43
|
+
)
|
|
44
|
+
anonymised_non_returning_userprofile = UserProfile.objects.create(
|
|
45
|
+
user=anonymised_non_returning_user
|
|
46
|
+
)
|
|
47
|
+
__anonymise_user(anonymised_non_returning_user)
|
|
48
|
+
|
|
49
|
+
migrator.apply_tested_migration(("common", "0051_verify_returning_users"))
|
|
50
|
+
|
|
51
|
+
def assert_userprofile_is_verified(pk: int, verified: bool):
|
|
52
|
+
assert UserProfile.objects.get(pk=pk).is_verified == verified
|
|
53
|
+
|
|
54
|
+
assert_userprofile_is_verified(returning_userprofile.pk, True)
|
|
55
|
+
assert_userprofile_is_verified(non_returning_userprofile.pk, False)
|
|
56
|
+
assert_userprofile_is_verified(anonymised_returning_userprofile.pk, True)
|
|
57
|
+
assert_userprofile_is_verified(
|
|
58
|
+
anonymised_non_returning_userprofile.pk, False
|
|
59
|
+
)
|
common/tests/test_models.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
from common.models import Student, Teacher
|
|
1
|
+
from common.models import DailyActivity, Student, Teacher
|
|
2
2
|
from django.test import TestCase
|
|
3
|
+
from django.utils import timezone
|
|
3
4
|
|
|
5
|
+
from ..helpers.organisation import sanitise_uk_postcode
|
|
4
6
|
from .utils.classes import create_class_directly
|
|
5
|
-
from .utils.organisation import create_organisation_directly
|
|
7
|
+
from .utils.organisation import create_organisation_directly, join_teacher_to_organisation
|
|
6
8
|
from .utils.student import create_independent_student_directly
|
|
7
9
|
from .utils.teacher import signup_teacher_directly
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ class TestModels(TestCase):
|
|
|
15
17
|
Then the student's pending class request field is set to null.
|
|
16
18
|
"""
|
|
17
19
|
teacher_email, _ = signup_teacher_directly()
|
|
18
|
-
|
|
20
|
+
create_organisation_directly(teacher_email)
|
|
19
21
|
class_name = "Test Class"
|
|
20
22
|
klass, _, _ = create_class_directly(teacher_email, class_name)
|
|
21
23
|
|
|
@@ -27,55 +29,59 @@ class TestModels(TestCase):
|
|
|
27
29
|
indep_student.pending_class_request = klass
|
|
28
30
|
indep_student.save()
|
|
29
31
|
|
|
30
|
-
klass.
|
|
32
|
+
klass.anonymise()
|
|
31
33
|
|
|
32
34
|
indep_student = Student.objects.get(new_user__username=username)
|
|
33
35
|
|
|
34
36
|
assert indep_student.pending_class_request is None
|
|
35
37
|
|
|
36
|
-
def
|
|
37
|
-
"""
|
|
38
|
-
Given a school and a teacher in that school,
|
|
39
|
-
When the school is deleted,
|
|
40
|
-
Then the teacher's school field is set to null.
|
|
41
|
-
"""
|
|
38
|
+
def test_creation_time(self):
|
|
42
39
|
teacher_email, _ = signup_teacher_directly()
|
|
43
|
-
school_name, _ = create_organisation_directly(teacher_email)
|
|
44
|
-
|
|
45
|
-
teacher = Teacher.objects.get(new_user__email=teacher_email)
|
|
46
|
-
school = School.objects.get(name=school_name)
|
|
47
40
|
|
|
48
|
-
|
|
41
|
+
sometime = timezone.now() # mark time before the school creation
|
|
42
|
+
school = create_organisation_directly(teacher_email)
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
# check the creation time
|
|
45
|
+
assert school.creation_time > sometime
|
|
52
46
|
|
|
53
|
-
|
|
47
|
+
sometime = timezone.now() # mark time before the class creation
|
|
48
|
+
klass, name, access_code = create_class_directly(teacher_email)
|
|
49
|
+
# check the creation time
|
|
50
|
+
assert klass.creation_time > sometime
|
|
54
51
|
|
|
55
|
-
def
|
|
52
|
+
def test_school_admins(self):
|
|
56
53
|
"""
|
|
57
|
-
|
|
58
|
-
When the teacher requests to join the school, and that school is deleted,
|
|
59
|
-
Then the teacher's pending join request field is set to null.
|
|
54
|
+
Test that only the admins of a school are returned by the school.admins() function.
|
|
60
55
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
teacher2.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
56
|
+
email1, password1 = signup_teacher_directly()
|
|
57
|
+
email2, password2 = signup_teacher_directly()
|
|
58
|
+
email3, password3 = signup_teacher_directly()
|
|
59
|
+
school = create_organisation_directly(email1)
|
|
60
|
+
join_teacher_to_organisation(email2, school.name)
|
|
61
|
+
join_teacher_to_organisation(email3, school.name, is_admin=True)
|
|
62
|
+
|
|
63
|
+
teacher1 = Teacher.objects.get(new_user__username=email1)
|
|
64
|
+
teacher2 = Teacher.objects.get(new_user__username=email2)
|
|
65
|
+
teacher3 = Teacher.objects.get(new_user__username=email3)
|
|
66
|
+
|
|
67
|
+
assert len(school.admins()) == 2
|
|
68
|
+
assert teacher1 in school.admins()
|
|
69
|
+
assert teacher2 not in school.admins()
|
|
70
|
+
assert teacher3 in school.admins()
|
|
71
|
+
|
|
72
|
+
def test_sanitise_uk_postcode(self):
|
|
73
|
+
postcode_with_space = "AL10 9NE"
|
|
74
|
+
postcode_without_space = "AL109UL"
|
|
75
|
+
invalid_postcode = "123"
|
|
76
|
+
|
|
77
|
+
assert sanitise_uk_postcode(postcode_with_space) == "AL10 9NE" # Check it stays the same
|
|
78
|
+
assert sanitise_uk_postcode(postcode_without_space) == "AL10 9UL" # Check a space is added
|
|
79
|
+
assert sanitise_uk_postcode(invalid_postcode) == "123" # Check nothing happens
|
|
80
|
+
|
|
81
|
+
def test_daily_activity_serializer(self):
|
|
82
|
+
daily_activity = DailyActivity()
|
|
83
|
+
|
|
84
|
+
assert (
|
|
85
|
+
str(daily_activity)
|
|
86
|
+
== f"Activity on {daily_activity.date}: CSV clicks: 0, login cards clicks: 0, primary pack downloads: 0, python pack downloads: 0, level control submits: 0, teacher lockout resets: 0, indy lockout resets: 0, school student lockout resets: 0, unverified teachers anonymised: 0, unverified independents anonymised: 0"
|
|
87
|
+
)
|
common/tests/utils/classes.py
CHANGED
|
@@ -16,9 +16,7 @@ def generate_details():
|
|
|
16
16
|
generate_details.next_id = 1
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def create_class_directly(
|
|
20
|
-
teacher_email: str, class_name: str = None
|
|
21
|
-
) -> Tuple[Class, str, str]:
|
|
19
|
+
def create_class_directly(teacher_email: str, class_name: str = None) -> Tuple[Class, str, str]:
|
|
22
20
|
"""Generate a class with the details given.
|
|
23
21
|
|
|
24
22
|
Args:
|
common/tests/utils/email.py
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
|
-
import re
|
|
2
1
|
from builtins import str
|
|
3
2
|
|
|
4
3
|
|
|
5
|
-
def follow_verify_email_link_to_onboarding(page,
|
|
6
|
-
|
|
4
|
+
def follow_verify_email_link_to_onboarding(page, url):
|
|
5
|
+
page.browser.get(url)
|
|
7
6
|
|
|
8
7
|
return go_to_teacher_login_page(page.browser)
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return go_to_teacher_dashboard_page(page.browser)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def follow_verify_email_link_to_login(page, email, user_type):
|
|
18
|
-
_follow_verify_email_link(page, email)
|
|
10
|
+
def follow_verify_email_link_to_login(page, url, user_type):
|
|
11
|
+
page.browser.get(url)
|
|
19
12
|
|
|
20
13
|
if user_type == "teacher":
|
|
21
14
|
return go_to_teacher_login_page(page.browser)
|
|
@@ -23,8 +16,8 @@ def follow_verify_email_link_to_login(page, email, user_type):
|
|
|
23
16
|
return go_to_independent_student_login_page(page.browser)
|
|
24
17
|
|
|
25
18
|
|
|
26
|
-
def follow_duplicate_account_link_to_login(page,
|
|
27
|
-
|
|
19
|
+
def follow_duplicate_account_link_to_login(page, url, user_type):
|
|
20
|
+
page.browser.get(url)
|
|
28
21
|
|
|
29
22
|
if user_type == "teacher":
|
|
30
23
|
return go_to_teacher_login_page(page.browser)
|
|
@@ -32,29 +25,7 @@ def follow_duplicate_account_link_to_login(page, email, user_type):
|
|
|
32
25
|
return go_to_independent_student_login_page(page.browser)
|
|
33
26
|
|
|
34
27
|
|
|
35
|
-
def
|
|
36
|
-
message = str(email.message())
|
|
37
|
-
prefix = '<p>Please go to <a href="'
|
|
38
|
-
i = str.find(message, prefix) + len(prefix)
|
|
39
|
-
suffix = '" rel="nofollow">'
|
|
40
|
-
j = str.find(message, suffix, i)
|
|
41
|
-
page.browser.get(message[i:j])
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def _follow_duplicate_account_email_link(page, email):
|
|
45
|
-
message = str(email.message())
|
|
46
|
-
prefix = 'please login: <a href="'
|
|
47
|
-
i = str.find(message, prefix) + len(prefix)
|
|
48
|
-
suffix = '" rel="nofollow">'
|
|
49
|
-
j = str.find(message, suffix, i)
|
|
50
|
-
page.browser.get(message[i:j])
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def follow_reset_email_link(browser, email):
|
|
54
|
-
message = str(email.body)
|
|
55
|
-
|
|
56
|
-
link = re.search("http.+/", message).group(0)
|
|
57
|
-
|
|
28
|
+
def follow_reset_email_link(browser, link):
|
|
58
29
|
browser.get(link)
|
|
59
30
|
|
|
60
31
|
from portal.tests.pageObjects.portal.password_reset_form_page import (
|
|
@@ -64,27 +35,18 @@ def follow_reset_email_link(browser, email):
|
|
|
64
35
|
return PasswordResetPage(browser)
|
|
65
36
|
|
|
66
37
|
|
|
67
|
-
def follow_change_email_link_to_dashboard(page,
|
|
68
|
-
|
|
38
|
+
def follow_change_email_link_to_dashboard(page, url):
|
|
39
|
+
page.browser.get(url)
|
|
69
40
|
|
|
70
41
|
return go_to_teacher_login_page(page.browser)
|
|
71
42
|
|
|
72
43
|
|
|
73
|
-
def follow_change_email_link_to_independent_dashboard(page,
|
|
74
|
-
|
|
44
|
+
def follow_change_email_link_to_independent_dashboard(page, url):
|
|
45
|
+
page.browser.get(url)
|
|
75
46
|
|
|
76
47
|
return go_to_independent_student_login_page(page.browser)
|
|
77
48
|
|
|
78
49
|
|
|
79
|
-
def _follow_change_email_link(page, email):
|
|
80
|
-
message = str(email.message())
|
|
81
|
-
prefix = "please go to "
|
|
82
|
-
i = str.find(message, prefix) + len(prefix)
|
|
83
|
-
suffix = " to verify"
|
|
84
|
-
j = str.find(message, suffix, i)
|
|
85
|
-
page.browser.get(message[i:j])
|
|
86
|
-
|
|
87
|
-
|
|
88
50
|
def go_to_teacher_login_page(browser):
|
|
89
51
|
from portal.tests.pageObjects.portal.teacher_login_page import TeacherLoginPage
|
|
90
52
|
|
|
@@ -1,36 +1,33 @@
|
|
|
1
|
-
from common.models import
|
|
1
|
+
from common.models import School, Teacher
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def generate_details(**kwargs):
|
|
5
5
|
name = kwargs.get("name", "School %d" % generate_details.next_id)
|
|
6
|
-
postcode = kwargs.get("postcode", "Al10 9NE")
|
|
7
6
|
|
|
8
7
|
generate_details.next_id += 1
|
|
9
8
|
|
|
10
|
-
return name
|
|
9
|
+
return name
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
generate_details.next_id = 1
|
|
14
13
|
|
|
15
14
|
|
|
16
15
|
def create_organisation_directly(teacher_email, **kwargs):
|
|
17
|
-
name
|
|
16
|
+
name = generate_details(**kwargs)
|
|
18
17
|
|
|
19
|
-
school = School.objects.create(
|
|
20
|
-
name=name, postcode=postcode, country="GB", town="", latitude="", longitude=""
|
|
21
|
-
)
|
|
18
|
+
school = School.objects.create(name=name, country="GB")
|
|
22
19
|
|
|
23
20
|
teacher = Teacher.objects.get(new_user__email=teacher_email)
|
|
24
21
|
teacher.school = school
|
|
25
22
|
teacher.is_admin = True
|
|
26
23
|
teacher.save()
|
|
27
24
|
|
|
28
|
-
return
|
|
25
|
+
return school
|
|
29
26
|
|
|
30
27
|
|
|
31
|
-
def join_teacher_to_organisation(teacher_email, org_name,
|
|
28
|
+
def join_teacher_to_organisation(teacher_email, org_name, is_admin=False):
|
|
32
29
|
teacher = Teacher.objects.get(new_user__email=teacher_email)
|
|
33
|
-
school = School.objects.get(name=org_name
|
|
30
|
+
school = School.objects.get(name=org_name)
|
|
34
31
|
|
|
35
32
|
teacher.school = school
|
|
36
33
|
teacher.is_admin = is_admin
|
|
@@ -38,8 +35,7 @@ def join_teacher_to_organisation(teacher_email, org_name, postcode, is_admin=Fal
|
|
|
38
35
|
|
|
39
36
|
|
|
40
37
|
def create_organisation(page, password):
|
|
38
|
+
name = generate_details()
|
|
39
|
+
page = page.create_organisation(name, password)
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
page = page.create_organisation(name, password, postcode)
|
|
44
|
-
|
|
45
|
-
return page, name, postcode
|
|
41
|
+
return page, name
|