diff --git a/game/end_to_end_tests/test_play_through.py b/game/end_to_end_tests/test_play_through.py index 1f61c16ae..a751be6d8 100644 --- a/game/end_to_end_tests/test_play_through.py +++ b/game/end_to_end_tests/test_play_through.py @@ -343,8 +343,8 @@ def test_python_level_013(self): 13, check_algorithm_score=False, from_python_den=True ) - def test_episode_14(self): - self._complete_episode(14, 14, from_python_den=True) + def test_episode_13(self): + self._complete_episode(13, 14, from_python_den=True) def test_python_level_014(self): self._complete_level(14, from_python_den=True) @@ -396,8 +396,8 @@ def test_python_level_025(self): 25, check_algorithm_score=False, from_python_den=True ) - def test_episode_13(self): - self._complete_episode(13, 26, from_python_den=True) + def test_episode_14(self): + self._complete_episode(14, 26, from_python_den=True) def test_python_level_026(self): self._complete_level(26, from_python_den=True) diff --git a/game/forms.py b/game/forms.py index 85920d633..2cfa96212 100644 --- a/game/forms.py +++ b/game/forms.py @@ -9,18 +9,24 @@ class ScoreboardForm(forms.Form): def __init__(self, *args, **kwargs): classes = kwargs.pop("classes") + language = kwargs.pop("language") super(ScoreboardForm, self).__init__(*args, **kwargs) classes_choices = [(c.id, c.name) for c in classes] self.fields["classes"] = forms.MultipleChoiceField( choices=classes_choices, widget=forms.CheckboxSelectMultiple() ) + + episodes_range = ( + range(1, 10) if language == "blockly" else range(12, 16) + ) + # Each tuple in choices has two elements, id and name of each level # First element is the actual value set on the model # Second element is the string displayed on the dropdown menu episodes_choices = ( (episode.id, episode.name) - for episode in Episode.objects.filter(pk__in=range(1, 10)) + for episode in Episode.objects.filter(pk__in=episodes_range) ) self.fields["episodes"] = forms.MultipleChoiceField( choices=itertools.chain(episodes_choices), diff --git a/game/messages.py b/game/messages.py index 98286da40..2048e87df 100644 --- a/game/messages.py +++ b/game/messages.py @@ -3329,8 +3329,8 @@ def get_episode_title(episode_id): 10: "Introduction to Python", 11: "Python", 12: "Counted Loops Using While", - 13: "Indeterminate Loops", - 14: "Selection in a Loop", + 13: "Selection in a Loop", + 14: "Indeterminate Loops", 15: "For Loops", 16: "Output, Operators, and Data", 17: "Variables, Input, and Casting", diff --git a/game/migrations/0102_reoder_episodes_13_14.py b/game/migrations/0102_reoder_episodes_13_14.py new file mode 100644 index 000000000..fccf20247 --- /dev/null +++ b/game/migrations/0102_reoder_episodes_13_14.py @@ -0,0 +1,136 @@ +from django.apps.registry import Apps +from django.db import migrations + + +def swap_episodes_13_14(apps: Apps, *args): + Episode = apps.get_model("game", "Episode") + Level = apps.get_model("game", "Level") + + episode12 = Episode.objects.get(pk=12) + episode13 = Episode.objects.get(pk=13) + episode14 = Episode.objects.get(pk=14) + episode20 = Episode.objects.get(pk=20) + + episode13_levels = Level.objects.filter( + default=True, name__in=range(1026, 1041) + ) + episode14_levels = Level.objects.filter( + default=True, name__in=range(1014, 1026) + ) + + episode13_levels.update(episode=episode14) + episode14_levels.update(episode=episode13) + + old_episode13_name = episode13.name + old_episode13_lesson_plan_link = episode13.lesson_plan_link + old_episode13_slides_link = episode13.slides_link + old_episode13_worksheet_link = episode13.worksheet_link + old_episode13_video_link = episode13.video_link + old_episode14_name = episode14.name + old_episode14_lesson_plan_link = episode14.lesson_plan_link + old_episode14_slides_link = episode14.slides_link + old_episode14_worksheet_link = episode14.worksheet_link + old_episode14_video_link = episode14.video_link + + episode13.name = old_episode14_name + episode13.lesson_plan_link = old_episode14_lesson_plan_link + episode13.slides_link = old_episode14_slides_link + episode13.worksheet_link = old_episode14_worksheet_link + episode13.video_link = old_episode14_video_link + episode14.name = old_episode13_name + episode14.lesson_plan_link = old_episode13_lesson_plan_link + episode14.slides_link = old_episode13_slides_link + episode14.worksheet_link = old_episode13_worksheet_link + episode14.video_link = old_episode13_video_link + + episode12.next_episode = episode13 + episode13.next_episode = episode14 + episode14.next_episode = episode20 + + episode12.save() + episode13.save() + episode14.save() + + episode12_last_level = episode12.level_set.first() + episode13_last_level = episode13.level_set.last() + episode14_last_level = episode14.level_set.last() + + episode12_last_level.next_level = episode13.level_set.all()[0] + episode13_last_level.next_level = episode14.level_set.all()[0] + episode14_last_level.next_level = None + + episode12_last_level.save() + episode13_last_level.save() + episode14_last_level.save() + + +def unswap_episodes_13_14(apps: Apps, *args): + Episode = apps.get_model("game", "Episode") + Level = apps.get_model("game", "Level") + + episode12 = Episode.objects.get(pk=12) + episode13 = Episode.objects.get(pk=13) + episode14 = Episode.objects.get(pk=14) + episode20 = Episode.objects.get(pk=20) + + episode13_levels = Level.objects.filter( + default=True, name__in=range(1014, 1026) + ) + episode14_levels = Level.objects.filter( + default=True, name__in=range(1026, 1041) + ) + + episode13_levels.update(episode=episode14) + episode14_levels.update(episode=episode13) + + old_episode13_name = episode13.name + old_episode13_lesson_plan_link = episode13.lesson_plan_link + old_episode13_slides_link = episode13.slides_link + old_episode13_worksheet_link = episode13.worksheet_link + old_episode13_video_link = episode13.video_link + old_episode14_name = episode14.name + old_episode14_lesson_plan_link = episode14.lesson_plan_link + old_episode14_slides_link = episode14.slides_link + old_episode14_worksheet_link = episode14.worksheet_link + old_episode14_video_link = episode14.video_link + + episode13.name = old_episode14_name + episode13.lesson_plan_link = old_episode14_lesson_plan_link + episode13.slides_link = old_episode14_slides_link + episode13.worksheet_link = old_episode14_worksheet_link + episode13.video_link = old_episode14_video_link + episode14.name = old_episode13_name + episode14.lesson_plan_link = old_episode13_lesson_plan_link + episode14.slides_link = old_episode13_slides_link + episode14.worksheet_link = old_episode13_worksheet_link + episode14.video_link = old_episode13_video_link + + episode12.next_episode = episode14 + episode14.next_episode = episode13 + episode13.next_episode = episode20 + + episode12.save() + episode13.save() + episode14.save() + + episode12_last_level = episode12.level_set.first() + episode13_last_level = episode13.level_set.last() + episode14_last_level = episode14.level_set.last() + + episode12_last_level.next_level = episode14.level_set.all()[0] + episode14_last_level.next_level = episode13.level_set.all()[0] + episode13_last_level.next_level = None + + episode12_last_level.save() + episode13_last_level.save() + episode14_last_level.save() + + +class Migration(migrations.Migration): + dependencies = [("game", "0101_rename_episodes")] + + operations = [ + migrations.RunPython( + code=swap_episodes_13_14, reverse_code=unswap_episodes_13_14 + ) + ] diff --git a/game/python_den_urls.py b/game/python_den_urls.py index e4cb7c736..65e5d0ac0 100644 --- a/game/python_den_urls.py +++ b/game/python_den_urls.py @@ -2,6 +2,7 @@ from game.views.level import play_default_python_level, start_python_episode from game.views.level_selection import python_levels +from game.views.scoreboard import python_scoreboard urlpatterns = [ url(r"^$", python_levels, name="python_levels"), @@ -15,4 +16,5 @@ start_python_episode, name="start_python_episode", ), + url(r"^scoreboard/$", python_scoreboard, name="python_scoreboard"), ] diff --git a/game/static/django_reverse_js/js/reverse.js b/game/static/django_reverse_js/js/reverse.js new file mode 100644 index 000000000..4b9eb9c39 --- /dev/null +++ b/game/static/django_reverse_js/js/reverse.js @@ -0,0 +1,171 @@ +this.Urls = (function () { + var data = {"urls": [["about", [["about", []]]], ["admin:app_list", [["administration/%(app_label)s/", ["app_label"]]]], ["admin:auth_group_add", [["administration/auth/group/add/", []]]], ["admin:auth_group_change", [["administration/auth/group/%(object_id)s/change/", ["object_id"]]]], ["admin:auth_group_changelist", [["administration/auth/group/", []]]], ["admin:auth_group_delete", [["administration/auth/group/%(object_id)s/delete/", ["object_id"]]]], ["admin:auth_group_history", [["administration/auth/group/%(object_id)s/history/", ["object_id"]]]], ["admin:auth_user_add", [["administration/auth/user/add/", []]]], ["admin:auth_user_change", [["administration/auth/user/%(object_id)s/change/", ["object_id"]]]], ["admin:auth_user_changelist", [["administration/auth/user/", []]]], ["admin:auth_user_delete", [["administration/auth/user/%(object_id)s/delete/", ["object_id"]]]], ["admin:auth_user_history", [["administration/auth/user/%(object_id)s/history/", ["object_id"]]]], ["admin:auth_user_password_change", [["administration/auth/user/%(id)s/password/", ["id"]]]], ["admin:autocomplete", [["administration/autocomplete/", []]]], ["admin:common_class_add", [["administration/common/class/add/", []]]], ["admin:common_class_change", [["administration/common/class/%(object_id)s/change/", ["object_id"]]]], ["admin:common_class_changelist", [["administration/common/class/", []]]], ["admin:common_class_delete", [["administration/common/class/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_class_history", [["administration/common/class/%(object_id)s/history/", ["object_id"]]]], ["admin:common_dailyactivity_add", [["administration/common/dailyactivity/add/", []]]], ["admin:common_dailyactivity_change", [["administration/common/dailyactivity/%(object_id)s/change/", ["object_id"]]]], ["admin:common_dailyactivity_changelist", [["administration/common/dailyactivity/", []]]], ["admin:common_dailyactivity_delete", [["administration/common/dailyactivity/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_dailyactivity_history", [["administration/common/dailyactivity/%(object_id)s/history/", ["object_id"]]]], ["admin:common_dynamicelement_add", [["administration/common/dynamicelement/add/", []]]], ["admin:common_dynamicelement_change", [["administration/common/dynamicelement/%(object_id)s/change/", ["object_id"]]]], ["admin:common_dynamicelement_changelist", [["administration/common/dynamicelement/", []]]], ["admin:common_dynamicelement_delete", [["administration/common/dynamicelement/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_dynamicelement_history", [["administration/common/dynamicelement/%(object_id)s/history/", ["object_id"]]]], ["admin:common_school_add", [["administration/common/school/add/", []]]], ["admin:common_school_change", [["administration/common/school/%(object_id)s/change/", ["object_id"]]]], ["admin:common_school_changelist", [["administration/common/school/", []]]], ["admin:common_school_delete", [["administration/common/school/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_school_history", [["administration/common/school/%(object_id)s/history/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_add", [["administration/common/schoolteacherinvitation/add/", []]]], ["admin:common_schoolteacherinvitation_change", [["administration/common/schoolteacherinvitation/%(object_id)s/change/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_changelist", [["administration/common/schoolteacherinvitation/", []]]], ["admin:common_schoolteacherinvitation_delete", [["administration/common/schoolteacherinvitation/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_schoolteacherinvitation_history", [["administration/common/schoolteacherinvitation/%(object_id)s/history/", ["object_id"]]]], ["admin:common_student_add", [["administration/common/student/add/", []]]], ["admin:common_student_change", [["administration/common/student/%(object_id)s/change/", ["object_id"]]]], ["admin:common_student_changelist", [["administration/common/student/", []]]], ["admin:common_student_delete", [["administration/common/student/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_student_history", [["administration/common/student/%(object_id)s/history/", ["object_id"]]]], ["admin:common_teacher_add", [["administration/common/teacher/add/", []]]], ["admin:common_teacher_change", [["administration/common/teacher/%(object_id)s/change/", ["object_id"]]]], ["admin:common_teacher_changelist", [["administration/common/teacher/", []]]], ["admin:common_teacher_delete", [["administration/common/teacher/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_teacher_history", [["administration/common/teacher/%(object_id)s/history/", ["object_id"]]]], ["admin:common_totalactivity_add", [["administration/common/totalactivity/add/", []]]], ["admin:common_totalactivity_change", [["administration/common/totalactivity/%(object_id)s/change/", ["object_id"]]]], ["admin:common_totalactivity_changelist", [["administration/common/totalactivity/", []]]], ["admin:common_totalactivity_delete", [["administration/common/totalactivity/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_totalactivity_history", [["administration/common/totalactivity/%(object_id)s/history/", ["object_id"]]]], ["admin:common_userprofile_add", [["administration/common/userprofile/add/", []]]], ["admin:common_userprofile_change", [["administration/common/userprofile/%(object_id)s/change/", ["object_id"]]]], ["admin:common_userprofile_changelist", [["administration/common/userprofile/", []]]], ["admin:common_userprofile_delete", [["administration/common/userprofile/%(object_id)s/delete/", ["object_id"]]]], ["admin:common_userprofile_history", [["administration/common/userprofile/%(object_id)s/history/", ["object_id"]]]], ["admin:game_attempt_add", [["administration/game/attempt/add/", []]]], ["admin:game_attempt_change", [["administration/game/attempt/%(object_id)s/change/", ["object_id"]]]], ["admin:game_attempt_changelist", [["administration/game/attempt/", []]]], ["admin:game_attempt_delete", [["administration/game/attempt/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_attempt_history", [["administration/game/attempt/%(object_id)s/history/", ["object_id"]]]], ["admin:game_block_add", [["administration/game/block/add/", []]]], ["admin:game_block_change", [["administration/game/block/%(object_id)s/change/", ["object_id"]]]], ["admin:game_block_changelist", [["administration/game/block/", []]]], ["admin:game_block_delete", [["administration/game/block/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_block_history", [["administration/game/block/%(object_id)s/history/", ["object_id"]]]], ["admin:game_episode_add", [["administration/game/episode/add/", []]]], ["admin:game_episode_change", [["administration/game/episode/%(object_id)s/change/", ["object_id"]]]], ["admin:game_episode_changelist", [["administration/game/episode/", []]]], ["admin:game_episode_delete", [["administration/game/episode/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_episode_history", [["administration/game/episode/%(object_id)s/history/", ["object_id"]]]], ["admin:game_level_add", [["administration/game/level/add/", []]]], ["admin:game_level_change", [["administration/game/level/%(object_id)s/change/", ["object_id"]]]], ["admin:game_level_changelist", [["administration/game/level/", []]]], ["admin:game_level_delete", [["administration/game/level/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_level_history", [["administration/game/level/%(object_id)s/history/", ["object_id"]]]], ["admin:game_leveldecor_add", [["administration/game/leveldecor/add/", []]]], ["admin:game_leveldecor_change", [["administration/game/leveldecor/%(object_id)s/change/", ["object_id"]]]], ["admin:game_leveldecor_changelist", [["administration/game/leveldecor/", []]]], ["admin:game_leveldecor_delete", [["administration/game/leveldecor/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_leveldecor_history", [["administration/game/leveldecor/%(object_id)s/history/", ["object_id"]]]], ["admin:game_workspace_add", [["administration/game/workspace/add/", []]]], ["admin:game_workspace_change", [["administration/game/workspace/%(object_id)s/change/", ["object_id"]]]], ["admin:game_workspace_changelist", [["administration/game/workspace/", []]]], ["admin:game_workspace_delete", [["administration/game/workspace/%(object_id)s/delete/", ["object_id"]]]], ["admin:game_workspace_history", [["administration/game/workspace/%(object_id)s/history/", ["object_id"]]]], ["admin:index", [["administration/", []]]], ["admin:jsi18n", [["administration/jsi18n/", []]]], ["admin:login", [["administration/login/", []]]], ["admin:logout", [["administration/logout/", []]]], ["admin:otp_static_staticdevice_add", [["administration/otp_static/staticdevice/add/", []]]], ["admin:otp_static_staticdevice_change", [["administration/otp_static/staticdevice/%(object_id)s/change/", ["object_id"]]]], ["admin:otp_static_staticdevice_changelist", [["administration/otp_static/staticdevice/", []]]], ["admin:otp_static_staticdevice_delete", [["administration/otp_static/staticdevice/%(object_id)s/delete/", ["object_id"]]]], ["admin:otp_static_staticdevice_history", [["administration/otp_static/staticdevice/%(object_id)s/history/", ["object_id"]]]], ["admin:otp_totp_totpdevice_add", [["administration/otp_totp/totpdevice/add/", []]]], ["admin:otp_totp_totpdevice_change", [["administration/otp_totp/totpdevice/%(object_id)s/change/", ["object_id"]]]], ["admin:otp_totp_totpdevice_changelist", [["administration/otp_totp/totpdevice/", []]]], ["admin:otp_totp_totpdevice_config", [["administration/otp_totp/totpdevice/%(pk)s/config/", ["pk"]]]], ["admin:otp_totp_totpdevice_delete", [["administration/otp_totp/totpdevice/%(object_id)s/delete/", ["object_id"]]]], ["admin:otp_totp_totpdevice_history", [["administration/otp_totp/totpdevice/%(object_id)s/history/", ["object_id"]]]], ["admin:otp_totp_totpdevice_qrcode", [["administration/otp_totp/totpdevice/%(pk)s/qrcode/", ["pk"]]]], ["admin:password_change", [["administration/password_change/", []]]], ["admin:password_change_done", [["administration/password_change/done/", []]]], ["admin:view_on_site", [["administration/r/%(content_type_id)s/%(object_id)s/", ["content_type_id", "object_id"]]]], ["administration_password_change", [["administration/password_change/", []]]], ["administration_password_change_done", [["administration/password_change_done/", []]]], ["anonymise-unverified-accounts", [["cron/user/unverified/delete/", []]]], ["anonymise_orphan_schools", [["schools/anonymise/%(start_id)s/", ["start_id"]]]], ["block-detail", [["rapidrouter/api/blocks/%(pk)s/", ["pk"]]]], ["block-list", [["rapidrouter/api/blocks/", []]]], ["celebrate", [["celebrate/", []]]], ["character-detail", [["rapidrouter/api/characters/%(pk)s/", ["pk"]]]], ["character-list", [["rapidrouter/api/characters/", []]]], ["codingClub", [["codingClub/", []]]], ["consent_form", [["consent_form/", []]]], ["contribute", [["contribute", []]]], ["dashboard", [["teach/dashboard/", []]]], ["decor-detail", [["rapidrouter/api/decors/%(pk)s/", ["pk"]]]], ["decor-list", [["rapidrouter/api/decors/", []]]], ["delete_account", [["delete/account/", []]]], ["delete_level", [["rapidrouter/level_moderation/delete/%(levelID)s/", ["levelID"]]]], ["delete_level_for_editor", [["rapidrouter/level_editor/delete/%(levelId)s/", ["levelId"]]]], ["delete_teacher_invite", [["teach/dashboard/delete_teacher_invite/%(token)s", ["token"]]]], ["delete_workspace", [["rapidrouter/workspace/delete/%(workspaceID)s/", ["workspaceID"]]]], ["download_student_pack", [["codingClub/%(student_pack_type)s/", ["student_pack_type"]]]], ["email_verification", [["verify_email/", []]]], ["episode-detail", [["rapidrouter/api/episodes/%(pk)s/", ["pk"]]]], ["episode-list", [["rapidrouter/api/episodes/", []]]], ["final-inactivity-reminder", [["cron/user/inactive/send-final-reminder/", []]]], ["first-inactivity-reminder", [["cron/user/inactive/send-first-reminder/", []]]], ["first-verify-email-reminder", [["cron/user/unverified/send-first-reminder/", []]]], ["generate_random_map_for_editor", [["rapidrouter/level_editor/random/", []]]], ["get_sharing_information_for_editor", [["rapidrouter/level_editor/get_sharing_information/%(levelID)s/", ["levelID"]]]], ["getinvolved", [["getinvolved", []]]], ["home", [["", []]]], ["home-learning", [["home-learning", []]]], ["inactive_users", [["users/inactive/", []]]], ["independent_edit_account", [["play/account/independent/", []]]], ["independent_student_details", [["play/details/independent", []]]], ["independent_student_login", [["login/independent/", []]]], ["invite_toggle_admin", [["teach/dashboard/toggle_admin_invite/%(invite_id)s/", ["invite_id"]]]], ["invited_teacher", [["invited_teacher/%(token)s/", ["token"]]]], ["js-reverse", [["rapidrouter/reverse.js", []]]], ["last-connected-since", [["api/lastconnectedsince/%(year)s/%(month)s/%(day)s/", ["year", "month", "day"]]]], ["level-detail", [["rapidrouter/api/levels/%(pk)s/", ["pk"]]]], ["level-for-episode", [["rapidrouter/api/episodes/%(pk)s/levels/", ["pk"]]]], ["level-list", [["rapidrouter/api/levels/", []]]], ["level_editor", [["rapidrouter/level_editor/", []]]], ["level_editor_chosen_level", [["rapidrouter/level_editor/%(levelId)s/", ["levelId"]]]], ["level_moderation", [["rapidrouter/level_moderation/", []]]], ["levelblock-detail", [["rapidrouter/api/levelblocks/%(pk)s/", ["pk"]]]], ["levelblock-for-level", [["rapidrouter/api/levels/%(pk)s/blocks/", ["pk"]]]], ["leveldecor-detail", [["rapidrouter/api/leveldecors/%(pk)s/", ["pk"]]]], ["leveldecor-for-level", [["rapidrouter/api/levels/%(pk)s/decors/", ["pk"]]]], ["levels", [["rapidrouter/", []]]], ["load_level_for_editor", [["rapidrouter/level_editor/get/%(levelID)s/", ["levelID"]]]], ["load_list_of_workspaces", [["rapidrouter/workspace/load_list/", []]]], ["load_workspace", [["rapidrouter/workspace/load/%(workspaceID)s/", ["workspaceID"]]]], ["load_workspace_solution", [["rapidrouter/workspace/solution/%(level_name)s/", ["level_name"]]]], ["locked_out", [["locked_out/", []]]], ["logout_view", [["logout/", []]]], ["map-for-level", [["rapidrouter/api/levels/%(pk)s/map/", ["pk"]]]], ["map-list", [["rapidrouter/api/maps/", []]]], ["mode-for-level", [["rapidrouter/api/levels/%(pk)s/mode/", ["pk"]]]], ["number_users_per_country", [["api/userspercountry/%(country)s/", ["country"]]]], ["old_login_form", [["login_form", []]]], ["onboarding-class", [["teach/onboarding-class/%(access_code)s", ["access_code"]]]], ["onboarding-classes", [["teach/onboarding-classes", []]]], ["onboarding-organisation", [["teach/onboarding-organisation/", []]]], ["organisation_kick", [["teach/dashboard/kick/%(pk)s/", ["pk"]]]], ["organisation_leave", [["teach/dashboard/school/leave/", []]]], ["organisation_toggle_admin", [["teach/dashboard/toggle_admin/%(pk)s/", ["pk"]]]], ["owned_levels", [["rapidrouter/level_editor/levels/owned/", []]]], ["password_reset_check_and_confirm", [["user/password/reset/%(uidb64)s-%(token)s/", ["uidb64", "token"]]]], ["password_reset_complete", [["teacher/password/reset/complete/", []]]], ["play", [["play/", []]]], ["play_anonymous_level", [["rapidrouter/level_editor/play_anonymous/%(levelId)s/", ["levelId"]]]], ["play_custom_level", [["rapidrouter/custom/%(levelId)s/", ["levelId"]]]], ["play_custom_level_from_editor", [["rapidrouter/level_editor/play_custom/%(levelId)s/", ["levelId"]]]], ["play_default_level", [["rapidrouter/%(level_name)s/", ["level_name"]], ["%(level_name)s/", ["level_name"]]]], ["play_python_default_level", [["pythonden/%(level_name)s/", ["level_name"]]]], ["privacy_notice", [["privacy-notice/", []]]], ["privacy_policy", [["privacy-policy/", []]]], ["process_newsletter_form", [["news_signup/", []]]], ["python_levels", [["pythonden/", []]]], ["python_scoreboard", [["pythonden/scoreboard/", []]]], ["random_level_for_episode", [["rapidrouter/levels/random/%(_0)s/", ["_0"]]]], ["rapid-router/javascript-catalog", [["rapidrouter/js-i18n/", []]]], ["register", [["register_form", []]]], ["registered-users", [["api/registered/%(year)s/%(month)s/%(day)s/", ["year", "month", "day"]]]], ["remove_fake_accounts", [["removeFakeAccounts/", []]]], ["resend_invite_teacher", [["teach/dashboard/resend_invite/%(token)s/", ["token"]]]], ["reset_password_email_sent", [["user/password/reset/done/", []]]], ["reset_screentime_warning", [["user/reset_screentime_warning/", []]]], ["reset_session_time", [["user/reset_session_time/", []]]], ["rest_framework:login", [["rapidrouter/api-auth/login/", []]]], ["rest_framework:logout", [["rapidrouter/api-auth/logout/", []]]], ["save_level_for_editor", [["rapidrouter/level_editor/save/%(levelId)s/", ["levelId"]], ["rapidrouter/level_editor/save/", []]]], ["save_workspace", [["rapidrouter/workspace/save/%(workspaceID)s/", ["workspaceID"]], ["rapidrouter/workspace/save/", []]]], ["school_student_edit_account", [["play/account/school_student/", []]]], ["scoreboard", [["rapidrouter/scoreboard/", []]]], ["second-inactivity-reminder", [["cron/user/inactive/send-second-reminder/", []]]], ["second-verify-email-reminder", [["cron/user/unverified/send-second-reminder/", []]]], ["set_language", [["i18n/setlang/", []]]], ["share_level_for_editor", [["rapidrouter/level_editor/share/%(levelID)s/", ["levelID"]]]], ["shared_levels", [["rapidrouter/level_editor/levels/shared/", []]]], ["start_episode", [["rapidrouter/episode/%(episodeId)s/", ["episodeId"]]]], ["start_python_episode", [["pythonden/episode/%(episodeId)s/", ["episodeId"]]]], ["student_details", [["play/details/", []]]], ["student_direct_login", [["u/%(user_id)s/%(login_id)s/", ["user_id", "login_id"]]]], ["student_edit_account", [["play/account/", []]]], ["student_join_organisation", [["play/join/", []]]], ["student_login", [["login/student/%(access_code)s/", ["access_code"]], ["login/student/%(access_code)s/%(login_type)s/", ["access_code", "login_type"]]]], ["student_login_access_code", [["login/student/", []]]], ["student_password_reset", [["user/password/reset/student/", []]]], ["submit_attempt", [["rapidrouter/submit/", []]]], ["teach", [["teach/", []]]], ["teacher_accept_student_request", [["teach/dashboard/student/accept/%(pk)s/", ["pk"]]]], ["teacher_class_password_reset", [["teach/class/%(access_code)s/password_reset/", ["access_code"]]]], ["teacher_delete_class", [["teach/class/delete/%(access_code)s", ["access_code"]]]], ["teacher_delete_students", [["teach/class/%(access_code)s/students/delete/", ["access_code"]]]], ["teacher_disable_2FA", [["teach/dashboard/disable_2FA/%(pk)s/", ["pk"]]]], ["teacher_dismiss_students", [["teach/class/%(access_code)s/students/dismiss/", ["access_code"]]]], ["teacher_download_csv", [["teach/onboarding-class/%(access_code)s/download_csv/", ["access_code"]]]], ["teacher_edit_class", [["teach/class/edit/%(access_code)s", ["access_code"]]]], ["teacher_edit_student", [["teach/class/student/edit/%(pk)s/", ["pk"]]]], ["teacher_login", [["login/teacher/", []]]], ["teacher_move_students", [["teach/class/%(access_code)s/students/move/", ["access_code"]]]], ["teacher_move_students_to_class", [["teach/class/%(access_code)s/students/move/disambiguate/", ["access_code"]]]], ["teacher_password_reset", [["user/password/reset/teacher/", []]]], ["teacher_print_reminder_cards", [["teach/onboarding-class/%(access_code)s/print_reminder_cards/", ["access_code"]]]], ["teacher_reject_student_request", [["teach/dashboard/student/reject/%(pk)s/", ["pk"]]]], ["terms", [["terms", []]]], ["theme-detail", [["rapidrouter/api/themes/%(pk)s/", ["pk"]]]], ["theme-list", [["rapidrouter/api/themes/", []]]], ["two_factor:backup_tokens", [["account/two_factor/backup/tokens/", []]]], ["two_factor:disable", [["account/two_factor/disable/", []]]], ["two_factor:profile", [["account/two_factor/", []]]], ["two_factor:qr", [["account/two_factor/qrcode/", []]]], ["two_factor:setup", [["account/two_factor/setup/", []]]], ["two_factor:setup_complete", [["account/two_factor/setup/complete/", []]]], ["verify_email", [["verify_email/%(token)s/", ["token"]]]], ["view_class", [["teach/class/%(access_code)s", ["access_code"]]]]], "prefix": "/"}; + var resolverFactory; +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "UrlResolver": () => (/* binding */ UrlResolver), +/* harmony export */ "factory": () => (/* binding */ factory) +/* harmony export */ }); +function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } + +function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } + +function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } + +function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } + +function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } + +function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } + +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var UrlResolver = /*#__PURE__*/function () { + function UrlResolver(prefix, patterns) { + _classCallCheck(this, UrlResolver); + + this.prefix = prefix; + this.patterns = patterns; + this.reverse = this.reverse.bind(this); + } + + _createClass(UrlResolver, [{ + key: "reverse", + value: function reverse() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var validateArgs, buildKwargs; + + if (args.length === 1 && _typeof(args[0]) === 'object') { + // kwargs mode + var providedKeys = Object.keys(args[0]); + + validateArgs = function validateArgs(_ref) { + var _ref2 = _slicedToArray(_ref, 2), + _urlTemplate = _ref2[0], + urlParams = _ref2[1]; + + // check every needed param was provided (without extra elements) + return urlParams.length === providedKeys.length && urlParams.every(function (p) { + return providedKeys.includes(p); + }); + }; // return first element + + + buildKwargs = function buildKwargs() { + return args[0]; + }; + } else { + // args mode + // check every required param + validateArgs = function validateArgs(_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + _urlTemplate = _ref4[0], + urlParams = _ref4[1]; + + return urlParams.length === args.length; + }; // build keyword-arguments from arguments + + + buildKwargs = function buildKwargs(keys) { + return Object.fromEntries(keys.map(function (key, i) { + return [key, args[i]]; + })); + }; + } // search between patterns if one matches provided args + + + var urlPattern = this.patterns.find(validateArgs); + + if (!urlPattern) { + return null; + } + + var _urlPattern = _slicedToArray(urlPattern, 2), + urlTemplate = _urlPattern[0], + urlKwargNames = _urlPattern[1]; + + var urlKwargs = buildKwargs(urlKwargNames); + var url = Object.entries(urlKwargs).reduce(function (partialUrl, _ref5) { + var _ref6 = _slicedToArray(_ref5, 2), + pName = _ref6[0], + pValue = _ref6[1]; + + if (pValue == null) pValue = ''; // replace variable with param + + return partialUrl.replace("%(".concat(pName, ")s"), pValue); + }, urlTemplate); + return "".concat(this.prefix).concat(url); + } + }]); + + return UrlResolver; +}(); +function factory(config) { + var urlPatterns = config.urls, + urlPrefix = config.prefix; + return urlPatterns.reduce(function (resolver, _ref7) { + var _ref8 = _slicedToArray(_ref7, 2), + name = _ref8[0], + pattern = _ref8[1]; + + var urlResolver = new UrlResolver(urlPrefix, pattern); + resolver[name] = urlResolver.reverse; // turn snake-case into camel-case + + resolver[name.replace(/[-_]+(.)/g, function (_m, p1) { + return p1.toUpperCase(); + })] = urlResolver.reverse; // turn snake-case into dash-case + + resolver[name.replace(/-/g, '_')] = urlResolver.reverse; + return resolver; + }, {}); +} +resolverFactory = __webpack_exports__; +/******/ })() +; + return data ? resolverFactory.factory(data) : resolverFactory.factory; +})(); diff --git a/game/static/game/css/backgrounds.css b/game/static/game/css/backgrounds.css index dbcd27848..b311412e6 100644 --- a/game/static/game/css/backgrounds.css +++ b/game/static/game/css/backgrounds.css @@ -27,3 +27,7 @@ .bg--late-python { background-color: #152584; } + +.banner--python-den--image { + width: 100%; +} diff --git a/game/static/game/css/level_selection.css b/game/static/game/css/level_selection.css index e3228c337..05207ae86 100644 --- a/game/static/game/css/level_selection.css +++ b/game/static/game/css/level_selection.css @@ -73,13 +73,13 @@ margin-left: 15px; } -#episodes .panel-header:not(.bg--loops-coming-soon) .collapsed.episode_range_text::after { +#episodes .panel-header .collapsed.episode_range_text::after { content: "\e250"; font-family: "Glyphicons Halflings"; margin-left: 10px; } -#episodes .panel-header:not(.bg--loops-coming-soon) .episode_range_text::after { +#episodes .panel-header .episode_range_text::after { content: "\e252"; font-family: "Glyphicons Halflings"; margin-left: 10px; @@ -95,10 +95,6 @@ text-decoration: none; } -.banner--python-den--image { - width: 100%; -} - .button--level { background-color: #f6be00; padding: 5px 12px; diff --git a/game/static/game/js/js-reverse.js b/game/static/game/js/js-reverse.js deleted file mode 100644 index 3ab752b75..000000000 --- a/game/static/game/js/js-reverse.js +++ /dev/null @@ -1,14 +0,0 @@ -this.Urls=(function(){"use strict";var data={"urls":[["about",[["about",[]]]],["admin:aimmo_avatar_add",[["administration/aimmo/avatar/add/",[]]]],["admin:aimmo_avatar_change",[["administration/aimmo/avatar/%(object_id)s/change/",["object_id"]]]],["admin:aimmo_avatar_changelist",[["administration/aimmo/avatar/",[]]]],["admin:aimmo_avatar_delete",[["administration/aimmo/avatar/%(object_id)s/delete/",["object_id"]]]],["admin:aimmo_avatar_history",[["administration/aimmo/avatar/%(object_id)s/history/",["object_id"]]]],["admin:aimmo_game_add",[["administration/aimmo/game/add/",[]]]],["admin:aimmo_game_change",[["administration/aimmo/game/%(object_id)s/change/",["object_id"]]]],["admin:aimmo_game_changelist",[["administration/aimmo/game/",[]]]],["admin:aimmo_game_delete",[["administration/aimmo/game/%(object_id)s/delete/",["object_id"]]]],["admin:aimmo_game_history",[["administration/aimmo/game/%(object_id)s/history/",["object_id"]]]],["admin:app_list",[["administration/%(app_label)s/",["app_label"]]]],["admin:auth_group_add",[["administration/auth/group/add/",[]]]],["admin:auth_group_change",[["administration/auth/group/%(object_id)s/change/",["object_id"]]]],["admin:auth_group_changelist",[["administration/auth/group/",[]]]],["admin:auth_group_delete",[["administration/auth/group/%(object_id)s/delete/",["object_id"]]]],["admin:auth_group_history",[["administration/auth/group/%(object_id)s/history/",["object_id"]]]],["admin:auth_user_add",[["administration/auth/user/add/",[]]]],["admin:auth_user_change",[["administration/auth/user/%(object_id)s/change/",["object_id"]]]],["admin:auth_user_changelist",[["administration/auth/user/",[]]]],["admin:auth_user_delete",[["administration/auth/user/%(object_id)s/delete/",["object_id"]]]],["admin:auth_user_history",[["administration/auth/user/%(object_id)s/history/",["object_id"]]]],["admin:auth_user_password_change",[["administration/auth/user/%(id)s/password/",["id"]]]],["admin:autocomplete",[["administration/autocomplete/",[]]]],["admin:common_class_add",[["administration/common/class/add/",[]]]],["admin:common_class_change",[["administration/common/class/%(object_id)s/change/",["object_id"]]]],["admin:common_class_changelist",[["administration/common/class/",[]]]],["admin:common_class_delete",[["administration/common/class/%(object_id)s/delete/",["object_id"]]]],["admin:common_class_history",[["administration/common/class/%(object_id)s/history/",["object_id"]]]],["admin:common_dailyactivity_add",[["administration/common/dailyactivity/add/",[]]]],["admin:common_dailyactivity_change",[["administration/common/dailyactivity/%(object_id)s/change/",["object_id"]]]],["admin:common_dailyactivity_changelist",[["administration/common/dailyactivity/",[]]]],["admin:common_dailyactivity_delete",[["administration/common/dailyactivity/%(object_id)s/delete/",["object_id"]]]],["admin:common_dailyactivity_history",[["administration/common/dailyactivity/%(object_id)s/history/",["object_id"]]]],["admin:common_dynamicelement_add",[["administration/common/dynamicelement/add/",[]]]],["admin:common_dynamicelement_change",[["administration/common/dynamicelement/%(object_id)s/change/",["object_id"]]]],["admin:common_dynamicelement_changelist",[["administration/common/dynamicelement/",[]]]],["admin:common_dynamicelement_delete",[["administration/common/dynamicelement/%(object_id)s/delete/",["object_id"]]]],["admin:common_dynamicelement_history",[["administration/common/dynamicelement/%(object_id)s/history/",["object_id"]]]],["admin:common_school_add",[["administration/common/school/add/",[]]]],["admin:common_school_change",[["administration/common/school/%(object_id)s/change/",["object_id"]]]],["admin:common_school_changelist",[["administration/common/school/",[]]]],["admin:common_school_delete",[["administration/common/school/%(object_id)s/delete/",["object_id"]]]],["admin:common_school_history",[["administration/common/school/%(object_id)s/history/",["object_id"]]]],["admin:common_schoolteacherinvitation_add",[["administration/common/schoolteacherinvitation/add/",[]]]],["admin:common_schoolteacherinvitation_change",[["administration/common/schoolteacherinvitation/%(object_id)s/change/",["object_id"]]]],["admin:common_schoolteacherinvitation_changelist",[["administration/common/schoolteacherinvitation/",[]]]],["admin:common_schoolteacherinvitation_delete",[["administration/common/schoolteacherinvitation/%(object_id)s/delete/",["object_id"]]]],["admin:common_schoolteacherinvitation_history",[["administration/common/schoolteacherinvitation/%(object_id)s/history/",["object_id"]]]],["admin:common_student_add",[["administration/common/student/add/",[]]]],["admin:common_student_change",[["administration/common/student/%(object_id)s/change/",["object_id"]]]],["admin:common_student_changelist",[["administration/common/student/",[]]]],["admin:common_student_delete",[["administration/common/student/%(object_id)s/delete/",["object_id"]]]],["admin:common_student_history",[["administration/common/student/%(object_id)s/history/",["object_id"]]]],["admin:common_teacher_add",[["administration/common/teacher/add/",[]]]],["admin:common_teacher_change",[["administration/common/teacher/%(object_id)s/change/",["object_id"]]]],["admin:common_teacher_changelist",[["administration/common/teacher/",[]]]],["admin:common_teacher_delete",[["administration/common/teacher/%(object_id)s/delete/",["object_id"]]]],["admin:common_teacher_history",[["administration/common/teacher/%(object_id)s/history/",["object_id"]]]],["admin:common_totalactivity_add",[["administration/common/totalactivity/add/",[]]]],["admin:common_totalactivity_change",[["administration/common/totalactivity/%(object_id)s/change/",["object_id"]]]],["admin:common_totalactivity_changelist",[["administration/common/totalactivity/",[]]]],["admin:common_totalactivity_delete",[["administration/common/totalactivity/%(object_id)s/delete/",["object_id"]]]],["admin:common_totalactivity_history",[["administration/common/totalactivity/%(object_id)s/history/",["object_id"]]]],["admin:common_userprofile_add",[["administration/common/userprofile/add/",[]]]],["admin:common_userprofile_change",[["administration/common/userprofile/%(object_id)s/change/",["object_id"]]]],["admin:common_userprofile_changelist",[["administration/common/userprofile/",[]]]],["admin:common_userprofile_delete",[["administration/common/userprofile/%(object_id)s/delete/",["object_id"]]]],["admin:common_userprofile_history",[["administration/common/userprofile/%(object_id)s/history/",["object_id"]]]],["admin:game_attempt_add",[["administration/game/attempt/add/",[]]]],["admin:game_attempt_change",[["administration/game/attempt/%(object_id)s/change/",["object_id"]]]],["admin:game_attempt_changelist",[["administration/game/attempt/",[]]]],["admin:game_attempt_delete",[["administration/game/attempt/%(object_id)s/delete/",["object_id"]]]],["admin:game_attempt_history",[["administration/game/attempt/%(object_id)s/history/",["object_id"]]]],["admin:game_block_add",[["administration/game/block/add/",[]]]],["admin:game_block_change",[["administration/game/block/%(object_id)s/change/",["object_id"]]]],["admin:game_block_changelist",[["administration/game/block/",[]]]],["admin:game_block_delete",[["administration/game/block/%(object_id)s/delete/",["object_id"]]]],["admin:game_block_history",[["administration/game/block/%(object_id)s/history/",["object_id"]]]],["admin:game_episode_add",[["administration/game/episode/add/",[]]]],["admin:game_episode_change",[["administration/game/episode/%(object_id)s/change/",["object_id"]]]],["admin:game_episode_changelist",[["administration/game/episode/",[]]]],["admin:game_episode_delete",[["administration/game/episode/%(object_id)s/delete/",["object_id"]]]],["admin:game_episode_history",[["administration/game/episode/%(object_id)s/history/",["object_id"]]]],["admin:game_level_add",[["administration/game/level/add/",[]]]],["admin:game_level_change",[["administration/game/level/%(object_id)s/change/",["object_id"]]]],["admin:game_level_changelist",[["administration/game/level/",[]]]],["admin:game_level_delete",[["administration/game/level/%(object_id)s/delete/",["object_id"]]]],["admin:game_level_history",[["administration/game/level/%(object_id)s/history/",["object_id"]]]],["admin:game_leveldecor_add",[["administration/game/leveldecor/add/",[]]]],["admin:game_leveldecor_change",[["administration/game/leveldecor/%(object_id)s/change/",["object_id"]]]],["admin:game_leveldecor_changelist",[["administration/game/leveldecor/",[]]]],["admin:game_leveldecor_delete",[["administration/game/leveldecor/%(object_id)s/delete/",["object_id"]]]],["admin:game_leveldecor_history",[["administration/game/leveldecor/%(object_id)s/history/",["object_id"]]]],["admin:game_workspace_add",[["administration/game/workspace/add/",[]]]],["admin:game_workspace_change",[["administration/game/workspace/%(object_id)s/change/",["object_id"]]]],["admin:game_workspace_changelist",[["administration/game/workspace/",[]]]],["admin:game_workspace_delete",[["administration/game/workspace/%(object_id)s/delete/",["object_id"]]]],["admin:game_workspace_history",[["administration/game/workspace/%(object_id)s/history/",["object_id"]]]],["admin:index",[["administration/",[]]]],["admin:jsi18n",[["administration/jsi18n/",[]]]],["admin:login",[["administration/login/",[]]]],["admin:logout",[["administration/logout/",[]]]],["admin:otp_static_staticdevice_add",[["administration/otp_static/staticdevice/add/",[]]]],["admin:otp_static_staticdevice_change",[["administration/otp_static/staticdevice/%(object_id)s/change/",["object_id"]]]],["admin:otp_static_staticdevice_changelist",[["administration/otp_static/staticdevice/",[]]]],["admin:otp_static_staticdevice_delete",[["administration/otp_static/staticdevice/%(object_id)s/delete/",["object_id"]]]],["admin:otp_static_staticdevice_history",[["administration/otp_static/staticdevice/%(object_id)s/history/",["object_id"]]]],["admin:otp_totp_totpdevice_add",[["administration/otp_totp/totpdevice/add/",[]]]],["admin:otp_totp_totpdevice_change",[["administration/otp_totp/totpdevice/%(object_id)s/change/",["object_id"]]]],["admin:otp_totp_totpdevice_changelist",[["administration/otp_totp/totpdevice/",[]]]],["admin:otp_totp_totpdevice_config",[["administration/otp_totp/totpdevice/%(pk)s/config/",["pk"]]]],["admin:otp_totp_totpdevice_delete",[["administration/otp_totp/totpdevice/%(object_id)s/delete/",["object_id"]]]],["admin:otp_totp_totpdevice_history",[["administration/otp_totp/totpdevice/%(object_id)s/history/",["object_id"]]]],["admin:otp_totp_totpdevice_qrcode",[["administration/otp_totp/totpdevice/%(pk)s/qrcode/",["pk"]]]],["admin:password_change",[["administration/password_change/",[]]]],["admin:password_change_done",[["administration/password_change/done/",[]]]],["admin:sites_site_add",[["administration/sites/site/add/",[]]]],["admin:sites_site_change",[["administration/sites/site/%(object_id)s/change/",["object_id"]]]],["admin:sites_site_changelist",[["administration/sites/site/",[]]]],["admin:sites_site_delete",[["administration/sites/site/%(object_id)s/delete/",["object_id"]]]],["admin:sites_site_history",[["administration/sites/site/%(object_id)s/history/",["object_id"]]]],["admin:two_factor_phonedevice_add",[["administration/two_factor/phonedevice/add/",[]]]],["admin:two_factor_phonedevice_change",[["administration/two_factor/phonedevice/%(object_id)s/change/",["object_id"]]]],["admin:two_factor_phonedevice_changelist",[["administration/two_factor/phonedevice/",[]]]],["admin:two_factor_phonedevice_delete",[["administration/two_factor/phonedevice/%(object_id)s/delete/",["object_id"]]]],["admin:two_factor_phonedevice_history",[["administration/two_factor/phonedevice/%(object_id)s/history/",["object_id"]]]],["admin:view_on_site",[["administration/r/%(content_type_id)s/%(object_id)s/",["content_type_id","object_id"]]]],["administration_password_change",[["administration/password_change/",[]]]],["administration_password_change_done",[["administration/password_change_done/",[]]]],["anonymise-unverified-accounts",[["cron/user/unverified/delete/",[]]]],["anonymise_orphan_schools",[["schools/anonymise/%(start_id)s/",["start_id"]]]],["block-detail",[["rapidrouter/api/blocks/%(pk)s/",["pk"]]]],["block-list",[["rapidrouter/api/blocks/",[]]]],["character-detail",[["rapidrouter/api/characters/%(pk)s/",["pk"]]]],["character-list",[["rapidrouter/api/characters/",[]]]],["codingClub",[["codingClub/",[]]]],["consent_form",[["consent_form/",[]]]],["contribute",[["contribute",[]]]],["dashboard",[["teach/dashboard/",[]]]],["decor-detail",[["rapidrouter/api/decors/%(pk)s/",["pk"]]]],["decor-list",[["rapidrouter/api/decors/",[]]]],["delete_account",[["delete/account/",[]]]],["delete_level",[["rapidrouter/level_moderation/delete/%(levelID)s/",["levelID"]]]],["delete_level_for_editor",[["rapidrouter/level_editor/delete/%(levelId)s/",["levelId"]]]],["delete_teacher_invite",[["teach/dashboard/delete_teacher_invite/%(token)s",["token"]]]],["delete_workspace",[["rapidrouter/workspace/delete/%(workspaceID)s/",["workspaceID"]]]],["download_student_pack",[["codingClub/%(student_pack_type)s/",["student_pack_type"]]]],["email_verification",[["verify_email/",[]]]],["episode-detail",[["rapidrouter/api/episodes/%(pk)s/",["pk"]]]],["episode-list",[["rapidrouter/api/episodes/",[]]]],["first-verify-email-reminder",[["cron/user/unverified/send-first-reminder/",[]]]],["game-delete-games",[["kurono/api/games/delete_games/",[]],["kurono/api/games/delete_games/",[]]]],["game-detail",[["kurono/api/games/%(pk)s/",["pk"]],["kurono/api/games/%(pk)s/",["pk"]]]],["game-list",[["kurono/api/games/",[]],["kurono/api/games/",[]]]],["game-running",[["kurono/api/games/running/",[]],["kurono/api/games/running/",[]]]],["generate_random_map_for_editor",[["rapidrouter/level_editor/random/",[]]]],["get_sharing_information_for_editor",[["rapidrouter/level_editor/get_sharing_information/%(levelID)s/",["levelID"]]]],["getinvolved",[["getinvolved",[]]]],["home",[["",[]]]],["home-learning",[["home-learning",[]]]],["inactive_users",[["users/inactive/",[]]]],["independent_edit_account",[["play/account/independent/",[]]]],["independent_student_details",[["play/details/independent",[]]]],["independent_student_login",[["login/independent/",[]]]],["invite_toggle_admin",[["teach/dashboard/toggle_admin_invite/%(invite_id)s/",["invite_id"]]]],["invited_teacher",[["invited_teacher/%(token)s/",["token"]]]],["js-reverse",[["rapidrouter/js-reverse/",[]]]],["kurono/badges",[["kurono/api/badges/%(id)s/",["id"]],["kurono/api/badges/%(id)s/",["id"]]]],["kurono/code",[["kurono/api/code/%(id)s/",["id"]],["kurono/api/code/%(id)s/",["id"]]]],["kurono/connection_parameters",[["kurono/api/games/%(game_id)s/connection_parameters/",["game_id"]],["kurono/api/games/%(game_id)s/connection_parameters/",["game_id"]]]],["kurono/game_token",[["kurono/api/games/%(id)s/token/",["id"]],["kurono/api/games/%(id)s/token/",["id"]]]],["kurono/game_user_details",[["kurono/api/games/%(id)s/users/",["id"]],["kurono/api/games/%(id)s/users/",["id"]]]],["kurono/js_reverse",[["kurono/jsreverse/",[]],["kurono/jsreverse/",[]]]],["kurono/play",[["kurono/play/%(id)s/",["id"]],["kurono/play/%(id)s/",["id"]]]],["kurono/statistics",[["kurono/statistics/",[]],["kurono/statistics/",[]]]],["last-connected-since",[["api/lastconnectedsince/%(year)s/%(month)s/%(day)s/",["year","month","day"]]]],["level-detail",[["rapidrouter/api/levels/%(pk)s/",["pk"]]]],["level-for-episode",[["rapidrouter/api/episodes/%(pk)s/levels/",["pk"]]]],["level-list",[["rapidrouter/api/levels/",[]]]],["level_editor",[["rapidrouter/level_editor/",[]]]],["level_editor_chosen_level",[["rapidrouter/level_editor/%(levelId)s/",["levelId"]]]],["level_moderation",[["rapidrouter/level_moderation/",[]]]],["levelblock-detail",[["rapidrouter/api/levelblocks/%(pk)s/",["pk"]]]],["levelblock-for-level",[["rapidrouter/api/levels/%(pk)s/blocks/",["pk"]]]],["leveldecor-detail",[["rapidrouter/api/leveldecors/%(pk)s/",["pk"]]]],["leveldecor-for-level",[["rapidrouter/api/levels/%(pk)s/decors/",["pk"]]]],["levels",[["rapidrouter/",[]]]],["load_level_for_editor",[["rapidrouter/level_editor/get/%(levelID)s/",["levelID"]]]],["load_list_of_workspaces",[["rapidrouter/workspace/load_list/",[]]]],["load_workspace",[["rapidrouter/workspace/load/%(workspaceID)s/",["workspaceID"]]]],["load_workspace_solution",[["rapidrouter/workspace/solution/%(level_name)s/",["level_name"]]]],["locked_out",[["locked_out/",[]]]],["logout_view",[["logout/",[]]]],["map-for-level",[["rapidrouter/api/levels/%(pk)s/map/",["pk"]]]],["map-list",[["rapidrouter/api/maps/",[]]]],["mode-for-level",[["rapidrouter/api/levels/%(pk)s/mode/",["pk"]]]],["number_users_per_country",[["api/userspercountry/%(country)s/",["country"]]]],["old_login_form",[["login_form",[]]]],["onboarding-class",[["teach/onboarding-class/%(access_code)s",["access_code"]]]],["onboarding-classes",[["teach/onboarding-classes",[]]]],["onboarding-organisation",[["teach/onboarding-organisation/",[]]]],["organisation_kick",[["teach/dashboard/kick/%(pk)s/",["pk"]]]],["organisation_leave",[["teach/dashboard/school/leave/",[]]]],["organisation_toggle_admin",[["teach/dashboard/toggle_admin/%(pk)s/",["pk"]]]],["owned_levels",[["rapidrouter/level_editor/levels/owned/",[]]]],["password_reset_check_and_confirm",[["user/password/reset/%(uidb64)s-%(token)s/",["uidb64","token"]]]],["password_reset_complete",[["teacher/password/reset/complete/",[]]]],["play",[["play/",[]]]],["play_anonymous_level",[["rapidrouter/level_editor/play_anonymous/%(levelId)s/",["levelId"]]]],["play_custom_level",[["rapidrouter/custom/%(levelId)s/",["levelId"]]]],["play_custom_level_from_editor",[["rapidrouter/level_editor/play_custom/%(levelId)s/",["levelId"]]]],["play_default_level",[["rapidrouter/%(levelName)s/",["levelName"]],["%(levelName)s/",["levelName"]]]],["privacy_notice",[["privacy-notice/",[]]]],["privacy_policy",[["privacy-policy/",[]]]],["process_newsletter_form",[["news_signup/",[]]]],["random_level_for_episode",[["rapidrouter/levels/random/%(_0)s/",["_0"]]]],["rapid-router/javascript-catalog",[["rapidrouter/js-i18n/",[]]]],["register",[["register_form",[]]]],["registered-users",[["api/registered/%(year)s/%(month)s/%(day)s/",["year","month","day"]]]],["remove_fake_accounts",[["removeFakeAccounts/",[]]]],["resend_invite_teacher",[["teach/dashboard/resend_invite/%(token)s/",["token"]]]],["reset_password_email_sent",[["user/password/reset/done/",[]]]],["reset_screentime_warning",[["user/reset_screentime_warning/",[]]]],["reset_session_time",[["user/reset_session_time/",[]]]],["rest_framework:login",[["rapidrouter/api-auth/login/",[]]]],["rest_framework:logout",[["rapidrouter/api-auth/logout/",[]]]],["save_level_for_editor",[["rapidrouter/level_editor/save/%(levelId)s/",["levelId"]],["rapidrouter/level_editor/save/",[]]]],["save_workspace",[["rapidrouter/workspace/save/%(workspaceID)s/",["workspaceID"]],["rapidrouter/workspace/save/",[]]]],["school_student_edit_account",[["play/account/school_student/",[]]]],["scoreboard",[["rapidrouter/scoreboard/",[]]]],["second-verify-email-reminder",[["cron/user/unverified/send-second-reminder/",[]]]],["send_new_users_report",[["mail/weekly/",[]]]],["set_language",[["i18n/setlang/",[]]]],["share_level_for_editor",[["rapidrouter/level_editor/share/%(levelID)s/",["levelID"]]]],["shared_levels",[["rapidrouter/level_editor/levels/shared/",[]]]],["start_episode",[["rapidrouter/episode/%(episodeId)s/",["episodeId"]]]],["student_aimmo_dashboard",[["play/kurono/dashboard/",[]]]],["student_details",[["play/details/",[]]]],["student_direct_login",[["u/%(user_id)s/%(login_id)s/",["user_id","login_id"]]]],["student_edit_account",[["play/account/",[]]]],["student_join_organisation",[["play/join/",[]]]],["student_login",[["login/student/%(access_code)s/",["access_code"]],["login/student/%(access_code)s/%(login_type)s/",["access_code","login_type"]]]],["student_login_access_code",[["login/student/",[]]]],["student_password_reset",[["user/password/reset/student/",[]]]],["submit_attempt",[["rapidrouter/submit/",[]]]],["teach",[["teach/",[]]]],["teacher_accept_student_request",[["teach/dashboard/student/accept/%(pk)s/",["pk"]]]],["teacher_aimmo_dashboard",[["teach/kurono/dashboard/",[]]]],["teacher_class_password_reset",[["teach/class/%(access_code)s/password_reset/",["access_code"]]]],["teacher_delete_class",[["teach/class/delete/%(access_code)s",["access_code"]]]],["teacher_delete_students",[["teach/class/%(access_code)s/students/delete/",["access_code"]]]],["teacher_disable_2FA",[["teach/dashboard/disable_2FA/%(pk)s/",["pk"]]]],["teacher_dismiss_students",[["teach/class/%(access_code)s/students/dismiss/",["access_code"]]]],["teacher_download_csv",[["teach/onboarding-class/%(access_code)s/download_csv/",["access_code"]]]],["teacher_edit_class",[["teach/class/edit/%(access_code)s",["access_code"]]]],["teacher_edit_student",[["teach/class/student/edit/%(pk)s/",["pk"]]]],["teacher_login",[["login/teacher/",[]]]],["teacher_move_students",[["teach/class/%(access_code)s/students/move/",["access_code"]]]],["teacher_move_students_to_class",[["teach/class/%(access_code)s/students/move/disambiguate/",["access_code"]]]],["teacher_password_reset",[["user/password/reset/teacher/",[]]]],["teacher_print_reminder_cards",[["teach/onboarding-class/%(access_code)s/print_reminder_cards/",["access_code"]]]],["teacher_reject_student_request",[["teach/dashboard/student/reject/%(pk)s/",["pk"]]]],["terms",[["terms",[]]]],["theme-detail",[["rapidrouter/api/themes/%(pk)s/",["pk"]]]],["theme-list",[["rapidrouter/api/themes/",[]]]],["two_factor:backup_tokens",[["account/two_factor/backup/tokens/",[]]]],["two_factor:disable",[["account/two_factor/disable/",[]]]],["two_factor:profile",[["account/two_factor/",[]]]],["two_factor:qr",[["account/two_factor/qrcode/",[]]]],["two_factor:setup",[["account/two_factor/setup/",[]]]],["two_factor:setup_complete",[["account/two_factor/setup/complete/",[]]]],["verify_email",[["verify_email/%(token)s/",["token"]]]],["versions",[["versions/",[]]]],["view_class",[["teach/class/%(access_code)s",["access_code"]]]]],"prefix":"/"};function factory(d){var url_patterns=d.urls;var url_prefix=d.prefix;var Urls={};var self_url_patterns={};var _get_url=function(url_pattern){return function(){var _arguments,index,url,url_arg,url_args,_i,_len,_ref,_ref_list,match_ref,provided_keys,build_kwargs;_arguments=arguments;_ref_list=self_url_patterns[url_pattern];if(arguments.length==1&&typeof(arguments[0])=="object"){var provided_keys_list=Object.keys(arguments[0]);provided_keys={};for(_i=0;_i - {% endblock %} @@ -56,26 +55,30 @@

Rapid router has been created to teach the first principles of computer prog {% endif %} {% block nav_ocargo_levels %} - {% if request.path == "/pythonden/" %} + {% if "/pythonden/" in request.path %} {% trans "Levels" %} {% else %} {% trans "Levels" %} {% endif %} {% endblock nav_ocargo_levels %} - {% if request.path != "/pythonden/" %} +{% if "/pythonden/" not in request.path %} {% block nav_ocargo_create %} {% trans "Create" %} {% endblock nav_ocargo_create %} {% endif %} - {% if user|is_logged_in_as_school_user and request.path != "/pythonden/" %} + {% if user|is_logged_in_as_school_user %} {% block nav_ocargo_scoreboard %} + {% if "/pythonden/" in request.path %} + {% trans "Scoreboard" %} + {% else %} {% trans "Scoreboard" %} + {% endif %} {% endblock nav_ocargo_scoreboard %} {% endif %} - {% if user|is_logged_in_as_teacher and request.path != "/pythonden/" %} + {% if user|is_logged_in_as_teacher and "/pythonden/" not in request.path %} {% block nav_ocargo_moderate %} {% trans "Moderate" %} {% endblock nav_ocargo_moderate %} diff --git a/game/templates/game/basenonav.html b/game/templates/game/basenonav.html index 681fed682..864dff384 100644 --- a/game/templates/game/basenonav.html +++ b/game/templates/game/basenonav.html @@ -69,6 +69,6 @@

- + {% endblock %} diff --git a/game/templates/game/scoreboard.html b/game/templates/game/scoreboard.html index f42acb98f..7f6c5e5de 100644 --- a/game/templates/game/scoreboard.html +++ b/game/templates/game/scoreboard.html @@ -4,7 +4,13 @@ {% load game.utils %} {% load app_tags %} -{% block title %}Code for Life - Rapid Router - Scoreboard{% endblock %} +{% block title %} + {% if language == "blockly" %} + Code for Life - Rapid Router - Scoreboard + {% else %} + Code for Life - Python Den - Scoreboard + {% endif %} +{% endblock %} {% block scripts %} {{block.super}} @@ -31,9 +37,21 @@ {% endblock %} {% block header %} - + {% if language == "blockly" %} + + {% else %} + + {% endif %} {% endblock header %} {% block nav_ocargo_scoreboard %} @@ -201,65 +219,67 @@

Scoreboard

-
+{% if language == "blockly" %} +
-
Shared levels
- {% if user|is_logged_in_as_teacher %} -

The shared levels table displays levels that have been shared and then played by others. - You can moderate which levels are shared on the moderation page.

- {% endif %} +
Shared levels
+ {% if user|is_logged_in_as_teacher %} +

The shared levels table displays levels that have been shared and then played by others. + You can moderate which levels are shared on the moderation page.

+ {% endif %} -
- {% if shared_student_data %} -
- - - - {% for shared_header in shared_headers %} - - {% endfor %} - {% for shared_level_header in shared_level_headers %} - - {% endfor %} - - - {% for student in shared_student_data %} - {% ifnotequal student.name user.first_name %} +
+ {% if shared_student_data %} +
+
{{ shared_header }}{{ shared_level_header }}
+ - {% else %} - - {% endifnotequal %} - - - {% for level_id, level_score in student.level_scores.items %} - {% if level_score.full_score %} - {% ifnotequal student.name user.first_name %} - - {% elif level_score.is_low_attempt %} - {% if user|is_logged_in_as_teacher %} - + {% for shared_header in shared_headers %} + + {% endfor %} + {% for shared_level_header in shared_level_headers %} + + {% endfor %} + + + {% for student in shared_student_data %} + {% ifnotequal student.name user.first_name %} + + {% else %} + + {% endifnotequal %} + + + {% for level_id, level_score in student.level_scores.items %} + {% if level_score.full_score %} + {% ifnotequal student.name user.first_name %} + + {% elif level_score.is_low_attempt %} + {% if user|is_logged_in_as_teacher %} + + {% else %} + + {% endif %} {% else %} {% endif %} - {% else %} - - {% endif %} - {% endfor %} - - {% endfor %} -
{{ student.class_field }}{{ student.name }} - {% else %} - - {% endifnotequal %} -
- -
-
{{ level_score.score }}{{ shared_header }}{{ shared_level_header }}
{{ student.class_field }}{{ student.name }} + {% else %} + + {% endifnotequal %} +
+ +
+
{{ level_score.score }}{{ level_score.score }}{{ level_score.score }}{{ level_score.score }}
- {% else %} -

No data.

- {% endif %} + {% endfor %} + + {% endfor %} + + {% else %} +

No data.

+ {% endif %} +
-
+{% endif %} {% if user|is_logged_in_as_teacher %}
diff --git a/game/tests/test_scoreboard.py b/game/tests/test_scoreboard.py index 319bdf5c1..d36f2733f 100644 --- a/game/tests/test_scoreboard.py +++ b/game/tests/test_scoreboard.py @@ -80,7 +80,7 @@ def test_teacher_multiple_students_multiple_levels(self): # Generate results student_data, headers, level_headers, levels_sorted = scoreboard_data( - episode_ids, attempts_per_student + episode_ids, attempts_per_student, "blockly" ) ( shared_headers, @@ -158,6 +158,30 @@ def test_scoreboard_loads(self): assert response.status_code == 200 assert len(response.context["level_headers"]) == active_levels.count() + def test_python_scoreboard_loads(self): + email, password = signup_teacher_directly() + create_organisation_directly(email) + klass, name, access_code = create_class_directly(email) + create_school_student_directly(access_code) + + url = reverse("python_scoreboard") + c = Client() + c.login(username=email, password=password) + + # test scoreboard page loads properly + response = c.get(url) + assert response.status_code == 200 + + # test scoreboard shows all episodes if no episodes are manually selected + data = {"classes": [klass.id], "view": [""]} + + response = c.post(url, data) + + active_levels = Level.objects.filter(episode__pk__in=range(12, 16)) + + assert response.status_code == 200 + assert len(response.context["level_headers"]) == active_levels.count() + def test_student_can_see_classes(self): """A student should be able to see the classes they are in""" mr_teacher = Teacher.objects.factory( diff --git a/game/urls.py b/game/urls.py index e1bd9daf9..9e8d7c24e 100644 --- a/game/urls.py +++ b/game/urls.py @@ -53,7 +53,7 @@ ) from game.views.level_moderation import level_moderation from game.views.level_selection import blockly_levels, random_level_for_episode -from game.views.scoreboard import scoreboard +from game.views.scoreboard import blockly_scoreboard urlpatterns = [ url(r"^$", blockly_levels, name="levels"), @@ -76,7 +76,7 @@ random_level_for_episode, name="random_level_for_episode", ), - url(r"^scoreboard/$", scoreboard, name="scoreboard"), + url(r"^scoreboard/$", blockly_scoreboard, name="scoreboard"), url( r"^workspace/", include( diff --git a/game/views/level.py b/game/views/level.py index 5dc1837b0..993602901 100644 --- a/game/views/level.py +++ b/game/views/level.py @@ -95,7 +95,11 @@ def _next_level_url(level, user, night_mode, from_python_den): """ if not level.next_level: - if level.episode and level.episode.pk == 13: + if ( + level.episode + and level.episode.next_episode + and len(level.episode.next_episode.levels) == 0 + ): return reverse("python_levels") return "" diff --git a/game/views/level_selection.py b/game/views/level_selection.py index 34ab29545..208e0b587 100644 --- a/game/views/level_selection.py +++ b/game/views/level_selection.py @@ -131,7 +131,7 @@ def get_blockly_episodes(request): def get_python_episodes(request): return fetch_episode_data( - app_settings.EARLY_ACCESS_FUNCTION(request), 16, 15 + app_settings.EARLY_ACCESS_FUNCTION(request), 16, 22 ) diff --git a/game/views/scoreboard.py b/game/views/scoreboard.py index a96590ea3..6492d0f11 100644 --- a/game/views/scoreboard.py +++ b/game/views/scoreboard.py @@ -134,6 +134,10 @@ def to_name(level): return f"L{level.name}" +def to_python_name(level): + return f"L{int(level.name) - 1000}" + + def shared_level_to_name(level, user): return ( f"{level.name} (you)" @@ -142,14 +146,16 @@ def shared_level_to_name(level, user): ) -def scoreboard_data(episode_ids, attempts_per_students): +def scoreboard_data(episode_ids, attempts_per_students, language): # Show the total score, total time and score of each level levels_sorted = [] for episode_id in episode_ids: episode = Episode.objects.get(id=episode_id) levels_sorted += episode.levels - level_headers = list(map(to_name, levels_sorted)) + to_name_function = to_name if language == "blockly" else to_python_name + + level_headers = list(map(to_name_function, levels_sorted)) student_data = [ student_row(levels_sorted, student, best_attempts) for student, best_attempts in attempts_per_students.items() @@ -235,6 +241,7 @@ def scoreboard_view( shared_headers, shared_level_headers, shared_student_data, + language, ): database_episodes = level_selection.fetch_episode_data(False) @@ -253,11 +260,20 @@ def scoreboard_view( "shared_headers": shared_headers, "shared_level_headers": shared_level_headers, "shared_student_data": shared_student_data, + "language": language, }, ) -def scoreboard(request): +def blockly_scoreboard(request): + return scoreboard(request, "blockly") + + +def python_scoreboard(request): + return scoreboard(request, "python") + + +def scoreboard(request, language): """ Renders a page with students' scores. A teacher can see the visible classes in their school. Student's view is restricted to their class if their teacher enabled @@ -268,8 +284,11 @@ def scoreboard(request): user = User(request.user.userprofile) users_classes = classes_for(user) + + episodes_range = range(1, 10) if language == "blockly" else range(12, 16) + all_episode_ids = [ - episode.id for episode in Episode.objects.filter(pk__in=range(1, 10)) + episode.id for episode in Episode.objects.filter(pk__in=episodes_range) ] if user.is_independent_student(): @@ -302,6 +321,7 @@ def scoreboard(request): form = ScoreboardForm( request.POST or None, classes=users_classes, + language=language, initial={ "classes": class_ids, "episodes": episode_ids, @@ -319,56 +339,63 @@ def scoreboard(request): all_levels += episode.levels attempts_per_student = {} - attempts_per_student_shared_levels = {} - - if user.is_teacher(): - if user.teacher.is_admin: - # Get all custom levels owned by non-admin teachers - standard_teachers = Teacher.objects.filter( - school=user.teacher.school, is_admin=False - ) - for standard_teacher in standard_teachers: - shared_levels += levels_owned_by(standard_teacher.new_user) - else: - # Get logged in teacher's custom levels - shared_levels += levels_owned_by(request.user) - - # In all cases, get all admins' custom levels - school_admins = Teacher.objects.filter( - school=user.teacher.school, is_admin=True - ) - for school_admin in school_admins: - shared_levels += levels_owned_by(school_admin.new_user) - - elif user.is_student(): - shared_levels += levels_shared_with(request.user) for student in students: best_attempts = Attempt.objects.filter( level__in=all_levels, student=student, is_best_attempt=True ).select_related("level") attempts_per_student[student] = best_attempts - shared_levels += levels_owned_by(student.new_user) - best_attempts_shared_levels = Attempt.objects.filter( - level__in=shared_levels, student=student, is_best_attempt=True - ).select_related("level") - attempts_per_student_shared_levels[ - student - ] = best_attempts_shared_levels (student_data, headers, level_headers, levels_sorted) = scoreboard_data( - episode_ids, attempts_per_student + episode_ids, attempts_per_student, language ) improvement_data = get_improvement_data(attempts_per_student) - ( - shared_headers, - shared_level_headers, - shared_student_data, - ) = shared_levels_data( - request.user.userprofile, - shared_levels, - attempts_per_student_shared_levels, - ) + + shared_headers = shared_level_headers = shared_student_data = [] + + if language == "blockly": + attempts_per_student_shared_levels = {} + + if user.is_teacher(): + if user.teacher.is_admin: + # Get all custom levels owned by non-admin teachers + standard_teachers = Teacher.objects.filter( + school=user.teacher.school, is_admin=False + ) + for standard_teacher in standard_teachers: + shared_levels += levels_owned_by(standard_teacher.new_user) + else: + # Get logged in teacher's custom levels + shared_levels += levels_owned_by(request.user) + + # In all cases, get all admins' custom levels + school_admins = Teacher.objects.filter( + school=user.teacher.school, is_admin=True + ) + for school_admin in school_admins: + shared_levels += levels_owned_by(school_admin.new_user) + + elif user.is_student(): + shared_levels += levels_shared_with(request.user) + + for student in students: + shared_levels += levels_owned_by(student.new_user) + best_attempts_shared_levels = Attempt.objects.filter( + level__in=shared_levels, student=student, is_best_attempt=True + ).select_related("level") + attempts_per_student_shared_levels[ + student + ] = best_attempts_shared_levels + + ( + shared_headers, + shared_level_headers, + shared_student_data, + ) = shared_levels_data( + request.user.userprofile, + shared_levels, + attempts_per_student_shared_levels, + ) csv_export = "export" in request.POST @@ -391,6 +418,7 @@ def scoreboard(request): shared_headers, shared_level_headers, shared_student_data, + language, )