rapid-router 5.4.1__py2.py3-none-any.whl → 7.6.8__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. example_project/rapid_router_test_settings.py +164 -0
  2. example_project/settings.py +152 -0
  3. example_project/urls.py +15 -0
  4. example_project/{example_project/wsgi.py → wsgi.py} +2 -1
  5. game/__init__.py +1 -1
  6. game/admin.py +43 -4
  7. game/app_settings.py +3 -7
  8. game/character.py +26 -18
  9. game/decor.py +172 -97
  10. game/end_to_end_tests/base_game_test.py +44 -33
  11. game/end_to_end_tests/editor_page.py +17 -2
  12. game/end_to_end_tests/game_page.py +127 -45
  13. game/end_to_end_tests/selenium_test_case.py +1 -20
  14. game/end_to_end_tests/test_cow_crashes.py +3 -5
  15. game/end_to_end_tests/test_language_dropdown.py +14 -0
  16. game/end_to_end_tests/test_level_editor.py +290 -0
  17. game/end_to_end_tests/test_level_failures.py +1 -1
  18. game/end_to_end_tests/test_level_selection.py +79 -0
  19. game/end_to_end_tests/test_play_through.py +240 -102
  20. game/end_to_end_tests/test_python_levels.py +44 -13
  21. game/end_to_end_tests/test_saving_workspace.py +22 -0
  22. game/forms.py +9 -2
  23. game/level_management.py +38 -29
  24. game/messages.py +1218 -203
  25. game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
  26. game/migrations/0026_levels_pt2.py +13 -2
  27. game/migrations/0032_cannot_turn_left_level.py +13 -2
  28. game/migrations/0033_recursion_level.py +13 -2
  29. game/migrations/0034_joes_level.py +13 -2
  30. game/migrations/0035_disable_route_score_level_70.py +0 -2
  31. game/migrations/0036_level_score_73.py +0 -2
  32. game/migrations/0037_level_score_79.py +0 -2
  33. game/migrations/0038_level_score_40.py +0 -1
  34. game/migrations/0042_level_score_73.py +0 -2
  35. game/migrations/0048_add_cow_field_and_blocks.py +0 -2
  36. game/migrations/0049_level_score_34.py +0 -2
  37. game/migrations/0050_level_score_40.py +0 -2
  38. game/migrations/0051_level_score_49.py +0 -1
  39. game/migrations/0076_level_locked_for_class.py +19 -0
  40. game/migrations/0077_alter_level_next_level.py +52 -0
  41. game/migrations/0078_add_block_types.py +23 -0
  42. game/migrations/0079_populate_block_type_add_cow_blocks.py +60 -0
  43. game/migrations/0080_level_disable_algorithm_score.py +18 -0
  44. game/migrations/0081_first_12_levels_no_algo_score.py +29 -0
  45. game/migrations/0082_level_43_solution.py +16 -0
  46. game/migrations/0083_add_cows_to_existing_levels.py +195 -0
  47. game/migrations/0084_alter_block_block_type.py +18 -0
  48. game/migrations/0085_add_new_blocks.py +53 -0
  49. game/migrations/0086_loop_levels.py +482 -0
  50. game/migrations/0087_workspace_python_view_enabled.py +18 -0
  51. game/migrations/0088_rename_episodes.py +35 -0
  52. game/migrations/0089_episodes_in_development.py +30 -0
  53. game/migrations/0090_add_missing_model_solutions.py +144 -0
  54. game/migrations/0091_disable_algo_score_if_no_model_solution.py +46 -0
  55. game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
  56. game/migrations/0093_alter_level_character_name.py +18 -0
  57. game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
  58. game/migrations/0095_level_commands.py +18 -0
  59. game/migrations/0096_alter_level_commands.py +18 -0
  60. game/migrations/0097_add_python_den_levels.py +1515 -0
  61. game/migrations/0098_add_episode_link_fields.py +44 -0
  62. game/migrations/0099_python_episodes_links.py +103 -0
  63. game/migrations/0100_reorder_python_levels.py +179 -0
  64. game/migrations/0101_rename_episodes.py +45 -0
  65. game/migrations/0102_reoder_episodes_13_14.py +136 -0
  66. game/migrations/0103_level_1015_solution.py +26 -0
  67. game/migrations/0104_remove_level_direct_drive.py +17 -0
  68. game/migrations/0105_delete_invalid_attempts.py +18 -0
  69. game/migrations/0106_fields_to_snake_case.py +48 -0
  70. game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
  71. game/migrations/0108_episode_indy_worksheet_link.py +18 -0
  72. game/migrations/0109_create_episodes_23_and_24.py +99 -0
  73. game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
  74. game/migrations/0111_create_worksheets.py +149 -0
  75. game/migrations/0112_worksheet_locked_classes.py +21 -0
  76. game/migrations/0113_level_needs_approval.py +18 -0
  77. game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
  78. game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
  79. game/migrations/0116_update_worksheet_video_links.py +68 -0
  80. game/migrations/0117_update_solutions_to_if_else.py +61 -0
  81. game/models.py +157 -16
  82. game/permissions.py +34 -19
  83. game/python_den_urls.py +26 -0
  84. game/random_road.py +43 -127
  85. game/serializers.py +12 -17
  86. game/static/django_reverse_js/js/reverse.js +171 -0
  87. game/static/game/css/LilitaOne-Regular.ttf +0 -0
  88. game/static/game/css/backgrounds.css +14 -10
  89. game/static/game/css/dataTables.custom.css +4 -2
  90. game/static/game/css/dataTables.jqueryui.css +561 -320
  91. game/static/game/css/editor.css +47 -0
  92. game/static/game/css/game.css +43 -49
  93. game/static/game/css/game_screen.css +116 -53
  94. game/static/game/css/jquery.dataTables.css +455 -251
  95. game/static/game/css/level_editor.css +10 -1
  96. game/static/game/css/level_selection.css +32 -3
  97. game/static/game/css/level_share.css +6 -5
  98. game/static/game/css/skulpt/codemirror.css +1 -0
  99. game/static/game/image/Python_Den_hero_student.png +0 -0
  100. game/static/game/image/Python_levels_page.svg +1954 -0
  101. game/static/game/image/characters/front_view/Electric_van.svg +448 -0
  102. game/static/game/image/characters/top_view/Electric_van.svg +448 -0
  103. game/static/game/image/characters/top_view/Sleigh.svg +436 -0
  104. game/static/game/image/decor/city/solar_panel.svg +1200 -0
  105. game/static/game/image/decor/farm/solar_panel.svg +86 -0
  106. game/static/game/image/decor/grass/solar_panel.svg +86 -0
  107. game/static/game/image/decor/snow/barn.svg +1788 -0
  108. game/static/game/image/decor/snow/cfc.svg +1050 -147
  109. game/static/game/image/decor/snow/crops.svg +7370 -0
  110. game/static/game/image/decor/snow/hospital.svg +1220 -0
  111. game/static/game/image/decor/snow/house1.svg +971 -0
  112. game/static/game/image/decor/snow/house2.svg +1574 -0
  113. game/static/game/image/decor/snow/school.svg +1071 -0
  114. game/static/game/image/decor/snow/shop.svg +3211 -0
  115. game/static/game/image/decor/snow/solar_panel.svg +173 -0
  116. game/static/game/image/electric_van.svg +448 -0
  117. game/static/game/image/icons/add_house.svg +26 -0
  118. game/static/game/image/icons/delete_house.svg +26 -0
  119. game/static/game/image/icons/description.svg +1 -0
  120. game/static/game/image/icons/hint.svg +1 -0
  121. game/static/game/image/icons/if_else.svg +3 -0
  122. game/static/game/image/icons/python.svg +1 -1
  123. game/static/game/image/if_else_example.png +0 -0
  124. game/static/game/image/pigeon.svg +684 -0
  125. game/static/game/image/python_den_header.svg +19 -0
  126. game/static/game/js/animation.js +84 -28
  127. game/static/game/js/blockly/msg/js/bg.js +52 -1
  128. game/static/game/js/blockly/msg/js/ca.js +52 -1
  129. game/static/game/js/blockly/msg/js/en-gb.js +52 -1
  130. game/static/game/js/blockly/msg/js/en.js +52 -1
  131. game/static/game/js/blockly/msg/js/es.js +52 -1
  132. game/static/game/js/blockly/msg/js/fr.js +52 -1
  133. game/static/game/js/blockly/msg/js/hi.js +52 -1
  134. game/static/game/js/blockly/msg/js/it.js +52 -1
  135. game/static/game/js/blockly/msg/js/pl.js +52 -1
  136. game/static/game/js/blockly/msg/js/pt-br.js +52 -1
  137. game/static/game/js/blockly/msg/js/ru.js +52 -1
  138. game/static/game/js/blockly/msg/js/ur.js +52 -1
  139. game/static/game/js/blocklyCompiler.js +550 -392
  140. game/static/game/js/blocklyControl.js +335 -302
  141. game/static/game/js/blocklyCustomBlocks.js +691 -458
  142. game/static/game/js/blocklyCustomisations.js +3 -1
  143. game/static/game/js/button.js +12 -0
  144. game/static/game/js/cow.js +15 -130
  145. game/static/game/js/drawing.js +313 -201
  146. game/static/game/js/editor.js +23 -0
  147. game/static/game/js/game.js +148 -139
  148. game/static/game/js/jquery.dataTables.min.js +3 -159
  149. game/static/game/js/level_editor.js +823 -448
  150. game/static/game/js/level_moderation.js +33 -2
  151. game/static/game/js/level_selection.js +62 -25
  152. game/static/game/js/loadLanguages.js +21 -0
  153. game/static/game/js/map.js +106 -36
  154. game/static/game/js/model.js +55 -107
  155. game/static/game/js/pathFinder.js +73 -72
  156. game/static/game/js/program.js +184 -193
  157. game/static/game/js/pythonControl.js +14 -1
  158. game/static/game/js/scoreboard.js +0 -37
  159. game/static/game/js/scoreboardSharedLevels.js +48 -0
  160. game/static/game/js/sharing.js +22 -10
  161. game/static/game/js/skulpt/codemirror.js +5 -4
  162. game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
  163. game/static/game/js/sound.js +52 -5
  164. game/static/game/js/van.js +0 -7
  165. game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
  166. game/static/game/raphael_image/characters/top_view/Sleigh.svg +436 -0
  167. game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
  168. game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
  169. game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
  170. game/static/game/raphael_image/decor/snow/barn.svg +1788 -0
  171. game/static/game/raphael_image/decor/snow/cfc.svg +1050 -147
  172. game/static/game/raphael_image/decor/snow/crops.svg +7370 -0
  173. game/static/game/raphael_image/decor/snow/hospital.svg +1220 -0
  174. game/static/game/raphael_image/decor/snow/house1.svg +971 -0
  175. game/static/game/raphael_image/decor/snow/house2.svg +1574 -0
  176. game/static/game/raphael_image/decor/snow/school.svg +1071 -0
  177. game/static/game/raphael_image/decor/snow/shop.svg +3211 -0
  178. game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
  179. game/static/game/raphael_image/pigeon.svg +685 -0
  180. game/static/game/raphael_image/sleigh_wreckage.svg +430 -0
  181. game/static/game/sass/game.scss +22 -6
  182. game/static/game/sound/clown_horn.mp3 +0 -0
  183. game/static/game/sound/clown_horn.ogg +0 -0
  184. game/static/game/sound/electric_van_starting.mp3 +0 -0
  185. game/static/game/sound/electric_van_starting.ogg +0 -0
  186. game/static/game/sound/pigeon.mp3 +0 -0
  187. game/static/game/sound/pigeon.ogg +0 -0
  188. game/static/game/sound/sleigh_bells.mp3 +0 -0
  189. game/static/game/sound/sleigh_bells.ogg +0 -0
  190. game/static/game/sound/sleigh_crash.mp3 +0 -0
  191. game/static/game/sound/sleigh_crash.ogg +0 -0
  192. game/templates/game/base.html +35 -15
  193. game/templates/game/basenonav.html +23 -17
  194. game/templates/game/game.html +236 -111
  195. game/templates/game/level_editor.html +353 -275
  196. game/templates/game/level_moderation.html +19 -6
  197. game/templates/game/level_selection.html +75 -62
  198. game/templates/game/python_den_level_selection.html +291 -0
  199. game/templates/game/python_den_worksheet.html +101 -0
  200. game/templates/game/scoreboard.html +88 -65
  201. game/tests/test_level_editor.py +210 -35
  202. game/tests/test_level_moderation.py +6 -20
  203. game/tests/test_level_selection.py +332 -11
  204. game/tests/test_python_den_worksheet.py +85 -0
  205. game/tests/test_scoreboard.py +258 -66
  206. game/tests/utils/level.py +43 -3
  207. game/tests/utils/teacher.py +2 -2
  208. game/theme.py +21 -21
  209. game/urls.py +125 -78
  210. game/views/language_code_conversions.py +90 -0
  211. game/views/level.py +201 -63
  212. game/views/level_editor.py +109 -48
  213. game/views/level_moderation.py +29 -6
  214. game/views/level_selection.py +179 -56
  215. game/views/level_solutions.py +600 -106
  216. game/views/scoreboard.py +181 -66
  217. game/views/worksheet.py +25 -0
  218. rapid_router-7.6.8.dist-info/METADATA +174 -0
  219. {rapid_router-5.4.1.dist-info → rapid_router-7.6.8.dist-info}/RECORD +222 -242
  220. {rapid_router-5.4.1.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
  221. rapid_router-7.6.8.dist-info/licenses/LICENSE.md +3 -0
  222. example_project/example_project/__init__.py +0 -1
  223. example_project/example_project/settings.py +0 -54
  224. example_project/example_project/urls.py +0 -16
  225. example_project/manage.py +0 -10
  226. game/autoconfig.py +0 -59
  227. game/csp_config.py +0 -23
  228. game/locale/ar_SA/LC_MESSAGES/django.mo +0 -0
  229. game/locale/ar_SA/LC_MESSAGES/django.po +0 -405
  230. game/locale/ar_SA/LC_MESSAGES/djangojs.mo +0 -0
  231. game/locale/ar_SA/LC_MESSAGES/djangojs.po +0 -743
  232. game/locale/bg_BG/LC_MESSAGES/django.mo +0 -0
  233. game/locale/bg_BG/LC_MESSAGES/django.po +0 -405
  234. game/locale/bg_BG/LC_MESSAGES/djangojs.mo +0 -0
  235. game/locale/bg_BG/LC_MESSAGES/djangojs.po +0 -739
  236. game/locale/ca_ES/LC_MESSAGES/django.mo +0 -0
  237. game/locale/ca_ES/LC_MESSAGES/django.po +0 -405
  238. game/locale/ca_ES/LC_MESSAGES/djangojs.mo +0 -0
  239. game/locale/ca_ES/LC_MESSAGES/djangojs.po +0 -740
  240. game/locale/cs_CZ/LC_MESSAGES/django.mo +0 -0
  241. game/locale/cs_CZ/LC_MESSAGES/django.po +0 -405
  242. game/locale/cs_CZ/LC_MESSAGES/djangojs.mo +0 -0
  243. game/locale/cs_CZ/LC_MESSAGES/djangojs.po +0 -741
  244. game/locale/cy_GB/LC_MESSAGES/django.mo +0 -0
  245. game/locale/cy_GB/LC_MESSAGES/django.po +0 -405
  246. game/locale/cy_GB/LC_MESSAGES/djangojs.mo +0 -0
  247. game/locale/cy_GB/LC_MESSAGES/djangojs.po +0 -743
  248. game/locale/de_DE/LC_MESSAGES/django.mo +0 -0
  249. game/locale/de_DE/LC_MESSAGES/django.po +0 -405
  250. game/locale/de_DE/LC_MESSAGES/djangojs.mo +0 -0
  251. game/locale/de_DE/LC_MESSAGES/djangojs.po +0 -739
  252. game/locale/el_GR/LC_MESSAGES/django.mo +0 -0
  253. game/locale/el_GR/LC_MESSAGES/django.po +0 -405
  254. game/locale/el_GR/LC_MESSAGES/djangojs.mo +0 -0
  255. game/locale/el_GR/LC_MESSAGES/djangojs.po +0 -739
  256. game/locale/en_GB/LC_MESSAGES/django.mo +0 -0
  257. game/locale/en_GB/LC_MESSAGES/django.po +0 -405
  258. game/locale/en_GB/LC_MESSAGES/djangojs.mo +0 -0
  259. game/locale/en_GB/LC_MESSAGES/djangojs.po +0 -739
  260. game/locale/es_ES/LC_MESSAGES/django.mo +0 -0
  261. game/locale/es_ES/LC_MESSAGES/django.po +0 -405
  262. game/locale/es_ES/LC_MESSAGES/djangojs.mo +0 -0
  263. game/locale/es_ES/LC_MESSAGES/djangojs.po +0 -739
  264. game/locale/fi_FI/LC_MESSAGES/django.mo +0 -0
  265. game/locale/fi_FI/LC_MESSAGES/django.po +0 -405
  266. game/locale/fi_FI/LC_MESSAGES/djangojs.mo +0 -0
  267. game/locale/fi_FI/LC_MESSAGES/djangojs.po +0 -739
  268. game/locale/fr_FR/LC_MESSAGES/django.mo +0 -0
  269. game/locale/fr_FR/LC_MESSAGES/django.po +0 -405
  270. game/locale/fr_FR/LC_MESSAGES/djangojs.mo +0 -0
  271. game/locale/fr_FR/LC_MESSAGES/djangojs.po +0 -739
  272. game/locale/gu_IN/LC_MESSAGES/django.mo +0 -0
  273. game/locale/gu_IN/LC_MESSAGES/django.po +0 -405
  274. game/locale/gu_IN/LC_MESSAGES/djangojs.mo +0 -0
  275. game/locale/gu_IN/LC_MESSAGES/djangojs.po +0 -739
  276. game/locale/hi_IN/LC_MESSAGES/django.mo +0 -0
  277. game/locale/hi_IN/LC_MESSAGES/django.po +0 -405
  278. game/locale/hi_IN/LC_MESSAGES/djangojs.mo +0 -0
  279. game/locale/hi_IN/LC_MESSAGES/djangojs.po +0 -739
  280. game/locale/id_ID/LC_MESSAGES/django.mo +0 -0
  281. game/locale/id_ID/LC_MESSAGES/django.po +0 -405
  282. game/locale/id_ID/LC_MESSAGES/djangojs.mo +0 -0
  283. game/locale/id_ID/LC_MESSAGES/djangojs.po +0 -738
  284. game/locale/it_IT/LC_MESSAGES/django.mo +0 -0
  285. game/locale/it_IT/LC_MESSAGES/django.po +0 -405
  286. game/locale/it_IT/LC_MESSAGES/djangojs.mo +0 -0
  287. game/locale/it_IT/LC_MESSAGES/djangojs.po +0 -739
  288. game/locale/ja_JP/LC_MESSAGES/django.mo +0 -0
  289. game/locale/ja_JP/LC_MESSAGES/django.po +0 -405
  290. game/locale/ja_JP/LC_MESSAGES/djangojs.mo +0 -0
  291. game/locale/ja_JP/LC_MESSAGES/djangojs.po +0 -738
  292. game/locale/lol_US/LC_MESSAGES/django.mo +0 -0
  293. game/locale/lol_US/LC_MESSAGES/django.po +0 -405
  294. game/locale/lol_US/LC_MESSAGES/djangojs.mo +0 -0
  295. game/locale/lol_US/LC_MESSAGES/djangojs.po +0 -739
  296. game/locale/nb_NO/LC_MESSAGES/django.mo +0 -0
  297. game/locale/nb_NO/LC_MESSAGES/django.po +0 -405
  298. game/locale/nb_NO/LC_MESSAGES/djangojs.mo +0 -0
  299. game/locale/nb_NO/LC_MESSAGES/djangojs.po +0 -739
  300. game/locale/nl_NL/LC_MESSAGES/django.mo +0 -0
  301. game/locale/nl_NL/LC_MESSAGES/django.po +0 -405
  302. game/locale/nl_NL/LC_MESSAGES/djangojs.mo +0 -0
  303. game/locale/nl_NL/LC_MESSAGES/djangojs.po +0 -739
  304. game/locale/pl_PL/LC_MESSAGES/django.mo +0 -0
  305. game/locale/pl_PL/LC_MESSAGES/django.po +0 -405
  306. game/locale/pl_PL/LC_MESSAGES/djangojs.mo +0 -0
  307. game/locale/pl_PL/LC_MESSAGES/djangojs.po +0 -741
  308. game/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  309. game/locale/pt_BR/LC_MESSAGES/django.po +0 -405
  310. game/locale/pt_BR/LC_MESSAGES/djangojs.mo +0 -0
  311. game/locale/pt_BR/LC_MESSAGES/djangojs.po +0 -739
  312. game/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  313. game/locale/pt_PT/LC_MESSAGES/django.po +0 -405
  314. game/locale/pt_PT/LC_MESSAGES/djangojs.mo +0 -0
  315. game/locale/pt_PT/LC_MESSAGES/djangojs.po +0 -739
  316. game/locale/ro_RO/LC_MESSAGES/django.mo +0 -0
  317. game/locale/ro_RO/LC_MESSAGES/django.po +0 -405
  318. game/locale/ro_RO/LC_MESSAGES/djangojs.mo +0 -0
  319. game/locale/ro_RO/LC_MESSAGES/djangojs.po +0 -740
  320. game/locale/ru_RU/LC_MESSAGES/django.mo +0 -0
  321. game/locale/ru_RU/LC_MESSAGES/django.po +0 -405
  322. game/locale/ru_RU/LC_MESSAGES/djangojs.mo +0 -0
  323. game/locale/ru_RU/LC_MESSAGES/djangojs.po +0 -741
  324. game/locale/sv_SE/LC_MESSAGES/django.mo +0 -0
  325. game/locale/sv_SE/LC_MESSAGES/django.po +0 -405
  326. game/locale/sv_SE/LC_MESSAGES/djangojs.mo +0 -0
  327. game/locale/sv_SE/LC_MESSAGES/djangojs.po +0 -739
  328. game/locale/tl_PH/LC_MESSAGES/django.mo +0 -0
  329. game/locale/tl_PH/LC_MESSAGES/django.po +0 -405
  330. game/locale/tl_PH/LC_MESSAGES/djangojs.mo +0 -0
  331. game/locale/tl_PH/LC_MESSAGES/djangojs.po +0 -739
  332. game/locale/tlh_AA/LC_MESSAGES/django.mo +0 -0
  333. game/locale/tlh_AA/LC_MESSAGES/django.po +0 -405
  334. game/locale/tlh_AA/LC_MESSAGES/djangojs.mo +0 -0
  335. game/locale/tlh_AA/LC_MESSAGES/djangojs.po +0 -739
  336. game/locale/tr_TR/LC_MESSAGES/django.mo +0 -0
  337. game/locale/tr_TR/LC_MESSAGES/django.po +0 -405
  338. game/locale/tr_TR/LC_MESSAGES/djangojs.mo +0 -0
  339. game/locale/tr_TR/LC_MESSAGES/djangojs.po +0 -740
  340. game/locale/ur_IN/LC_MESSAGES/django.mo +0 -0
  341. game/locale/ur_IN/LC_MESSAGES/django.po +0 -405
  342. game/locale/ur_IN/LC_MESSAGES/djangojs.mo +0 -0
  343. game/locale/ur_IN/LC_MESSAGES/djangojs.po +0 -739
  344. game/locale/ur_PK/LC_MESSAGES/django.mo +0 -0
  345. game/locale/ur_PK/LC_MESSAGES/django.po +0 -405
  346. game/locale/ur_PK/LC_MESSAGES/djangojs.mo +0 -0
  347. game/locale/ur_PK/LC_MESSAGES/djangojs.po +0 -739
  348. game/static/game/image/actions/go.svg +0 -18
  349. game/static/game/image/icons/destination.svg +0 -9
  350. game/static/game/js/pqselect.min.js +0 -9
  351. game/static/game/js/widget-scroller.js +0 -906
  352. rapid_router-5.4.1.dist-info/LICENSE.md +0 -577
  353. rapid_router-5.4.1.dist-info/METADATA +0 -24
  354. {rapid_router-5.4.1.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
@@ -34,13 +34,14 @@
34
34
  <div class="background">
35
35
  <div class="container">
36
36
  <div>
37
- <h4>Level moderation</h5>
37
+ <h4>Level moderation</h4>
38
38
  <p>Search or filter the levels to find specific details, and click 'Play' to view the games.</p>
39
+ <p>You can approve or delete any level.</p>
39
40
 
40
41
  <form action="" method="post" id="moderateForm">
41
42
  {% csrf_token %}
42
43
  <div class="row form--row">
43
- <div class="col-sm-4">
44
+ <div class="col-sm-6">
44
45
  <div class="dropdown">
45
46
  <button class="button--secondary button--secondary--dark button--dropdown" type="button" data-toggle="dropdown" aria-expanded="false">
46
47
  <div class="dropdown__text">Filter classes</div>
@@ -76,7 +77,7 @@
76
77
  </div>
77
78
  </div>
78
79
  </div>
79
- <div class="form--row__input col-sm-4">
80
+ <div class="form--row__input col-sm-6">
80
81
  <div class="input--icon">
81
82
  <input type="text" name="Search" placeholder="Search" id="moderateSearch"><span class="iconify" data-icon="mdi:search"></span>
82
83
  </div>
@@ -89,7 +90,7 @@
89
90
  <div class="mainBody container">
90
91
  {% include "portal/partials/popup.html" %}
91
92
  {% if levelData %}
92
- <div class="tableWrapper">
93
+ <div class="tableWrapper" id="tableWrapper">
93
94
  {% if thead %}
94
95
  <table id="moderateTable" class="header-primary data-primary">
95
96
  <thead>
@@ -97,11 +98,12 @@
97
98
  <th rowspan="2">Student</th>
98
99
  <th rowspan="2">Level name</th>
99
100
  <th rowspan="2">Shared with</th>
100
- <th colspan="2">Actions</th>
101
+ <th colspan="3">Actions</th>
101
102
  </tr>
102
103
  <!-- Extra header only needed for DataTables - should be hidden to the user -->
103
104
  <tr class="d-none">
104
105
  <th>Play</th>
106
+ <th>Approve</th>
105
107
  <th>Delete</th>
106
108
  </tr>
107
109
  </thead>
@@ -113,7 +115,18 @@
113
115
  <td><small>{{level.name}}</small></td>
114
116
  <td><small>{{level.shared_with}}</small></td>
115
117
  <td class="text-center">
116
- <button class="button button--small button--primary play" value={{level.id}}>Play</button>
118
+ <a class="button button--small button--primary play" href="{% url 'play_custom_level' level.id %}">Play</a>
119
+ </td>
120
+ <td class="text-center">
121
+ {% if level.needs_approval %}
122
+ <button class="button button--small button--primary approve" value={{level.id}}>
123
+ Approve
124
+ </button>
125
+ {% else %}
126
+ <button class="button button--small button--primary disabled button--icon">
127
+ Approved<span class="iconify" data-icon="mdi:tick"></span>
128
+ </button>
129
+ {% endif %}
117
130
  </td>
118
131
  <td class="text-center">
119
132
  <button class="button button--small button--primary--danger button--icon delete" value={{level.id}}>
@@ -20,14 +20,14 @@
20
20
  EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
21
21
  {% endfor %}
22
22
 
23
- {% for episode in pythonEpisodes %}
23
+ {% for episode in oldPythonEpisodes %}
24
24
  var levels = [];
25
25
  {% for level in episode.levels %}
26
- levels.push({
27
- 'name': {{level.name}},
26
+ levels.push({
27
+ 'name': {{level.name}},
28
28
  'score': '{{level.score}}',
29
- 'maxScore': {{level.maxScore}}
30
- });
29
+ 'maxScore': {{level.maxScore}}
30
+ });
31
31
  {% endfor %}
32
32
  EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
33
33
  {% endfor %}
@@ -41,7 +41,7 @@
41
41
  {% endfor %}
42
42
  </script>
43
43
 
44
- <script src="{% static "game/js/level_selection.js" %}"></script>
44
+ <script src="{% static 'game/js/level_selection.js' %}"></script>
45
45
  {% endblock %}
46
46
 
47
47
  {% block css %}
@@ -71,8 +71,9 @@
71
71
  <div id="episodes">
72
72
  <div class="panel-intro">
73
73
  <h4>Blockly levels</h4>
74
- The first set of levels use Blockly to slowly introduce you to Python. You can read more about Blockly
75
- <a href="https://docs.codeforlife.education/rapid-router/blockly-guide" target="_blank">here</a>.
74
+ The first set of levels use Blockly to slowly introduce you to
75
+ core programming concepts. You can read more about Blockly
76
+ <a href="https://code-for-life.gitbook.io/rapid-router/blockly-guide" target="_blank">here</a>.
76
77
  </div>
77
78
  {% for episode in blocklyEpisodes %}
78
79
  <div class="panel">
@@ -88,21 +89,40 @@
88
89
 
89
90
  <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
90
91
  <div class="panel-body">
92
+ {% if not user.is_authenticated and episode.id > 2 %}
93
+ <p class="text--warning">In order to access the full content for this course, please log in.</p>
94
+ {% endif %}
91
95
  {% for level in episode.levels %}
92
- <!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
93
- <p>
94
- <a href="{% url 'play_default_level' level.name %}">{{level.name}}: {{level.title.strip | safe}}</a>
95
- {% if level.score != None %}
96
- <span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
97
- <img class="level_image coin_image" value="{{level.name}}">
96
+ {% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
97
+ <!-- Mark level as locked -->
98
+ <p>
99
+ <a class="disabled">{{level.name}}: {{level.title.strip | safe}}</a>
100
+ {% if level.score != None %}
101
+ <span class="score_text disabled">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
102
+ <img class="level_image coin_image" value="{{level.name}}">
103
+ {% endif %}
104
+ </p>
105
+ {% elif not user.is_authenticated and level.name > 19 and level.name != 29 and level.name != 33 and level.name != 44 and level.name != 51 and level.name != 61 and level.name != 68 %}
106
+ <!-- Mark level as locked -->
107
+ <p>
108
+ <a class="disabled">{{level.name}}: {{level.title.strip | safe}}</a>
109
+ </p>
110
+ {% else %}
111
+ <!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
112
+ <p>
113
+ <a href="{% url 'play_default_level' level.name %}">{{level.name}}: {{level.title.strip | safe}}</a>
114
+ {% if level.score != None %}
115
+ <span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
116
+ <img class="level_image coin_image" value="{{level.name}}">
117
+ {% endif %}
118
+ </p>
98
119
  {% endif %}
99
- </p>
100
120
  {% endfor %}
101
121
 
102
- {% if episode.random_levels_enabled %}
122
+ {% if not user.is_authenticated and episode.id <= 2 or user.is_authenticated and episode.random_levels_enabled %}
103
123
  <p>
104
124
  <a href="{% url 'random_level_for_episode' episode.id %}">
105
- Random: Try your hand at a random level.
125
+ Random: Try your hand at a random level
106
126
  </a>
107
127
  </p>
108
128
  {% endif %}
@@ -111,40 +131,6 @@
111
131
  </div>
112
132
  {% endfor %}
113
133
 
114
- <div class="panel-intro">
115
- <h4>Python levels</h4>
116
- The next set of levels introduce you to coding directly with Python. You can read more about Python
117
- <a href="https://docs.codeforlife.education/rapid-router/python-guide" target="_blank">here</a>.
118
- </div>
119
- {% for episode in pythonEpisodes %}
120
- <div class="panel">
121
- <div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
122
- <p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
123
- {{episode.name}}
124
- <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
125
- Levels {{episode.first_level}}-{{episode.last_level}}
126
- </span>
127
- <img class="episode_image coin_image" value="{{episode.id}}">
128
- </p>
129
- </div>
130
-
131
- <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
132
- <div class="panel-body">
133
- {% for level in episode.levels %}
134
- <!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
135
- <p>
136
- <a href="{% url 'play_default_level' level.name %}">{{level.name}}: {{level.title.strip | safe}}</a>
137
- {% if level.score != None %}
138
- <span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
139
- <img class="level_image coin_image" value="{{level.name}}">
140
- {% endif %}
141
- </p>
142
- {% endfor %}
143
- </div>
144
- </div>
145
- </div>
146
- {% endfor %}
147
-
148
134
  {% if user|is_logged_in %}
149
135
  <div class="panel-intro">
150
136
  <h4>Created levels</h4>
@@ -187,19 +173,46 @@
187
173
  </div>
188
174
  <div id="collapse-levels-shared-with-you" aria-labelledby="episode-levels-shared-with-you" class="collapse">
189
175
  <div class="panel-body">
190
- {% if shared_levels %}
191
- {% for level in shared_levels %}
192
- <p>
193
- <a href="{% url 'play_custom_level' level.id %}">
194
- {{level.title}} ({{level.owner|make_into_username}})</a>
195
- {% if level.score != None %}
196
- <span class="score_text">{{level.score|floatformat}}/10</span>
197
- <img class="level_image coin_image" value="{{level.id}}">
198
- {% endif %}
199
- </p>
176
+ {% if user|is_logged_in_as_admin_teacher %}
177
+ <h6>Your classes</h6>
178
+ {% endif %}
179
+ {% if directly_shared_levels %}
180
+ {% for level in directly_shared_levels %}
181
+ <p>
182
+ <a href="{% url 'play_custom_level' level.id %}">
183
+ {{ level.title }}, {{ level.owner|make_into_username }}
184
+ {% if level.class %}
185
+ ({{ level.class }})
186
+ {% endif %}
187
+ </a>
188
+ {% if level.score != None %}
189
+ <span class="score_text">{{ level.score|floatformat }}/10</span>
190
+ <img class="level_image coin_image" value="{{ level.id }}">
191
+ {% endif %}
192
+ </p>
200
193
  {% endfor %}
201
194
  {% else %}
202
- <p>No levels have been shared with you yet.</p>
195
+ <p>No levels.</p>
196
+ {% endif %}
197
+
198
+ {% if indirectly_shared_levels %}
199
+ {% for teacher, levels in indirectly_shared_levels.items %}
200
+ <h6>Owned by {{ teacher|make_into_username }}</h6>
201
+ {% for level in levels %}
202
+ <p>
203
+ <a href="{% url 'play_custom_level' level.id %}">
204
+ {{ level.title }}, {{level.owner|make_into_username}}
205
+ {% if level.class %}
206
+ ({{ level.class }})
207
+ {% endif %}
208
+ </a>
209
+ {% if level.score != None %}
210
+ <span class="score_text">{{level.score|floatformat}}/10</span>
211
+ <img class="level_image coin_image" value="{{level.id}}">
212
+ {% endif %}
213
+ </p>
214
+ {% endfor %}
215
+ {% endfor %}
203
216
  {% endif %}
204
217
  </div>
205
218
  </div>
@@ -0,0 +1,291 @@
1
+ {% extends 'game/base.html' %}
2
+
3
+ {% load static %}
4
+ {% load i18n %}
5
+ {% load app_tags %}
6
+
7
+ {% block scripts %}
8
+ {{block.super}}
9
+ <script>
10
+ var EPISODES = [];
11
+
12
+ {% for episode in pythonEpisodes %}
13
+ var levels = [];
14
+ {% for level in episode.levels %}
15
+ levels.push({
16
+ 'name': {{level.name}},
17
+ 'score': '{{level.score}}',
18
+ 'maxScore': {{level.maxScore}}
19
+ });
20
+ {% endfor %}
21
+ EPISODES.push({'id' : {{episode.id}}, 'levels': levels});
22
+ {% endfor %}
23
+ </script>
24
+
25
+ <script src="{% static 'game/js/level_selection.js' %}"></script>
26
+ {% endblock %}
27
+
28
+ {% block css %}
29
+ {{block.super}}
30
+ <link href="{% static 'game/css/level_selection.css' %}" rel="stylesheet" type="text/css">
31
+ {% endblock %}
32
+
33
+ {% block header %}
34
+ <section class="banner">
35
+ {% if user|is_logged_in_as_student or user|is_independent_student %}
36
+ <img class="banner--python-den--image" title="Python Den logo" alt="Python Den logo" src="{% static 'game/image/Python_Den_hero_student.png' %}">
37
+ {% else %}
38
+ <img class="banner--python-den--image" title="Python Den logo" alt="Python Den logo" src="{% static 'game/image/Python_levels_page.svg' %}">
39
+ {% endif %}
40
+ </section>
41
+ {% endblock header %}
42
+
43
+
44
+ {% block nav_ocargo_levels %}
45
+ {% if user|is_logged_in_as_student %}
46
+ <a class="button button--secondary button--secondary--light sub-nav--student-active">Levels</a>
47
+ {% elif user|is_independent_student %}
48
+ <a class="button button--secondary sub-nav--independent-active">Levels</a>
49
+ {% else %}
50
+ <a class="button button--secondary button--secondary--light sub-nav--teacher-active">Levels</a>
51
+ {% endif %}
52
+ {% endblock nav_ocargo_levels %}
53
+
54
+ {% block content %}
55
+ <div class="container background">
56
+ <div id="episodes">
57
+ <div class="panel-intro">
58
+ <h4>Introduction to Python</h4>
59
+ Python lessons using split-screen Blockly/Python and an online IDE for programming lessons in Python.
60
+ We have created free editable plans, presentations, and worksheets to support these lessons.
61
+ </div>
62
+ {% for episode in pythonEpisodes %}
63
+ {% if episode.difficulty != "late-python" %}
64
+ <div class="panel">
65
+ <div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
66
+ <p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
67
+ {{episode.name}}
68
+ <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes"></span>
69
+ </p>
70
+ </div>
71
+
72
+ <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
73
+ <div class="panel-body">
74
+ {% for worksheet in episode.worksheets %}
75
+ {% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
76
+ {% if not user|is_logged_in %}
77
+ <p class="text--warning">In order to access the full content for this course, please log in.</p>
78
+ {% endif %}
79
+ <div class="col-sm-10 python-den-level">
80
+ <a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
81
+ </div>
82
+ <div class="col-sm-2 python-den-level">
83
+ <a class="button button--level button--icon disabled">
84
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
85
+ </div>
86
+ {% else %}
87
+ <div class="col-sm-7 python-den-level">
88
+ <a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
89
+ </div>
90
+ {% if user|is_logged_in_as_teacher %}
91
+ <div class="col-sm-3 python-den-level">
92
+ <a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
93
+ Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
94
+ </div>
95
+ <div class="col-sm-2 python-den-level">
96
+ <a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
97
+ Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
98
+ </div>
99
+ {% elif user|is_independent_student %}
100
+ <div class="col-sm-3 python-den-level">
101
+ <a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
102
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
103
+ </div>
104
+ <div class="col-sm-2 python-den-level">
105
+ <a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
106
+ Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
107
+ </div>
108
+ {% else %}
109
+ <div class="col-sm-3"></div>
110
+ <div class="col-sm-2 python-den-level">
111
+ <a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
112
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
113
+ </div>
114
+ {% endif %}
115
+ {% endif %}
116
+ {% endfor %}
117
+ </div>
118
+ </div>
119
+ </div>
120
+ {% endif %}
121
+ {% endfor %}
122
+ <div class="panel-subintro">
123
+ This section introduces Python using a mix of Blockly split screen and text based programming.
124
+ </div>
125
+ {% for episode in pythonEpisodes %}
126
+ {% if episode.difficulty == "late-python" %}
127
+ <div class="panel">
128
+ <div class="panel-header bg--{{ episode.difficulty }}" id="episode-{{episode.id}}">
129
+ <p class="episode-title" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
130
+ {{episode.name}}
131
+ {% if episode.first_level != None and episode.last_level != None %}
132
+ {% if episode.first_level > 1009 %}
133
+ <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
134
+ Levels {{episode.first_level|stringformat:"i"|slice:"2:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}
135
+ </span>
136
+ {% else %}
137
+ {% if episode.last_level > 1009 %}
138
+ <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
139
+ Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"2:4"}}
140
+ </span>
141
+ {% else %}
142
+ <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes">
143
+ Levels {{episode.first_level|stringformat:"i"|slice:"3:4"}}-{{episode.last_level|stringformat:"i"|slice:"3:4"}}
144
+ </span>
145
+ {% endif %}
146
+ {% endif %}
147
+ {% else %}
148
+ <span class="episode_range_text collapsed" data-toggle="collapse" data-target="#collapse-{{episode.id}}" aria-expanded="false" aria-controls="collapse-{{episode.id}}" data-parent="#episodes"></span>
149
+ {% endif %}
150
+ <img class="episode_image coin_image" value="{{episode.id}}">
151
+ </p>
152
+ </div>
153
+
154
+ <div id="collapse-{{episode.id}}" aria-labelledby="episode-{{episode.id}}" class="collapse">
155
+ <div class="panel-body">
156
+ {% for level in episode.levels %}
157
+ {% for worksheet in episode.worksheets %}
158
+ {% if worksheet.before_level == level.id %}
159
+ {% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
160
+ {% if not user|is_logged_in %}
161
+ <p class="text--warning">In order to access the full content for this course, please log in.</p>
162
+ {% endif %}
163
+ <div class="col-sm-10 python-den-level">
164
+ <a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
165
+ </div>
166
+ <div class="col-sm-2 python-den-level">
167
+ <a class="button button--level button--icon disabled">
168
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
169
+ </div>
170
+ {% else %}
171
+ <div class="col-sm-7 python-den-level">
172
+ <a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
173
+ </div>
174
+ {% if user|is_logged_in_as_teacher %}
175
+ <div class="col-sm-3 python-den-level">
176
+ <a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
177
+ Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
178
+ </div>
179
+ <div class="col-sm-2 python-den-level">
180
+ <a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
181
+ Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
182
+ </div>
183
+ {% elif user|is_independent_student %}
184
+ <div class="col-sm-3 python-den-level">
185
+ <a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
186
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
187
+ </div>
188
+ <div class="col-sm-2 python-den-level">
189
+ <a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
190
+ Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
191
+ </div>
192
+ {% else %}
193
+ <div class="col-sm-3"></div>
194
+ <div class="col-sm-2 python-den-level">
195
+ <a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
196
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
197
+ </div>
198
+ {% endif %}
199
+ {% endif %}
200
+ {% endif %}
201
+ {% endfor %}
202
+ {% if user|is_logged_in_as_student and user.new_student.class_field in level.locked_for_class.all %}
203
+ <!-- Mark level as locked -->
204
+ <p>
205
+ {% if level.name > 1009 %}
206
+ <a class="disabled">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
207
+ {% else %}
208
+ <a class="disabled">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
209
+ {% endif %}
210
+ {% if level.score != None %}
211
+ <span class="score_text disabled">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
212
+ <img class="level_image coin_image" value="{{level.name}}">
213
+ {% endif %}
214
+ </p>
215
+ {% elif not user.is_authenticated and level.name > 1026 and level.name != 1041 %}
216
+ <!-- Mark level as locked -->
217
+ <p>
218
+ {% if level.name > 1009 %}
219
+ <a class="disabled">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
220
+ {% else %}
221
+ <a class="disabled">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
222
+ {% endif %}
223
+ </p>
224
+ {% else %}
225
+ <!-- Marking titles as safe to enable bold, not to be used for user-created levels -->
226
+ <p>
227
+ {% if level.name > 1009 %}
228
+ <a href="{% url 'play_python_default_level' level.name|stringformat:'i'|slice:'2:4' %}">{{level.name|stringformat:"i"|slice:"2:4"}}: {{level.title.strip | safe}}</a>
229
+ {% else %}
230
+ <a href="{% url 'play_python_default_level' level.name|stringformat:'i'|slice:'3:4' %}">{{level.name|stringformat:"i"|slice:"3:4"}}: {{level.title.strip | safe}}</a>
231
+ {% endif %}
232
+ {% if level.score != None %}
233
+ <span class="score_text">{{level.score|floatformat}}/{{level.maxScore|floatformat}}</span>
234
+ <img class="level_image coin_image" value="{{level.name}}">
235
+ {% endif %}
236
+ </p>
237
+ {% endif %}
238
+ {% endfor %}
239
+ {% for worksheet in episode.worksheets %}
240
+ {% if not worksheet.before_level %}
241
+ {% if not user|is_logged_in or user.new_student.class_field in worksheet.locked_classes.all %}
242
+ {% if not user|is_logged_in %}
243
+ <p class="text--warning">In order to access the full content for this course, please log in.</p>
244
+ {% endif %}
245
+ <div class="col-sm-10 python-den-level">
246
+ <a class="disabled">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
247
+ </div>
248
+ <div class="col-sm-2 python-den-level">
249
+ <a class="button button--level button--icon disabled">
250
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
251
+ </div>
252
+ {% else %}
253
+ <div class="col-sm-7 python-den-level">
254
+ <a href="{% url 'worksheet' worksheet.id %}">{{episode.name}}{% if episode.worksheets|length > 1 %} pt. {{ worksheet.index }}{% endif %}</a>
255
+ </div>
256
+ {% if user|is_logged_in_as_teacher %}
257
+ <div class="col-sm-3 python-den-level">
258
+ <a href="{{worksheet.lesson_plan_link}}" class="button button--level button--icon" target="_blank">
259
+ Lesson plan<span class="iconify" data-icon="mdi:open-in-new"></span></a>
260
+ </div>
261
+ <div class="col-sm-2 python-den-level">
262
+ <a href="{{worksheet.slides_link}}" class="button button--level button--icon" target="_blank">
263
+ Slides<span class="iconify" data-icon="mdi:tray-arrow-down"></span></a>
264
+ </div>
265
+ {% elif user|is_independent_student %}
266
+ <div class="col-sm-3 python-den-level">
267
+ <a href="{{worksheet.indy_worksheet_link}}" class="button button--level button--icon" target="_blank">
268
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
269
+ </div>
270
+ <div class="col-sm-2 python-den-level">
271
+ <a href="{{worksheet.video_link}}" class="button button--level button--icon" target="_blank">
272
+ Video<span class="iconify" data-icon="mdi:open-in-new"></span></a>
273
+ </div>
274
+ {% else %}
275
+ <div class="col-sm-3"></div>
276
+ <div class="col-sm-2 python-den-level">
277
+ <a href="{{worksheet.student_worksheet_link}}" class="button button--level button--icon" target="_blank">
278
+ Worksheet<span class="iconify" data-icon="mdi:open-in-new"></span></a>
279
+ </div>
280
+ {% endif %}
281
+ {% endif %}
282
+ {% endif %}
283
+ {% endfor %}
284
+ </div>
285
+ </div>
286
+ </div>
287
+ {% endif %}
288
+ {% endfor %}
289
+ </div>
290
+ </div>
291
+ {% endblock content %}