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
@@ -1,8 +1,37 @@
1
+ from selenium.webdriver.common.action_chains import ActionChains
2
+ from selenium.webdriver.common.by import By
3
+ from selenium.webdriver.support import expected_conditions as EC
4
+ from selenium.webdriver.support.ui import Select, WebDriverWait
5
+
1
6
  from game.end_to_end_tests.base_game_test import BaseGameTest
2
7
  from game.views.level_editor import available_blocks
3
8
 
9
+ DELAY_TIME = 10
10
+
4
11
 
5
12
  class TestLevelEditor(BaseGameTest):
13
+ def set_up_basic_map(self):
14
+ self.test_level_editor_displays()
15
+
16
+ add_road_button = self.selenium.find_element(By.ID, "add_road")
17
+ add_road_button.click()
18
+
19
+ road_start = self.selenium.find_element(
20
+ By.CSS_SELECTOR, "rect[x='130'][y='530']"
21
+ )
22
+ road_end = self.selenium.find_element(By.CSS_SELECTOR, "rect[x='330'][y='530']")
23
+ ActionChains(self.selenium).drag_and_drop(road_start, road_end).perform()
24
+
25
+ mark_start_button = self.selenium.find_element(By.ID, "start")
26
+ mark_start_button.click()
27
+ ActionChains(self.selenium).move_to_element(road_start).click().perform()
28
+
29
+ add_house_button = self.selenium.find_element(By.ID, "add_house")
30
+ add_house_button.click()
31
+ ActionChains(self.selenium).move_to_element(road_end).click().perform()
32
+
33
+ return [road_start, road_end]
34
+
6
35
  def test_level_editor_displays(self):
7
36
  page = self.go_to_level_editor()
8
37
 
@@ -17,3 +46,264 @@ class TestLevelEditor(BaseGameTest):
17
46
  for block_type in block_types:
18
47
  assert page.element_exists_by_id(f"{block_type}_checkbox")
19
48
  assert page.element_exists_by_id(f"{block_type}_image")
49
+
50
+ def test_multiple_houses(self):
51
+ [road_start, road_end] = self.set_up_basic_map()
52
+
53
+ road_middle = self.selenium.find_element(
54
+ By.CSS_SELECTOR, "rect[x='230'][y='530']"
55
+ )
56
+
57
+ add_house_button = self.selenium.find_element(By.ID, "add_house")
58
+ add_house_button.click()
59
+ ActionChains(self.selenium).move_to_element(road_middle).click().perform()
60
+
61
+ added_houses = self.selenium.find_elements(
62
+ By.CSS_SELECTOR, "rect[fill='#0000ff']"
63
+ )
64
+ assert len(added_houses) == 2
65
+
66
+ delete_house_button = self.selenium.find_element(By.ID, "delete_house")
67
+ delete_house_button.click()
68
+ ActionChains(self.selenium).move_to_element(road_middle).click().perform()
69
+ ActionChains(self.selenium).move_to_element(road_start).perform()
70
+
71
+ houses_after_delete = self.selenium.find_elements(
72
+ By.CSS_SELECTOR, "rect[fill='#0000ff']"
73
+ )
74
+ assert len(houses_after_delete) == 1
75
+
76
+ def test_cow_on_origin(self):
77
+ page = self.go_to_level_editor()
78
+ [road_start, road_end] = self.set_up_basic_map()
79
+
80
+ origin_space = self.selenium.find_elements(
81
+ By.CSS_SELECTOR, "rect[fill='#ff0000']"
82
+ )
83
+ assert len(origin_space) == 1
84
+
85
+ page.go_to_scenery_tab()
86
+
87
+ draggable_cow = self.selenium.find_element(By.ID, "cow")
88
+ ActionChains(self.selenium).click_and_hold(draggable_cow).move_to_element(
89
+ road_start
90
+ ).perform()
91
+ start_space_warning = self.selenium.find_elements(
92
+ By.CSS_SELECTOR,
93
+ "rect[fill='#e35f4d'][fill-opacity='0.7'][x='130'][y='530']",
94
+ )
95
+ assert len(start_space_warning) == 1
96
+
97
+ def test_cow_on_house(self):
98
+ page = self.go_to_level_editor()
99
+ [road_start, road_end] = self.set_up_basic_map()
100
+
101
+ house_space = self.selenium.find_elements(
102
+ By.CSS_SELECTOR, "rect[fill='#0000ff']"
103
+ )
104
+ assert len(house_space) == 1
105
+ assert road_end == house_space[0]
106
+
107
+ page.go_to_scenery_tab()
108
+
109
+ draggable_cow = self.selenium.find_elements(By.ID, "cow")
110
+ assert len(draggable_cow) == 1
111
+ ActionChains(self.selenium).click_and_hold(draggable_cow[0]).move_to_element(
112
+ road_end
113
+ ).perform()
114
+ allowed_space = self.selenium.find_elements(
115
+ By.CSS_SELECTOR, "rect[fill='#87e34d']"
116
+ )
117
+ assert len(allowed_space) == 0
118
+
119
+ def test_draggable_decor(self):
120
+ page = self.go_to_level_editor()
121
+ page.go_to_scenery_tab()
122
+
123
+ source_tree = self.selenium.find_element(By.ID, "tree2")
124
+ end_space = self.selenium.find_element(
125
+ By.CSS_SELECTOR, "rect[x='130'][y='530']"
126
+ )
127
+ ActionChains(self.selenium).drag_and_drop(source_tree, end_space).perform()
128
+
129
+ decor_tree = self.selenium.find_elements(By.CSS_SELECTOR, "image[x='0'][y='0']")
130
+ cloned_source_tree = self.selenium.find_elements(By.ID, "tree2")
131
+ assert len(decor_tree) == 1
132
+ assert len(cloned_source_tree) == 1
133
+
134
+ def test_draggable_cow(self):
135
+ page = self.go_to_level_editor()
136
+ page.go_to_scenery_tab()
137
+
138
+ source_cow = self.selenium.find_element(By.ID, "cow")
139
+ end_space = self.selenium.find_element(
140
+ By.CSS_SELECTOR, "rect[x='130'][y='530']"
141
+ )
142
+ ActionChains(self.selenium).drag_and_drop(source_cow, end_space).perform()
143
+
144
+ scenery_cow = self.selenium.find_elements(
145
+ By.CSS_SELECTOR, "image[x='0'][y='0']"
146
+ )
147
+ cloned_source_cow = self.selenium.find_elements(By.ID, "cow")
148
+ assert len(scenery_cow) == 1
149
+ assert len(cloned_source_cow) == 1
150
+
151
+ def test_draggable_traffic_light(self):
152
+ page = self.go_to_level_editor()
153
+ page.go_to_scenery_tab()
154
+
155
+ source_light = self.selenium.find_element(By.ID, "trafficLightRed")
156
+ end_space = self.selenium.find_element(
157
+ By.CSS_SELECTOR, "rect[x='130'][y='530']"
158
+ )
159
+ ActionChains(self.selenium).drag_and_drop(source_light, end_space).perform()
160
+
161
+ scenery_light = self.selenium.find_elements(
162
+ By.CSS_SELECTOR, "image[x='0'][y='0']"
163
+ )
164
+ cloned_source_light = self.selenium.find_elements(By.ID, "trafficLightRed")
165
+ assert len(scenery_light) == 1
166
+ assert len(cloned_source_light) == 1
167
+
168
+ def test_custom_description_and_hint(self):
169
+ # login
170
+ self.login_once()
171
+
172
+ # go to level editor and set up basic map
173
+ page = self.go_to_level_editor()
174
+ [road_start, road_end] = self.set_up_basic_map()
175
+
176
+ # fill in custom description and hint fields
177
+ page.go_to_description_tab()
178
+ self.selenium.find_element(By.ID, "subtitle").send_keys("test subtitle")
179
+ self.selenium.find_element(By.ID, "description").send_keys("test description")
180
+
181
+ page.go_to_hint_tab()
182
+ self.selenium.find_element(By.ID, "hint").send_keys("test hint")
183
+
184
+ # save level and choose to play it
185
+ page.go_to_save_tab()
186
+ self.selenium.find_element(By.ID, "levelNameInput").send_keys("test level")
187
+ self.selenium.find_element(By.ID, "saveLevel").click()
188
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
189
+ EC.presence_of_element_located((By.ID, "play_button"))
190
+ )
191
+ self.selenium.find_element(By.ID, "play_button").click()
192
+
193
+ # check to see if custom subtitle and lesson appear on the initial popup
194
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
195
+ EC.presence_of_element_located((By.ID, "myModal-lead"))
196
+ )
197
+ modal_text = self.selenium.find_element(By.ID, "myModal-lead").get_attribute(
198
+ "innerHTML"
199
+ )
200
+ assert "test subtitle" in modal_text
201
+ assert "test description" in modal_text
202
+ self.selenium.find_element(By.ID, "close-modal").click()
203
+
204
+ # wait for modal to disappear
205
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
206
+ EC.none_of(
207
+ EC.visibility_of_all_elements_located((By.ID, "myModal-mainText"))
208
+ )
209
+ )
210
+
211
+ # check to see if the custom hint appears on failure modal
212
+ fast_tab = self.selenium.find_element(By.ID, "fast_tab")
213
+ fast_tab.click()
214
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
215
+ EC.visibility_of_element_located((By.ID, "hintPopupBtn"))
216
+ )
217
+ hint_button = self.selenium.find_element(By.ID, "hintPopupBtn")
218
+ hint_button.click()
219
+
220
+ hint_modal_text = self.selenium.find_element(By.ID, "hintText").get_attribute(
221
+ "innerHTML"
222
+ )
223
+ hint_modal_style = self.selenium.find_element(By.ID, "hintText").get_attribute(
224
+ "style"
225
+ )
226
+ assert "display: none" in hint_button.get_attribute("style")
227
+ assert "display: block" in hint_modal_style
228
+ assert "test hint" in hint_modal_text
229
+
230
+ self.selenium.find_element(By.ID, "try_again_button").click()
231
+
232
+ # check to see if the custom hint appears on the hint popup
233
+ self.selenium.find_element(By.ID, "help_tab").click()
234
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
235
+ EC.visibility_of_element_located((By.ID, "myModal-mainText"))
236
+ )
237
+ hint_modal_text_two = self.selenium.find_element(
238
+ By.ID, "myModal-mainText"
239
+ ).get_attribute("innerHTML")
240
+ assert "test hint" in hint_modal_text_two
241
+
242
+ def test_solar_panels(self):
243
+ """test that the solar panels appear as a scenery option when clicking on the scenery tab
244
+ """
245
+ page = self.go_to_level_editor()
246
+ page.go_to_scenery_tab()
247
+
248
+ solar_panel = self.selenium.find_element(
249
+ By.ID, "solar_panel"
250
+ )
251
+ assert solar_panel.is_displayed()
252
+
253
+ def test_electric_fuel_gauge(self):
254
+ self.login_once()
255
+
256
+ page = self.go_to_level_editor()
257
+
258
+ [road_start, road_end] = self.set_up_basic_map()
259
+ page.go_to_character_tab()
260
+
261
+ # the electric van has dropdown value 7 - select the electric van as character
262
+ Select(self.selenium.find_element(By.ID, "character_select")).select_by_value(
263
+ "7"
264
+ )
265
+
266
+ # save level and choose to play it
267
+ page.go_to_save_tab()
268
+ self.selenium.find_element(By.ID, "levelNameInput").send_keys(
269
+ "test electric van level"
270
+ )
271
+ self.selenium.find_element(By.ID, "saveLevel").click()
272
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
273
+ EC.visibility_of_element_located((By.ID, "myModal-lead"))
274
+ )
275
+ self.selenium.find_element(By.ID, "play_button").click()
276
+
277
+ # check to see if electric fuel gauge appears
278
+ assert WebDriverWait(self.selenium, DELAY_TIME).until(
279
+ EC.presence_of_element_located((By.ID, "electricFuelGauge"))
280
+ )
281
+ electric_fuel_gauge = self.selenium.find_element(By.ID, "electricFuelGauge")
282
+ assert "visibility: visible" in electric_fuel_gauge.get_attribute("style")
283
+
284
+ def test_pigeon(self):
285
+ """Test that cows on the map automatically become pigeons when the theme is changed to "city" """
286
+ page = self.go_to_level_editor()
287
+ page.go_to_scenery_tab()
288
+
289
+ source_cow = self.selenium.find_element(By.ID, "cow")
290
+ end_space = self.selenium.find_element(
291
+ By.CSS_SELECTOR, "rect[x='130'][y='530']"
292
+ )
293
+ ActionChains(self.selenium).drag_and_drop(source_cow, end_space).perform()
294
+
295
+ scenery_cow = self.selenium.find_elements(
296
+ By.CSS_SELECTOR, "image[x='0'][y='0']"
297
+ )
298
+ cow_link = scenery_cow[0].get_attribute("href")
299
+ assert cow_link == "/static/game/raphael_image/Clarice.svg"
300
+
301
+ Select(self.selenium.find_element(By.ID, "theme_select")).select_by_value(
302
+ "city"
303
+ )
304
+
305
+ scenery_pigeon = self.selenium.find_elements(
306
+ By.CSS_SELECTOR, "image[x='0'][y='0']"
307
+ )
308
+ pigeon_link = scenery_pigeon[0].get_attribute("href")
309
+ assert pigeon_link == "/static/game/raphael_image/pigeon.svg"
@@ -75,4 +75,4 @@ class TestCrashes(BaseGameTest):
75
75
  .clear()
76
76
  )
77
77
 
78
- self.complete_and_check_level(6, page)
78
+ self.complete_and_check_level(6, page, check_algorithm_score=False)
@@ -0,0 +1,79 @@
1
+ import pytest
2
+ from common.tests.utils.classes import create_class_directly
3
+ from common.tests.utils.organisation import create_organisation_directly
4
+ from common.tests.utils.student import create_school_student_directly
5
+ from common.tests.utils.teacher import signup_teacher_directly
6
+ from hamcrest import assert_that, ends_with, equal_to
7
+ from selenium.common.exceptions import NoSuchElementException
8
+ from selenium.webdriver.common.by import By
9
+
10
+ from game.end_to_end_tests.base_game_test import BaseGameTest
11
+ from game.models import Attempt, Episode
12
+
13
+
14
+ class TestLevelSelection(BaseGameTest):
15
+ def test_coins(self):
16
+
17
+ # Set up student
18
+ email, password = signup_teacher_directly()
19
+ create_organisation_directly(email)
20
+ klass, name, access_code = create_class_directly(email)
21
+ name, password, student = create_school_student_directly(access_code)
22
+
23
+ # Student has perfect score for each level in an episode
24
+ episode = Episode.objects.get(name="Loops with Conditions")
25
+ for a_level in episode.levels:
26
+ attempt = Attempt(student=student, score=20.0, level=a_level)
27
+ attempt.save()
28
+
29
+ # Student logs in
30
+ code_page = self.go_to_homepage().go_to_student_login_page()
31
+ student_login_page = code_page.student_input_access_code(access_code)
32
+ page = student_login_page.student_login(name, password)
33
+
34
+ # Goes to rapid router levels
35
+ page = self.go_to_reverse("levels")
36
+
37
+ # The coin images for the levels
38
+ level_coin_images = page.browser.find_elements(
39
+ By.CSS_SELECTOR, ("#collapse-4 div img")
40
+ )
41
+ # There are 4 levels in this episode, each with gold coin
42
+ assert_that(len(level_coin_images), equal_to(4))
43
+
44
+ for image in level_coin_images:
45
+ assert_that(
46
+ image.get_attribute("src"),
47
+ ends_with("/static/game/image/coins/coin_gold.svg"),
48
+ )
49
+
50
+ # So the episode has a gold coin too
51
+ episode_coin_image = page.browser.find_element(
52
+ By.CSS_SELECTOR, "#episode-4 > p > img"
53
+ )
54
+ assert_that(
55
+ episode_coin_image.get_attribute("src"),
56
+ ends_with("/static/game/image/coins/coin_gold.svg"),
57
+ )
58
+
59
+ try:
60
+ image_for_uncomplete_episode = page.browser.find_element(
61
+ By.CSS_SELECTOR, "#episode-3 > p > img"
62
+ )
63
+ except NoSuchElementException as this_should_happen:
64
+ pass
65
+
66
+ @pytest.mark.skip(reason="levelless episode no longer opens up after clicking next level, need to investigate")
67
+ def test_redirect_to_levelless_episode(self):
68
+ levels_page = self.go_to_reverse("python_levels")
69
+ expected_url = levels_page.browser.current_url
70
+
71
+ page = self.go_to_level_without_dismissing_dialog(26, True)
72
+ self.selenium.find_element(By.ID, "next_button").click()
73
+
74
+ current_url = page.browser.current_url
75
+ assert current_url == expected_url
76
+
77
+ episode_20_header = self.selenium.find_element(By.ID, "collapse-20")
78
+ episode_20_expanded = episode_20_header.get_attribute("class")
79
+ assert episode_20_expanded == "collapse"