rapid-router 7.5.11__py2.py3-none-any.whl → 7.5.12__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.
- game/__init__.py +1 -1
- game/tests/test_level_editor.py +35 -0
- game/views/level_editor.py +79 -69
- {rapid_router-7.5.11.dist-info → rapid_router-7.5.12.dist-info}/METADATA +1 -1
- {rapid_router-7.5.11.dist-info → rapid_router-7.5.12.dist-info}/RECORD +8 -8
- {rapid_router-7.5.11.dist-info → rapid_router-7.5.12.dist-info}/WHEEL +0 -0
- {rapid_router-7.5.11.dist-info → rapid_router-7.5.12.dist-info}/licenses/LICENSE.md +0 -0
- {rapid_router-7.5.11.dist-info → rapid_router-7.5.12.dist-info}/top_level.txt +0 -0
game/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "7.5.
|
|
1
|
+
__version__ = "7.5.12"
|
game/tests/test_level_editor.py
CHANGED
|
@@ -488,3 +488,38 @@ class LevelEditorTestCase(TestCase):
|
|
|
488
488
|
# Teacher shouldn't see any shared levels now
|
|
489
489
|
response = self.client.get(levels_url)
|
|
490
490
|
assert len(response.context["directly_shared_levels"]) == 0
|
|
491
|
+
|
|
492
|
+
def test_level_cannot_be_created_with_invalid_fields(self):
|
|
493
|
+
email, password = signup_teacher_directly()
|
|
494
|
+
create_organisation_directly(email)
|
|
495
|
+
_, _, access_code = create_class_directly(email)
|
|
496
|
+
create_school_student_directly(access_code)
|
|
497
|
+
|
|
498
|
+
level_data = self.LEVEL_DATA1
|
|
499
|
+
level_data["subtitle"] = "<a>invalid subtitle</a>"
|
|
500
|
+
|
|
501
|
+
self.login(email, password)
|
|
502
|
+
url = reverse("save_level_for_editor")
|
|
503
|
+
response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
|
|
504
|
+
|
|
505
|
+
assert response.status_code == 401
|
|
506
|
+
|
|
507
|
+
level_data["subtitle"] = "valid subtitle"
|
|
508
|
+
level_data["lesson"] = "<a>invalid lesson</a>"
|
|
509
|
+
|
|
510
|
+
response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
|
|
511
|
+
|
|
512
|
+
assert response.status_code == 401
|
|
513
|
+
|
|
514
|
+
level_data["lesson"] = "valid lesson"
|
|
515
|
+
level_data["hint"] = "<a>invalid hint</a>"
|
|
516
|
+
|
|
517
|
+
response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
|
|
518
|
+
|
|
519
|
+
assert response.status_code == 401
|
|
520
|
+
|
|
521
|
+
level_data["hint"] = "valid hint"
|
|
522
|
+
|
|
523
|
+
response = self.client.post(url, {"data": json.dumps(self.LEVEL_DATA1)})
|
|
524
|
+
|
|
525
|
+
assert response.status_code == 200
|
game/views/level_editor.py
CHANGED
|
@@ -221,80 +221,88 @@ def save_level_for_editor(request, levelId=None):
|
|
|
221
221
|
if not permissions.can_save_level(request.user, level):
|
|
222
222
|
return HttpResponseUnauthorized()
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
name_pattern = re.compile("^(\w?[ ]?)*$")
|
|
225
|
+
fields_pattern = re.compile("^[\w.?!', ]*$")
|
|
226
|
+
|
|
227
|
+
name_is_safe = name_pattern.match(data["name"])
|
|
228
|
+
fields_are_safe = all(
|
|
229
|
+
[
|
|
230
|
+
field not in data or fields_pattern.match(data[field])
|
|
231
|
+
for field in ["subtitle", "lesson", "hint"]
|
|
232
|
+
]
|
|
233
|
+
)
|
|
225
234
|
|
|
226
|
-
if
|
|
227
|
-
|
|
235
|
+
if not (name_is_safe and fields_are_safe):
|
|
236
|
+
return HttpResponseUnauthorized()
|
|
228
237
|
|
|
229
|
-
|
|
230
|
-
hasattr(level.owner, "student")
|
|
231
|
-
and not level.owner.student.is_independent()
|
|
232
|
-
)
|
|
233
|
-
is_user_independent = (
|
|
234
|
-
hasattr(level.owner, "student") and level.owner.student.is_independent()
|
|
235
|
-
)
|
|
236
|
-
is_user_teacher = hasattr(level.owner, "teacher")
|
|
237
|
-
|
|
238
|
-
# when level is created
|
|
239
|
-
if levelId is None:
|
|
240
|
-
teacher = None
|
|
241
|
-
|
|
242
|
-
# if level owner is a school student, share with teacher automatically if they aren't an admin
|
|
243
|
-
if is_user_school_student:
|
|
244
|
-
teacher = level.owner.student.class_field.teacher
|
|
245
|
-
if not teacher.is_admin:
|
|
246
|
-
level.shared_with.add(teacher.new_user)
|
|
247
|
-
|
|
248
|
-
if not data["anonymous"]:
|
|
249
|
-
level_management.email_new_custom_level(
|
|
250
|
-
teacher.new_user.email,
|
|
251
|
-
request.build_absolute_uri(reverse("level_moderation")),
|
|
252
|
-
request.build_absolute_uri(
|
|
253
|
-
reverse("play_custom_level", kwargs={"levelId": level.id})
|
|
254
|
-
),
|
|
255
|
-
str(level.owner.student),
|
|
256
|
-
level.owner.student.class_field.name,
|
|
257
|
-
)
|
|
238
|
+
level_management.save_level(level, data)
|
|
258
239
|
|
|
259
|
-
|
|
260
|
-
|
|
240
|
+
is_user_school_student = (
|
|
241
|
+
hasattr(level.owner, "student") and not level.owner.student.is_independent()
|
|
242
|
+
)
|
|
243
|
+
is_user_independent = (
|
|
244
|
+
hasattr(level.owner, "student") and level.owner.student.is_independent()
|
|
245
|
+
)
|
|
246
|
+
is_user_teacher = hasattr(level.owner, "teacher")
|
|
261
247
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
248
|
+
# when level is created
|
|
249
|
+
if levelId is None:
|
|
250
|
+
teacher = None
|
|
265
251
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
252
|
+
# if level owner is a school student, share with teacher automatically if they aren't an admin
|
|
253
|
+
if is_user_school_student:
|
|
254
|
+
teacher = level.owner.student.class_field.teacher
|
|
255
|
+
if not teacher.is_admin:
|
|
256
|
+
level.shared_with.add(teacher.new_user)
|
|
257
|
+
|
|
258
|
+
if not data["anonymous"]:
|
|
259
|
+
level_management.email_new_custom_level(
|
|
260
|
+
teacher.new_user.email,
|
|
261
|
+
request.build_absolute_uri(reverse("level_moderation")),
|
|
262
|
+
request.build_absolute_uri(
|
|
263
|
+
reverse("play_custom_level", kwargs={"levelId": level.id})
|
|
264
|
+
),
|
|
265
|
+
str(level.owner.student),
|
|
266
|
+
level.owner.student.class_field.name,
|
|
267
|
+
)
|
|
270
268
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
for school_admin in school_admins
|
|
274
|
-
if school_admin.new_user != request.user
|
|
275
|
-
]
|
|
269
|
+
elif is_user_teacher:
|
|
270
|
+
teacher = level.owner.teacher
|
|
276
271
|
|
|
277
|
-
#
|
|
278
|
-
if is_user_school_student:
|
|
279
|
-
|
|
280
|
-
level.needs_approval = True
|
|
281
|
-
|
|
282
|
-
if not data["anonymous"]:
|
|
283
|
-
level_management.email_new_custom_level(
|
|
284
|
-
level.owner.student.class_field.teacher.new_user.email,
|
|
285
|
-
request.build_absolute_uri(reverse("level_moderation")),
|
|
286
|
-
request.build_absolute_uri(
|
|
287
|
-
reverse("play_custom_level", kwargs={"levelId": level.id})
|
|
288
|
-
),
|
|
289
|
-
str(level.owner.student),
|
|
290
|
-
level.owner.student.class_field.name,
|
|
291
|
-
)
|
|
272
|
+
# if level owner is a teacher or an indy user, approval isn't needed
|
|
273
|
+
if not is_user_school_student:
|
|
274
|
+
level.needs_approval = False
|
|
292
275
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
276
|
+
# share with all admins of the school if user is in a school
|
|
277
|
+
if not is_user_independent:
|
|
278
|
+
if not teacher.school is None:
|
|
279
|
+
school_admins = teacher.school.admins()
|
|
280
|
+
|
|
281
|
+
[
|
|
282
|
+
level.shared_with.add(school_admin.new_user)
|
|
283
|
+
for school_admin in school_admins
|
|
284
|
+
if school_admin.new_user != request.user
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
# anytime a student edits their level
|
|
288
|
+
if is_user_school_student:
|
|
289
|
+
if not level.needs_approval:
|
|
290
|
+
level.needs_approval = True
|
|
291
|
+
|
|
292
|
+
if not data["anonymous"]:
|
|
293
|
+
level_management.email_new_custom_level(
|
|
294
|
+
level.owner.student.class_field.teacher.new_user.email,
|
|
295
|
+
request.build_absolute_uri(reverse("level_moderation")),
|
|
296
|
+
request.build_absolute_uri(
|
|
297
|
+
reverse("play_custom_level", kwargs={"levelId": level.id})
|
|
298
|
+
),
|
|
299
|
+
str(level.owner.student),
|
|
300
|
+
level.owner.student.class_field.name,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
level.save()
|
|
304
|
+
response = {"id": level.id}
|
|
305
|
+
return HttpResponse(json.dumps(response), content_type="application/json")
|
|
298
306
|
|
|
299
307
|
|
|
300
308
|
@transaction.atomic
|
|
@@ -397,9 +405,11 @@ class SharingInformationForEditor(APIView):
|
|
|
397
405
|
)
|
|
398
406
|
valid_recipients["classes"].append(
|
|
399
407
|
{
|
|
400
|
-
"name":
|
|
401
|
-
|
|
402
|
-
|
|
408
|
+
"name": (
|
|
409
|
+
f"{class_.name} ({app_tags.make_into_username(class_.teacher.new_user)})"
|
|
410
|
+
if teacher.is_admin
|
|
411
|
+
else class_.name
|
|
412
|
+
),
|
|
403
413
|
"id": class_.id,
|
|
404
414
|
"students": [
|
|
405
415
|
{
|
|
@@ -3,7 +3,7 @@ example_project/rapid_router_test_settings.py,sha256=3PPkhCEztAn-WGLQ-Bf2hA5n1q_
|
|
|
3
3
|
example_project/settings.py,sha256=-Lsw_DJow_LaKaTE4DNfY69o3cclXUHNoWNybPBHIqY,4333
|
|
4
4
|
example_project/urls.py,sha256=XHug_cpNy21yOef3E1-wWT5VkTuxpl6ZXIlCj6jDjWA,422
|
|
5
5
|
example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
|
|
6
|
-
game/__init__.py,sha256=
|
|
6
|
+
game/__init__.py,sha256=pFUKWsutX3VUz-kNRAZXm5PflBdJ7dAo_wTAJT9qHdM,23
|
|
7
7
|
game/admin.py,sha256=BLwwaqQYuqmMdwqnvhdan19iGxdcoBX4CXFk_ROG5-M,1431
|
|
8
8
|
game/app_settings.py,sha256=mlg-1AiP7AR5JNOHAXXLuCrYWaZMmSihvSYk9c2c8YY,857
|
|
9
9
|
game/cache.py,sha256=dtOiFl6Z4I2Q9-8Hz24ZI-5C0asXYSQhF2Be5q74N8g,2227
|
|
@@ -774,7 +774,7 @@ game/templatetags/game/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
774
774
|
game/templatetags/game/utils.py,sha256=quMDcxpoi998hHiOH6CtoxITgpVPo4iWeINFk5AHFPU,406
|
|
775
775
|
game/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
776
776
|
game/tests/test_api.py,sha256=RI2PBnSD2dOGmCdXgH8SsoHuBSRJzUv8zBA3Hzb_ASU,5688
|
|
777
|
-
game/tests/test_level_editor.py,sha256=
|
|
777
|
+
game/tests/test_level_editor.py,sha256=ttUMFpfpJp1Vc90X15v2i6AOItvPTwnA1BeuZ3sj9m8,20767
|
|
778
778
|
game/tests/test_level_moderation.py,sha256=OcU8nx0Ih4FCR9b_tp0w4n6zWVdJ3gzftz6fa0iz67U,7057
|
|
779
779
|
game/tests/test_level_selection.py,sha256=IbrIPKDozvQ-05JAmLxHw9DsTfTwTBF2VJQPU8dn2XI,11800
|
|
780
780
|
game/tests/test_models.py,sha256=L1F5yHtVdDmVuhw7uGDBiOOTYi9rgZVIjzd248-eqLc,2592
|
|
@@ -794,14 +794,14 @@ game/views/api.py,sha256=j5Qwabpj0x9oJJ5iHhgGKeJ1RcHZgR5-eg3VGHPCyjE,8994
|
|
|
794
794
|
game/views/helper.py,sha256=SR11w5rpshwSvC7v5dDFazTrH-Vpn9gOe93OLpwrVlE,548
|
|
795
795
|
game/views/language_code_conversions.py,sha256=oaBqaPd5n1a4XmD1UWacpKrFYZ8Gk6CDII9sTrLDQDM,2590
|
|
796
796
|
game/views/level.py,sha256=8Z5ZXnspK5Bnhy8-BeVt_Evf2JSSrRklGO7Fw3W78BA,16887
|
|
797
|
-
game/views/level_editor.py,sha256=
|
|
797
|
+
game/views/level_editor.py,sha256=qJlHPs85hFCJoXrkwql37UduGs0MKxpAtwm5EpzEwi0,18227
|
|
798
798
|
game/views/level_moderation.py,sha256=GwnvXlHRxGNjgjr3pcCCmnxCHEX4UCJlsGw2VA6rncA,5303
|
|
799
799
|
game/views/level_selection.py,sha256=UI345nDv5iTRQ7VttiLKLzezJlaSlaKOnhlALZgMU9Q,9896
|
|
800
800
|
game/views/level_solutions.py,sha256=lfwLFvw4gFuptTkL2J_ibhnuiysl3Yao15sn2qoQlcE,97194
|
|
801
801
|
game/views/scoreboard.py,sha256=Lxy7XtoG7VwWpTb-c22BGC6eN8uCmmOnQ2qjY-oXA3k,16914
|
|
802
802
|
game/views/scoreboard_csv.py,sha256=yx4tOwx5QsHyU1S1BUPUqRBWIh5idq8QVtBID-NqZto,1768
|
|
803
|
-
rapid_router-7.5.
|
|
804
|
-
rapid_router-7.5.
|
|
805
|
-
rapid_router-7.5.
|
|
806
|
-
rapid_router-7.5.
|
|
807
|
-
rapid_router-7.5.
|
|
803
|
+
rapid_router-7.5.12.dist-info/licenses/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
|
|
804
|
+
rapid_router-7.5.12.dist-info/METADATA,sha256=k3d-4OlAyJnh6YOk_Z4lfUmSSKwfTzjgGMlV3KMydHQ,9209
|
|
805
|
+
rapid_router-7.5.12.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
806
|
+
rapid_router-7.5.12.dist-info/top_level.txt,sha256=rKP4ryr1t8Wcnx8grJHDViM3T5cMYH_0vygDjC04ArA,21
|
|
807
|
+
rapid_router-7.5.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|