rapid-router 5.18.0__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 (170) hide show
  1. example_project/rapid_router_test_settings.py +19 -7
  2. example_project/settings.py +21 -8
  3. example_project/urls.py +5 -6
  4. game/__init__.py +1 -1
  5. game/admin.py +7 -2
  6. game/character.py +8 -0
  7. game/decor.py +40 -0
  8. game/end_to_end_tests/base_game_test.py +34 -27
  9. game/end_to_end_tests/editor_page.py +15 -0
  10. game/end_to_end_tests/game_page.py +88 -20
  11. game/end_to_end_tests/selenium_test_case.py +1 -20
  12. game/end_to_end_tests/test_cow_crashes.py +3 -5
  13. game/end_to_end_tests/test_level_editor.py +273 -10
  14. game/end_to_end_tests/test_level_selection.py +25 -3
  15. game/end_to_end_tests/test_play_through.py +222 -127
  16. game/end_to_end_tests/test_python_levels.py +41 -7
  17. game/end_to_end_tests/test_saving_workspace.py +2 -1
  18. game/forms.py +7 -1
  19. game/level_management.py +26 -11
  20. game/messages.py +899 -337
  21. game/migrations/0001_squashed_0025_levels_ordering_pt1.py +19 -1
  22. game/migrations/0026_levels_pt2.py +13 -2
  23. game/migrations/0032_cannot_turn_left_level.py +13 -2
  24. game/migrations/0033_recursion_level.py +13 -2
  25. game/migrations/0034_joes_level.py +13 -2
  26. game/migrations/0035_disable_route_score_level_70.py +0 -2
  27. game/migrations/0036_level_score_73.py +0 -2
  28. game/migrations/0037_level_score_79.py +0 -2
  29. game/migrations/0038_level_score_40.py +0 -1
  30. game/migrations/0042_level_score_73.py +0 -2
  31. game/migrations/0048_add_cow_field_and_blocks.py +0 -2
  32. game/migrations/0049_level_score_34.py +0 -2
  33. game/migrations/0050_level_score_40.py +0 -2
  34. game/migrations/0051_level_score_49.py +0 -1
  35. game/migrations/0086_loop_levels.py +13 -2
  36. game/migrations/0092_disable_algo_score_in_custom_levels.py +28 -0
  37. game/migrations/0093_alter_level_character_name.py +18 -0
  38. game/migrations/0094_add_hint_lesson_subtitle_to_levels.py +28 -0
  39. game/migrations/0095_level_commands.py +18 -0
  40. game/migrations/0096_alter_level_commands.py +18 -0
  41. game/migrations/0097_add_python_den_levels.py +1515 -0
  42. game/migrations/0098_add_episode_link_fields.py +44 -0
  43. game/migrations/0099_python_episodes_links.py +103 -0
  44. game/migrations/0100_reorder_python_levels.py +179 -0
  45. game/migrations/0101_rename_episodes.py +45 -0
  46. game/migrations/0102_reoder_episodes_13_14.py +136 -0
  47. game/migrations/0103_level_1015_solution.py +26 -0
  48. game/migrations/0104_remove_level_direct_drive.py +17 -0
  49. game/migrations/0105_delete_invalid_attempts.py +18 -0
  50. game/migrations/0106_fields_to_snake_case.py +48 -0
  51. game/migrations/0107_rename_worksheet_link_episode_student_worksheet_link.py +18 -0
  52. game/migrations/0108_episode_indy_worksheet_link.py +18 -0
  53. game/migrations/0109_create_episodes_23_and_24.py +99 -0
  54. game/migrations/0110_remove_episode_indy_worksheet_link_and_more.py +100 -0
  55. game/migrations/0111_create_worksheets.py +149 -0
  56. game/migrations/0112_worksheet_locked_classes.py +21 -0
  57. game/migrations/0113_level_needs_approval.py +18 -0
  58. game/migrations/0114_default_and_non_student_levels_no_approval.py +31 -0
  59. game/migrations/0115_level_level__default_does_not_need_approval.py +22 -0
  60. game/migrations/0116_update_worksheet_video_links.py +68 -0
  61. game/migrations/0117_update_solutions_to_if_else.py +61 -0
  62. game/models.py +127 -17
  63. game/permissions.py +51 -19
  64. game/python_den_urls.py +26 -0
  65. game/random_road.py +9 -9
  66. game/serializers.py +12 -17
  67. game/static/django_reverse_js/js/reverse.js +171 -0
  68. game/static/game/css/LilitaOne-Regular.ttf +0 -0
  69. game/static/game/css/backgrounds.css +8 -12
  70. game/static/game/css/dataTables.custom.css +3 -2
  71. game/static/game/css/editor.css +47 -0
  72. game/static/game/css/game.css +37 -43
  73. game/static/game/css/game_screen.css +16 -0
  74. game/static/game/css/level_editor.css +5 -0
  75. game/static/game/css/level_selection.css +17 -2
  76. game/static/game/image/Python_Den_hero_student.png +0 -0
  77. game/static/game/image/Python_levels_page.svg +1954 -0
  78. game/static/game/image/characters/front_view/Electric_van.svg +448 -0
  79. game/static/game/image/characters/top_view/Electric_van.svg +448 -0
  80. game/static/game/image/decor/city/solar_panel.svg +1200 -0
  81. game/static/game/image/decor/farm/solar_panel.svg +86 -0
  82. game/static/game/image/decor/grass/solar_panel.svg +86 -0
  83. game/static/game/image/decor/snow/solar_panel.svg +173 -0
  84. game/static/game/image/electric_van.svg +448 -0
  85. game/static/game/image/icons/description.svg +1 -0
  86. game/static/game/image/icons/hint.svg +1 -0
  87. game/static/game/image/icons/python.svg +1 -1
  88. game/static/game/image/pigeon.svg +684 -0
  89. game/static/game/image/python_den_header.svg +19 -0
  90. game/static/game/js/animation.js +65 -24
  91. game/static/game/js/blockly/msg/js/bg.js +52 -1
  92. game/static/game/js/blockly/msg/js/ca.js +52 -1
  93. game/static/game/js/blockly/msg/js/en-gb.js +2 -0
  94. game/static/game/js/blockly/msg/js/en.js +2 -0
  95. game/static/game/js/blockly/msg/js/es.js +52 -1
  96. game/static/game/js/blockly/msg/js/fr.js +2 -0
  97. game/static/game/js/blockly/msg/js/hi.js +2 -0
  98. game/static/game/js/blockly/msg/js/it.js +52 -1
  99. game/static/game/js/blockly/msg/js/pl.js +52 -1
  100. game/static/game/js/blockly/msg/js/pt-br.js +52 -1
  101. game/static/game/js/blockly/msg/js/ru.js +52 -1
  102. game/static/game/js/blockly/msg/js/ur.js +52 -1
  103. game/static/game/js/blocklyCustomBlocks.js +93 -52
  104. game/static/game/js/button.js +12 -0
  105. game/static/game/js/cow.js +11 -7
  106. game/static/game/js/drawing.js +68 -29
  107. game/static/game/js/editor.js +23 -0
  108. game/static/game/js/game.js +74 -110
  109. game/static/game/js/level_editor.js +646 -274
  110. game/static/game/js/level_moderation.js +33 -2
  111. game/static/game/js/level_selection.js +1 -1
  112. game/static/game/js/loadLanguages.js +2 -2
  113. game/static/game/js/model.js +32 -2
  114. game/static/game/js/pythonControl.js +14 -1
  115. game/static/game/js/scoreboard.js +0 -37
  116. game/static/game/js/scoreboardSharedLevels.js +48 -0
  117. game/static/game/js/skulpt/skulpt-stdlib.js +1 -1
  118. game/static/game/js/sound.js +52 -5
  119. game/static/game/raphael_image/characters/top_view/Electric_van.svg +448 -0
  120. game/static/game/raphael_image/decor/city/solar_panel.svg +1200 -0
  121. game/static/game/raphael_image/decor/farm/solar_panel.svg +86 -0
  122. game/static/game/raphael_image/decor/grass/solar_panel.svg +86 -0
  123. game/static/game/raphael_image/decor/snow/solar_panel.svg +173 -0
  124. game/static/game/raphael_image/pigeon.svg +685 -0
  125. game/static/game/sass/game.scss +2 -2
  126. game/static/game/sound/clown_horn.mp3 +0 -0
  127. game/static/game/sound/clown_horn.ogg +0 -0
  128. game/static/game/sound/electric_van_starting.mp3 +0 -0
  129. game/static/game/sound/electric_van_starting.ogg +0 -0
  130. game/static/game/sound/pigeon.mp3 +0 -0
  131. game/static/game/sound/pigeon.ogg +0 -0
  132. game/static/game/sound/sleigh_bells.mp3 +0 -0
  133. game/static/game/sound/sleigh_bells.ogg +0 -0
  134. game/static/game/sound/sleigh_crash.mp3 +0 -0
  135. game/static/game/sound/sleigh_crash.ogg +0 -0
  136. game/templates/game/base.html +34 -14
  137. game/templates/game/basenonav.html +11 -5
  138. game/templates/game/game.html +142 -38
  139. game/templates/game/level_editor.html +340 -236
  140. game/templates/game/level_moderation.html +19 -6
  141. game/templates/game/level_selection.html +18 -110
  142. game/templates/game/python_den_level_selection.html +291 -0
  143. game/templates/game/python_den_worksheet.html +101 -0
  144. game/templates/game/scoreboard.html +83 -64
  145. game/tests/test_level_editor.py +94 -26
  146. game/tests/test_level_selection.py +149 -46
  147. game/tests/test_python_den_worksheet.py +85 -0
  148. game/tests/test_scoreboard.py +34 -7
  149. game/tests/utils/level.py +32 -26
  150. game/theme.py +5 -5
  151. game/urls.py +199 -61
  152. game/views/language_code_conversions.py +86 -86
  153. game/views/level.py +155 -63
  154. game/views/level_editor.py +88 -55
  155. game/views/level_moderation.py +23 -0
  156. game/views/level_selection.py +116 -47
  157. game/views/level_solutions.py +491 -106
  158. game/views/scoreboard.py +76 -51
  159. game/views/worksheet.py +25 -0
  160. rapid_router-7.6.8.dist-info/METADATA +174 -0
  161. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/RECORD +164 -104
  162. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/WHEEL +1 -1
  163. example_project/manage.py +0 -10
  164. game/static/game/image/actions/go.svg +0 -18
  165. game/static/game/js/js-reverse.js +0 -14
  166. game/static/game/js/pqselect.min.js +0 -9
  167. game/static/game/js/widget-scroller.js +0 -906
  168. rapid_router-5.18.0.dist-info/METADATA +0 -17
  169. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info/licenses}/LICENSE.md +0 -0
  170. {rapid_router-5.18.0.dist-info → rapid_router-7.6.8.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ import pytest
2
+
1
3
  from .base_game_test import BaseGameTest
2
4
 
3
5
 
@@ -5,13 +7,19 @@ class TestPlayThrough(BaseGameTest):
5
7
  def setUp(self):
6
8
  self.login_once()
7
9
 
8
- def _complete_episode(self, episode_number, level_number, **kwargs):
10
+ def _complete_episode(
11
+ self, episode_number, level_number, from_python_den=False, **kwargs
12
+ ):
9
13
  page = self.go_to_episode(episode_number)
10
- self.complete_and_check_level(level_number, page, **kwargs)
14
+ self.complete_and_check_level(
15
+ level_number, page, from_python_den, **kwargs
16
+ )
11
17
 
12
- def _complete_level(self, level_number, **kwargs):
13
- page = self.go_to_level(level_number)
14
- self.complete_and_check_level(level_number, page, **kwargs)
18
+ def _complete_level(self, level_number, from_python_den=False, **kwargs):
19
+ page = self.go_to_level(level_number, from_python_den)
20
+ self.complete_and_check_level(
21
+ level_number, page, from_python_den, **kwargs
22
+ )
15
23
 
16
24
  def test_episode_01(self):
17
25
  self._complete_episode(1, 1, check_algorithm_score=False)
@@ -275,143 +283,230 @@ class TestPlayThrough(BaseGameTest):
275
283
  self._complete_level(78, check_route_score=False)
276
284
 
277
285
  def test_level_079(self):
278
- self._complete_level(79)
279
-
280
- def test_episode_10(self):
281
- self._complete_episode(10, 80)
282
-
283
- def test_level_080(self):
284
- self._complete_level(80)
285
-
286
- def test_level_081(self):
287
- self._complete_level(81)
288
-
289
- def test_level_082(self):
290
- self._complete_level(82)
291
-
292
- def test_level_083(self):
293
- self._complete_level(83)
294
-
295
- def test_level_084(self):
296
- self._complete_level(84)
297
-
298
- def test_level_085(self):
299
- self._complete_level(85)
300
-
301
- def test_level_086(self):
302
- self._complete_level(86)
303
-
304
- def test_level_087(self):
305
- self._complete_level(87)
306
-
307
- def test_level_088(self):
308
- self._complete_level(88)
309
-
310
- def test_level_089(self):
311
- self._complete_level(89)
312
-
313
- def test_level_090(self):
314
- self._complete_level(90)
315
-
316
- def test_level_091(self):
317
- self._complete_level(91)
318
-
319
- def test_episode_11(self):
320
- self._complete_episode(11, 92, check_algorithm_score=False)
321
-
322
- def test_level_092(self):
323
- self._complete_level(92, check_algorithm_score=False)
286
+ self._complete_level(79, final_level=True)
324
287
 
325
- def test_level_093(self):
326
- self._complete_level(93, check_algorithm_score=False)
327
-
328
- def test_level_094(self):
329
- self._complete_level(94, check_algorithm_score=False)
330
-
331
- def test_level_095(self):
332
- self._complete_level(95, check_algorithm_score=False)
333
-
334
- def test_level_096(self):
335
- self._complete_level(96, check_algorithm_score=False)
336
-
337
- def test_level_097(self):
338
- self._complete_level(97, check_algorithm_score=False)
339
-
340
- def test_level_098(self):
341
- self._complete_level(98, check_algorithm_score=False)
342
-
343
- def test_level_099(self):
344
- self._complete_level(99, check_algorithm_score=False)
345
-
346
- def test_level_100(self):
347
- self._complete_level(100, check_algorithm_score=False)
348
-
349
- def test_level_101(self):
350
- self._complete_level(101, check_algorithm_score=False)
351
-
352
- def test_level_102(self):
353
- self._complete_level(102, check_algorithm_score=False)
354
-
355
- def test_level_103(self):
356
- self._complete_level(103, check_algorithm_score=False)
357
-
358
- def test_level_104(self):
359
- self._complete_level(104, check_algorithm_score=False)
360
-
361
- def test_level_105(self):
362
- self._complete_level(105, check_algorithm_score=False)
363
-
364
- def test_level_106(self):
365
- self._complete_level(106, check_algorithm_score=False)
366
-
367
- def test_level_107(self):
368
- self._complete_level(107, check_algorithm_score=False)
288
+ def test_episode_12(self):
289
+ self._complete_episode(
290
+ 12, 1, check_algorithm_score=False, from_python_den=True
291
+ )
292
+
293
+ def test_python_level_001(self):
294
+ self._complete_level(1, from_python_den=True)
369
295
 
370
- def test_level_108(self):
371
- self._complete_level(108, check_algorithm_score=False)
296
+ def test_python_level_002(self):
297
+ self._complete_level(2, from_python_den=True)
372
298
 
373
- def test_level_109(self):
374
- self._complete_level(109, check_algorithm_score=False)
299
+ def test_python_level_003(self):
300
+ self._complete_level(3, from_python_den=True)
375
301
 
376
- def test_episode_12(self):
377
- self._complete_episode(12, 110, check_algorithm_score=False)
302
+ def test_python_level_004(self):
303
+ self._complete_level(
304
+ 4, check_algorithm_score=False, from_python_den=True
305
+ )
378
306
 
379
- def test_level_110(self):
380
- self._complete_level(110, check_algorithm_score=False)
307
+ def test_python_level_005(self):
308
+ self._complete_level(
309
+ 5, check_algorithm_score=False, from_python_den=True
310
+ )
381
311
 
382
- def test_level_111(self):
383
- self._complete_level(111, check_algorithm_score=False)
312
+ def test_python_level_006(self):
313
+ self._complete_level(
314
+ 6, check_algorithm_score=False, from_python_den=True
315
+ )
384
316
 
385
- def test_level_112(self):
386
- self._complete_level(112)
317
+ def test_python_level_007(self):
318
+ self._complete_level(7, from_python_den=True)
387
319
 
388
- def test_level_113(self):
389
- self._complete_level(113, check_algorithm_score=False)
320
+ def test_python_level_008(self):
321
+ self._complete_level(8, from_python_den=True)
390
322
 
391
- def test_level_114(self):
392
- self._complete_level(114, check_algorithm_score=False)
323
+ def test_python_level_009(self):
324
+ self._complete_level(9, from_python_den=True)
393
325
 
394
- def test_level_115(self):
395
- self._complete_level(115, check_algorithm_score=False)
326
+ def test_python_level_010(self):
327
+ self._complete_level(
328
+ 10, check_algorithm_score=False, from_python_den=True
329
+ )
396
330
 
397
- def test_level_116(self):
398
- self._complete_level(116)
331
+ def test_python_level_011(self):
332
+ self._complete_level(
333
+ 11, check_algorithm_score=False, from_python_den=True
334
+ )
399
335
 
400
- def test_level_117(self):
401
- self._complete_level(117)
336
+ def test_python_level_012(self):
337
+ self._complete_level(
338
+ 12, check_algorithm_score=False, from_python_den=True
339
+ )
402
340
 
403
- def test_level_118(self):
404
- self._complete_level(118)
341
+ def test_python_level_013(self):
342
+ self._complete_level(
343
+ 13, check_algorithm_score=False, from_python_den=True
344
+ )
405
345
 
406
- def test_level_119(self):
407
- self._complete_level(119, check_algorithm_score=False)
346
+ def test_episode_13(self):
347
+ self._complete_episode(13, 14, from_python_den=True)
408
348
 
409
- def test_level_120(self):
410
- self._complete_level(120, check_algorithm_score=False)
349
+ def test_python_level_014(self):
350
+ self._complete_level(14, from_python_den=True)
411
351
 
412
- def test_level_121(self):
413
- self._complete_level(121, check_algorithm_score=False)
352
+ def test_python_level_015(self):
353
+ self._complete_level(15, from_python_den=True)
414
354
 
415
- def test_level_122(self):
416
- self._complete_level(122, check_algorithm_score=False, final_level=True)
355
+ def test_python_level_016(self):
356
+ self._complete_level(
357
+ 16, check_algorithm_score=False, from_python_den=True
358
+ )
417
359
 
360
+ def test_python_level_017(self):
361
+ self._complete_level(
362
+ 17, check_algorithm_score=False, from_python_den=True
363
+ )
364
+
365
+ def test_python_level_018(self):
366
+ self._complete_level(
367
+ 18, check_algorithm_score=False, from_python_den=True
368
+ )
369
+
370
+ def test_python_level_019(self):
371
+ self._complete_level(19, from_python_den=True)
372
+
373
+ def test_python_level_020(self):
374
+ self._complete_level(
375
+ 20, check_algorithm_score=False, from_python_den=True
376
+ )
377
+
378
+ def test_python_level_021(self):
379
+ self._complete_level(
380
+ 21, check_algorithm_score=False, from_python_den=True
381
+ )
382
+
383
+ def test_python_level_022(self):
384
+ self._complete_level(22, from_python_den=True)
385
+
386
+ def test_python_level_023(self):
387
+ self._complete_level(23, from_python_den=True)
388
+
389
+ def test_python_level_024(self):
390
+ self._complete_level(
391
+ 24, check_algorithm_score=False, from_python_den=True
392
+ )
393
+
394
+ def test_python_level_025(self):
395
+ self._complete_level(
396
+ 25, check_algorithm_score=False, from_python_den=True
397
+ )
398
+
399
+ def test_episode_14(self):
400
+ self._complete_episode(14, 26, from_python_den=True)
401
+
402
+ def test_python_level_026(self):
403
+ self._complete_level(26, from_python_den=True)
404
+
405
+ def test_python_level_027(self):
406
+ self._complete_level(27, from_python_den=True)
407
+
408
+ def test_python_level_028(self):
409
+ self._complete_level(28, from_python_den=True)
410
+
411
+ def test_python_level_029(self):
412
+ self._complete_level(29, from_python_den=True)
413
+
414
+ def test_python_level_030(self):
415
+ self._complete_level(
416
+ 30, check_algorithm_score=False, from_python_den=True
417
+ )
418
+
419
+ def test_python_level_031(self):
420
+ self._complete_level(31, from_python_den=True)
421
+
422
+ def test_python_level_032(self):
423
+ self._complete_level(32, from_python_den=True)
424
+
425
+ def test_python_level_033(self):
426
+ self._complete_level(
427
+ 33, check_algorithm_score=False, from_python_den=True
428
+ )
429
+
430
+ def test_python_level_034(self):
431
+ self._complete_level(
432
+ 34, check_algorithm_score=False, from_python_den=True
433
+ )
434
+
435
+ def test_python_level_035(self):
436
+ self._complete_level(35, from_python_den=True)
437
+
438
+ def test_python_level_036(self):
439
+ self._complete_level(36, from_python_den=True)
440
+
441
+ def test_python_level_037(self):
442
+ self._complete_level(
443
+ 37, check_algorithm_score=False, from_python_den=True
444
+ )
445
+
446
+ @pytest.mark.skip(reason="this level's solution is currently flawed")
447
+ def test_python_level_038(self):
448
+ self._complete_level(
449
+ 38, check_algorithm_score=False, from_python_den=True
450
+ )
451
+
452
+ def test_python_level_039(self):
453
+ self._complete_level(
454
+ 39, check_algorithm_score=False, from_python_den=True
455
+ )
456
+
457
+ def test_python_level_040(self):
458
+ self._complete_level(
459
+ 40,
460
+ check_algorithm_score=False,
461
+ from_python_den=True,
462
+ redirects=True,
463
+ )
464
+
465
+ def test_episode_15(self):
466
+ self._complete_episode(
467
+ 15, 41, check_algorithm_score=False, from_python_den=True
468
+ )
469
+
470
+ def test_python_level_041(self):
471
+ self._complete_level(41, from_python_den=True)
472
+
473
+ def test_python_level_042(self):
474
+ self._complete_level(
475
+ 42, check_algorithm_score=False, from_python_den=True
476
+ )
477
+
478
+ def test_python_level_043(self):
479
+ self._complete_level(
480
+ 43, check_algorithm_score=False, from_python_den=True
481
+ )
482
+
483
+ def test_python_level_044(self):
484
+ self._complete_level(44, from_python_den=True)
485
+
486
+ def test_python_level_045(self):
487
+ self._complete_level(
488
+ 45, check_algorithm_score=False, from_python_den=True
489
+ )
490
+
491
+ def test_python_level_046(self):
492
+ self._complete_level(
493
+ 46, check_algorithm_score=False, from_python_den=True
494
+ )
495
+
496
+ def test_python_level_047(self):
497
+ self._complete_level(
498
+ 47, check_algorithm_score=False, from_python_den=True
499
+ )
500
+
501
+ def test_python_level_048(self):
502
+ self._complete_level(
503
+ 48, check_algorithm_score=False, from_python_den=True
504
+ )
505
+
506
+ def test_python_level_049(self):
507
+ self._complete_level(
508
+ 49,
509
+ check_algorithm_score=False,
510
+ from_python_den=True,
511
+ final_level=True,
512
+ )
@@ -2,34 +2,68 @@ from selenium.webdriver.common.by import By
2
2
  from selenium.webdriver.support import expected_conditions as EC
3
3
  from selenium.webdriver.support.ui import WebDriverWait
4
4
 
5
+ from game.character import get_character
5
6
  from game.end_to_end_tests.base_game_test import BaseGameTest
7
+ from game.models import Level
8
+ from game.theme import get_theme
6
9
 
7
10
  DELAY_TIME = 10
8
11
 
9
12
 
10
13
  class TestPythonLevels(BaseGameTest):
11
14
  def test_can_see_python_commands(self):
12
- self.run_python_commands_test(level=92)
15
+ self.go_to_level(4, from_python_den=True).check_python_commands()
13
16
 
14
17
  def test_clear_console(self):
15
- self.run_clear_console_test(level=92)
18
+ self.go_to_level(4, from_python_den=True).write_to_then_clear_console()
16
19
 
17
20
  def test_console_parse_error(self):
18
- self.run_console_parse_error_test(level=92)
21
+ self.go_to_level(4, from_python_den=True).run_parse_error_program()
19
22
 
20
23
  def test_console_attribute_error(self):
21
- self.run_console_attribute_error_test(level=92)
24
+ self.go_to_level(4, from_python_den=True).run_attribute_error_program()
22
25
 
23
26
  def test_console_print(self):
24
- self.run_console_print_test(level=92)
27
+ self.go_to_level(4, from_python_den=True).run_print_program()
25
28
 
26
29
  def test_invalid_import(self):
27
- self.run_invalid_import_test(level=109)
30
+ self.go_to_level(5, from_python_den=True).run_invalid_import_program()
28
31
 
29
32
  def test_run_code(self):
30
- self.go_to_level(92)
33
+ self.go_to_level(4, from_python_den=True)
31
34
  run_code = self.selenium.find_element(By.ID, "run-code-button")
32
35
  run_code.click()
33
36
  assert WebDriverWait(self.selenium, DELAY_TIME).until(
34
37
  EC.presence_of_all_elements_located((By.ID, "myModal-lead"))
35
38
  )
39
+
40
+ def test_animal_sound_horn(self):
41
+ grass = get_theme(name="grass")
42
+
43
+ van = get_character("Van")
44
+
45
+ animal_level = Level(
46
+ name="Animal commands",
47
+ anonymous=False,
48
+ blockly_enabled=False,
49
+ character=van,
50
+ cows='[{"minCows":1,"maxCows":1,"potentialCoordinates":[{"x":3,"y":4}],"type":"WHITE"}]',
51
+ default=False,
52
+ destinations="[[4,4]]",
53
+ fuel_gauge=False,
54
+ max_fuel=50,
55
+ model_solution="",
56
+ origin='{"coordinate":[2,4],"direction":"E"}',
57
+ path='[{"coordinate":[2,4],"connectedNodes":[1]},{"coordinate":[3,4],"connectedNodes":[0,2]},{"coordinate":[4,4],"connectedNodes":[1]}]',
58
+ python_enabled=True,
59
+ theme=grass,
60
+ threads=1,
61
+ traffic_lights="[]",
62
+ disable_algorithm_score=True,
63
+ )
64
+
65
+ user_profile = self.login_once()
66
+ animal_level.owner = user_profile
67
+ animal_level.save()
68
+
69
+ self.run_animal_sound_horn_test(animal_level).assert_success()
@@ -12,7 +12,8 @@ class TestSavingWorkspace(BaseGameTest):
12
12
  self.login_once()
13
13
  level = 10
14
14
  random_save_entry_name = "".join(
15
- random.choice(string.ascii_uppercase + string.digits) for _ in range(10)
15
+ random.choice(string.ascii_uppercase + string.digits)
16
+ for _ in range(10)
16
17
  )
17
18
  return (
18
19
  self.go_to_level(level)
game/forms.py CHANGED
@@ -9,18 +9,24 @@ from .models import Episode
9
9
  class ScoreboardForm(forms.Form):
10
10
  def __init__(self, *args, **kwargs):
11
11
  classes = kwargs.pop("classes")
12
+ language = kwargs.pop("language")
12
13
  super(ScoreboardForm, self).__init__(*args, **kwargs)
13
14
  classes_choices = [(c.id, c.name) for c in classes]
14
15
 
15
16
  self.fields["classes"] = forms.MultipleChoiceField(
16
17
  choices=classes_choices, widget=forms.CheckboxSelectMultiple()
17
18
  )
19
+
20
+ episodes_range = (
21
+ range(1, 10) if language == "blockly" else range(12, 16)
22
+ )
23
+
18
24
  # Each tuple in choices has two elements, id and name of each level
19
25
  # First element is the actual value set on the model
20
26
  # Second element is the string displayed on the dropdown menu
21
27
  episodes_choices = (
22
28
  (episode.id, episode.name)
23
- for episode in Episode.objects.filter(in_development=False)
29
+ for episode in Episode.objects.filter(pk__in=episodes_range)
24
30
  )
25
31
  self.fields["episodes"] = forms.MultipleChoiceField(
26
32
  choices=itertools.chain(episodes_choices),
game/level_management.py CHANGED
@@ -35,8 +35,12 @@ def levels_shared_with(user):
35
35
  return []
36
36
 
37
37
  shared_levels = user.shared
38
+ shared_levels = add_related_fields(shared_levels)
38
39
 
39
- return add_related_fields(shared_levels)
40
+ if hasattr(user.userprofile, "student"):
41
+ shared_levels = shared_levels.filter(needs_approval=False)
42
+
43
+ return shared_levels
40
44
 
41
45
 
42
46
  def levels_owned_by(user):
@@ -52,13 +56,13 @@ def get_decor(level):
52
56
  """Helper method parsing decor into a dictionary format 'sendable' to javascript."""
53
57
  decorData = []
54
58
  for ld in LevelDecor.objects.filter(level=level):
55
- decor = get_decor_element(name=ld.decorName, theme=level.theme)
59
+ decor = get_decor_element(name=ld.decor_name, theme=level.theme)
56
60
  decorData.append(
57
61
  {
58
62
  "x": int(ld.x),
59
63
  "y": int(ld.y),
60
64
  "z": int(decor.z_index),
61
- "decorName": str(ld.decorName),
65
+ "decorName": str(ld.decor_name),
62
66
  "width": int(decor.width),
63
67
  "height": int(decor.height),
64
68
  "url": str(decor.url),
@@ -81,7 +85,10 @@ def set_decor_inner(level, decor, LevelDecor):
81
85
  for data in decor:
82
86
  level_decors.append(
83
87
  LevelDecor(
84
- level_id=level.id, x=data["x"], y=data["y"], decorName=data["decorName"]
88
+ level_id=level.id,
89
+ x=data["x"],
90
+ y=data["y"],
91
+ decor_name=data["decorName"],
85
92
  )
86
93
  )
87
94
  LevelDecor.objects.bulk_create(level_decors)
@@ -160,11 +167,19 @@ def save_level(level, data):
160
167
  level.max_fuel = data["max_fuel"]
161
168
  level.traffic_lights = data["traffic_lights"]
162
169
  level.cows = data["cows"]
163
- level.blocklyEnabled = data.get("blocklyEnabled", True)
164
- level.pythonEnabled = data.get("pythonEnabled", False)
165
- level.pythonViewEnabled = data.get("pythonViewEnabled", False)
170
+ level.blockly_enabled = data.get("blockly_enabled", True)
171
+ level.python_enabled = data.get("python_enabled", False)
172
+ level.python_view_enabled = data.get("python_view_enabled", False)
166
173
  level.theme = get_theme_by_pk(pk=data["theme"])
167
174
  level.character = get_character_by_pk(pk=data["character"])
175
+ level.disable_algorithm_score = data.get("disable_algorithm_score", False)
176
+ if data.get("subtitle") != None:
177
+ level.subtitle = data.get("subtitle")
178
+ if data.get("lesson") != None:
179
+ level.lesson = data.get("lesson")
180
+ if data.get("hint") != None:
181
+ level.hint = data.get("hint")
182
+
168
183
  level.save()
169
184
 
170
185
  set_decor(level, data["decor"])
@@ -184,9 +199,9 @@ def unshare_level(level, *users):
184
199
 
185
200
 
186
201
  def email_new_custom_level(
187
- teacher_email, moderate_url, level_url, home_url, student_name, class_name
202
+ teacher_email, moderate_url, level_url, student_name, class_name
188
203
  ):
189
- # email teacher when a new custom level is created by a pupil, so it can be moderated ASAP
204
+ # email teacher when a new custom level is created by a pupil, so it can be moderated
190
205
 
191
206
  send_dotdigital_email(
192
207
  campaign_ids["level_creation"],
@@ -195,6 +210,6 @@ def email_new_custom_level(
195
210
  "STUDENT_NAME": student_name,
196
211
  "CLASS_NAME": class_name,
197
212
  "LEVEL_URL": level_url,
198
- "MODERATE_URL": moderate_url
199
- }
213
+ "MODERATE_URL": moderate_url,
214
+ },
200
215
  )