codeforlife-portal 8.0.0__py2.py3-none-any.whl → 8.0.2__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.
Potentially problematic release.
This version of codeforlife-portal might be problematic. Click here for more details.
- cfl_common/common/models.py +20 -43
- {codeforlife_portal-8.0.0.dist-info → codeforlife_portal-8.0.2.dist-info}/METADATA +1 -1
- {codeforlife_portal-8.0.0.dist-info → codeforlife_portal-8.0.2.dist-info}/RECORD +11 -11
- {codeforlife_portal-8.0.0.dist-info → codeforlife_portal-8.0.2.dist-info}/WHEEL +1 -1
- portal/__init__.py +1 -1
- portal/forms/teach.py +57 -152
- portal/templates/portal/teach/teacher_edit_class.html +18 -8
- portal/tests/test_class.py +244 -229
- portal/views/teacher/teach.py +17 -8
- {codeforlife_portal-8.0.0.dist-info → codeforlife_portal-8.0.2.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-8.0.0.dist-info → codeforlife_portal-8.0.2.dist-info}/top_level.txt +0 -0
portal/tests/test_class.py
CHANGED
|
@@ -30,9 +30,7 @@ class TestClass(TestCase):
|
|
|
30
30
|
|
|
31
31
|
c = Client()
|
|
32
32
|
|
|
33
|
-
url = reverse(
|
|
34
|
-
"teacher_delete_class", kwargs={"access_code": access_code}
|
|
35
|
-
)
|
|
33
|
+
url = reverse("teacher_delete_class", kwargs={"access_code": access_code})
|
|
36
34
|
|
|
37
35
|
# Login as another teacher, try to delete the class and check for 404
|
|
38
36
|
c.login(username=email2, password=password2)
|
|
@@ -136,112 +134,138 @@ class TestClass(TestCase):
|
|
|
136
134
|
old_daily_activity = DailyActivity(date=old_date)
|
|
137
135
|
old_daily_activity.save()
|
|
138
136
|
|
|
139
|
-
url = reverse(
|
|
140
|
-
"teacher_edit_class", kwargs={"access_code": access_code1}
|
|
141
|
-
)
|
|
137
|
+
url = reverse("teacher_edit_class", kwargs={"access_code": access_code1})
|
|
142
138
|
# POST request data for locking only the first level
|
|
143
139
|
data = {
|
|
144
140
|
"Getting Started": [
|
|
145
|
-
"2",
|
|
146
|
-
"3",
|
|
147
|
-
"4",
|
|
148
|
-
"5",
|
|
149
|
-
"6",
|
|
150
|
-
"7",
|
|
151
|
-
"8",
|
|
152
|
-
"9",
|
|
153
|
-
"10",
|
|
154
|
-
"11",
|
|
155
|
-
"12",
|
|
141
|
+
"level:2",
|
|
142
|
+
"level:3",
|
|
143
|
+
"level:4",
|
|
144
|
+
"level:5",
|
|
145
|
+
"level:6",
|
|
146
|
+
"level:7",
|
|
147
|
+
"level:8",
|
|
148
|
+
"level:9",
|
|
149
|
+
"level:10",
|
|
150
|
+
"level:11",
|
|
151
|
+
"level:12",
|
|
152
|
+
],
|
|
153
|
+
"Shortest Route": [
|
|
154
|
+
"level:13",
|
|
155
|
+
"level:14",
|
|
156
|
+
"level:15",
|
|
157
|
+
"level:16",
|
|
158
|
+
"level:17",
|
|
159
|
+
"level:18",
|
|
156
160
|
],
|
|
157
|
-
"Shortest Route": ["13", "14", "15", "16", "17", "18"],
|
|
158
161
|
"Loops and Repetitions": [
|
|
159
|
-
"19",
|
|
160
|
-
"20",
|
|
161
|
-
"21",
|
|
162
|
-
"22",
|
|
163
|
-
"23",
|
|
164
|
-
"24",
|
|
165
|
-
"25",
|
|
166
|
-
"26",
|
|
167
|
-
"27",
|
|
168
|
-
"28",
|
|
162
|
+
"level:19",
|
|
163
|
+
"level:20",
|
|
164
|
+
"level:21",
|
|
165
|
+
"level:22",
|
|
166
|
+
"level:23",
|
|
167
|
+
"level:24",
|
|
168
|
+
"level:25",
|
|
169
|
+
"level:26",
|
|
170
|
+
"level:27",
|
|
171
|
+
"level:28",
|
|
172
|
+
],
|
|
173
|
+
"Loops with Conditions": [
|
|
174
|
+
"level:29",
|
|
175
|
+
"level:30",
|
|
176
|
+
"level:31",
|
|
177
|
+
"level:32",
|
|
169
178
|
],
|
|
170
|
-
"Loops with Conditions": ["29", "30", "31", "32"],
|
|
171
179
|
"If... Only": [
|
|
172
|
-
"33",
|
|
173
|
-
"34",
|
|
174
|
-
"35",
|
|
175
|
-
"36",
|
|
176
|
-
"37",
|
|
177
|
-
"38",
|
|
178
|
-
"39",
|
|
179
|
-
"40",
|
|
180
|
-
"41",
|
|
181
|
-
"42",
|
|
182
|
-
"43",
|
|
180
|
+
"level:33",
|
|
181
|
+
"level:34",
|
|
182
|
+
"level:35",
|
|
183
|
+
"level:36",
|
|
184
|
+
"level:37",
|
|
185
|
+
"level:38",
|
|
186
|
+
"level:39",
|
|
187
|
+
"level:40",
|
|
188
|
+
"level:41",
|
|
189
|
+
"level:42",
|
|
190
|
+
"level:43",
|
|
191
|
+
],
|
|
192
|
+
"Traffic Lights": [
|
|
193
|
+
"level:44",
|
|
194
|
+
"level:45",
|
|
195
|
+
"level:46",
|
|
196
|
+
"level:47",
|
|
197
|
+
"level:48",
|
|
198
|
+
"level:49",
|
|
199
|
+
"level:50",
|
|
183
200
|
],
|
|
184
|
-
"Traffic Lights": ["44", "45", "46", "47", "48", "49", "50"],
|
|
185
201
|
"Limited Blocks": [
|
|
186
|
-
"53",
|
|
187
|
-
"78",
|
|
188
|
-
"79",
|
|
189
|
-
"80",
|
|
190
|
-
"81",
|
|
191
|
-
"82",
|
|
192
|
-
"83",
|
|
193
|
-
"84",
|
|
194
|
-
"54",
|
|
195
|
-
"55",
|
|
202
|
+
"level:53",
|
|
203
|
+
"level:78",
|
|
204
|
+
"level:79",
|
|
205
|
+
"level:80",
|
|
206
|
+
"level:81",
|
|
207
|
+
"level:82",
|
|
208
|
+
"level:83",
|
|
209
|
+
"level:84",
|
|
210
|
+
"level:54",
|
|
211
|
+
"level:55",
|
|
212
|
+
],
|
|
213
|
+
"Procedures": [
|
|
214
|
+
# "level:85",
|
|
215
|
+
# "level:52",
|
|
216
|
+
# "level:60",
|
|
217
|
+
# "level:86",
|
|
218
|
+
# "level:62",
|
|
219
|
+
# "level:87",
|
|
220
|
+
# "level:61",
|
|
196
221
|
],
|
|
197
|
-
"Procedures": ["85", "52", "60", "86", "62", "87", "61"],
|
|
198
222
|
"Blockly Brain Teasers": [
|
|
199
|
-
"56",
|
|
200
|
-
"57",
|
|
201
|
-
"58",
|
|
202
|
-
"59",
|
|
203
|
-
"88",
|
|
204
|
-
"91",
|
|
205
|
-
"90",
|
|
206
|
-
"89",
|
|
207
|
-
"110",
|
|
208
|
-
"111",
|
|
209
|
-
"112",
|
|
210
|
-
"92",
|
|
223
|
+
"level:56",
|
|
224
|
+
"level:57",
|
|
225
|
+
"level:58",
|
|
226
|
+
"level:59",
|
|
227
|
+
"level:88",
|
|
228
|
+
"level:91",
|
|
229
|
+
"level:90",
|
|
230
|
+
"level:89",
|
|
231
|
+
"level:110",
|
|
232
|
+
"level:111",
|
|
233
|
+
"level:112",
|
|
234
|
+
"level:92",
|
|
211
235
|
],
|
|
212
236
|
"Introduction to Python": [
|
|
213
|
-
"93",
|
|
214
|
-
"63",
|
|
215
|
-
"64",
|
|
216
|
-
"65",
|
|
217
|
-
"94",
|
|
218
|
-
"66",
|
|
219
|
-
"67",
|
|
220
|
-
"68",
|
|
221
|
-
"95",
|
|
222
|
-
"69",
|
|
223
|
-
"96",
|
|
224
|
-
"97",
|
|
237
|
+
"level:93",
|
|
238
|
+
"level:63",
|
|
239
|
+
"level:64",
|
|
240
|
+
"level:65",
|
|
241
|
+
"level:94",
|
|
242
|
+
"level:66",
|
|
243
|
+
"level:67",
|
|
244
|
+
"level:68",
|
|
245
|
+
"level:95",
|
|
246
|
+
"level:69",
|
|
247
|
+
"level:96",
|
|
248
|
+
"level:97",
|
|
225
249
|
],
|
|
226
250
|
"Python": [
|
|
227
|
-
"98",
|
|
228
|
-
"70",
|
|
229
|
-
"71",
|
|
230
|
-
"73",
|
|
231
|
-
"72",
|
|
232
|
-
"99",
|
|
233
|
-
"74",
|
|
234
|
-
"75",
|
|
235
|
-
"100",
|
|
236
|
-
"101",
|
|
237
|
-
"102",
|
|
238
|
-
"103",
|
|
239
|
-
"104",
|
|
240
|
-
"105",
|
|
241
|
-
"106",
|
|
242
|
-
"107",
|
|
243
|
-
"108",
|
|
244
|
-
"109",
|
|
251
|
+
"level:98",
|
|
252
|
+
"level:70",
|
|
253
|
+
"level:71",
|
|
254
|
+
"level:73",
|
|
255
|
+
"level:72",
|
|
256
|
+
"level:99",
|
|
257
|
+
"level:74",
|
|
258
|
+
"level:75",
|
|
259
|
+
"level:100",
|
|
260
|
+
"level:101",
|
|
261
|
+
"level:102",
|
|
262
|
+
"level:103",
|
|
263
|
+
"level:104",
|
|
264
|
+
"level:105",
|
|
265
|
+
"level:106",
|
|
266
|
+
"level:107",
|
|
267
|
+
"level:108",
|
|
268
|
+
"level:109",
|
|
245
269
|
],
|
|
246
270
|
"level_control_submit": "",
|
|
247
271
|
}
|
|
@@ -261,118 +285,141 @@ class TestClass(TestCase):
|
|
|
261
285
|
assert str(messages[0]) == "Your level preferences have been saved."
|
|
262
286
|
|
|
263
287
|
# test the old analytic stays the same and the new one is incremented
|
|
264
|
-
assert (
|
|
265
|
-
|
|
266
|
-
)
|
|
267
|
-
assert (
|
|
268
|
-
DailyActivity.objects.get(date=datetime.now()).level_control_submits
|
|
269
|
-
== 1
|
|
270
|
-
)
|
|
288
|
+
assert DailyActivity.objects.get(date=old_date).level_control_submits == 0
|
|
289
|
+
assert DailyActivity.objects.get(date=datetime.now()).level_control_submits == 1
|
|
271
290
|
|
|
272
291
|
# Resubmitting to unlock level 1
|
|
273
292
|
data = {
|
|
274
293
|
"Getting Started": [
|
|
275
|
-
"1",
|
|
276
|
-
"2",
|
|
277
|
-
"3",
|
|
278
|
-
"4",
|
|
279
|
-
"5",
|
|
280
|
-
"6",
|
|
281
|
-
"7",
|
|
282
|
-
"8",
|
|
283
|
-
"9",
|
|
284
|
-
"10",
|
|
285
|
-
"11",
|
|
286
|
-
"12",
|
|
294
|
+
"level:1",
|
|
295
|
+
"level:2",
|
|
296
|
+
"level:3",
|
|
297
|
+
"level:4",
|
|
298
|
+
"level:5",
|
|
299
|
+
"level:6",
|
|
300
|
+
"level:7",
|
|
301
|
+
"level:8",
|
|
302
|
+
"level:9",
|
|
303
|
+
"level:10",
|
|
304
|
+
"level:11",
|
|
305
|
+
"level:12",
|
|
306
|
+
],
|
|
307
|
+
"Shortest Route": [
|
|
308
|
+
"level:13",
|
|
309
|
+
"level:14",
|
|
310
|
+
"level:15",
|
|
311
|
+
"level:16",
|
|
312
|
+
"level:17",
|
|
313
|
+
"level:18",
|
|
287
314
|
],
|
|
288
|
-
"Shortest Route": ["13", "14", "15", "16", "17", "18"],
|
|
289
315
|
"Loops and Repetitions": [
|
|
290
|
-
"19",
|
|
291
|
-
"20",
|
|
292
|
-
"21",
|
|
293
|
-
"22",
|
|
294
|
-
"23",
|
|
295
|
-
"24",
|
|
296
|
-
"25",
|
|
297
|
-
"26",
|
|
298
|
-
"27",
|
|
299
|
-
"28",
|
|
316
|
+
"level:19",
|
|
317
|
+
"level:20",
|
|
318
|
+
"level:21",
|
|
319
|
+
"level:22",
|
|
320
|
+
"level:23",
|
|
321
|
+
"level:24",
|
|
322
|
+
"level:25",
|
|
323
|
+
"level:26",
|
|
324
|
+
"level:27",
|
|
325
|
+
"level:28",
|
|
326
|
+
],
|
|
327
|
+
"Loops with Conditions": [
|
|
328
|
+
"level:29",
|
|
329
|
+
"level:30",
|
|
330
|
+
"level:31",
|
|
331
|
+
"level:32",
|
|
300
332
|
],
|
|
301
|
-
"Loops with Conditions": ["29", "30", "31", "32"],
|
|
302
333
|
"If... Only": [
|
|
303
|
-
"33",
|
|
304
|
-
"34",
|
|
305
|
-
"35",
|
|
306
|
-
"36",
|
|
307
|
-
"37",
|
|
308
|
-
"38",
|
|
309
|
-
"39",
|
|
310
|
-
"40",
|
|
311
|
-
"41",
|
|
312
|
-
"42",
|
|
313
|
-
"43",
|
|
334
|
+
"level:33",
|
|
335
|
+
"level:34",
|
|
336
|
+
"level:35",
|
|
337
|
+
"level:36",
|
|
338
|
+
"level:37",
|
|
339
|
+
"level:38",
|
|
340
|
+
"level:39",
|
|
341
|
+
"level:40",
|
|
342
|
+
"level:41",
|
|
343
|
+
"level:42",
|
|
344
|
+
"level:43",
|
|
345
|
+
],
|
|
346
|
+
"Traffic Lights": [
|
|
347
|
+
"level:44",
|
|
348
|
+
"level:45",
|
|
349
|
+
"level:46",
|
|
350
|
+
"level:47",
|
|
351
|
+
"level:48",
|
|
352
|
+
"level:49",
|
|
353
|
+
"level:50",
|
|
314
354
|
],
|
|
315
|
-
"Traffic Lights": ["44", "45", "46", "47", "48", "49", "50"],
|
|
316
355
|
"Limited Blocks": [
|
|
317
|
-
"53",
|
|
318
|
-
"78",
|
|
319
|
-
"79",
|
|
320
|
-
"80",
|
|
321
|
-
"81",
|
|
322
|
-
"82",
|
|
323
|
-
"83",
|
|
324
|
-
"84",
|
|
325
|
-
"54",
|
|
326
|
-
"55",
|
|
356
|
+
"level:53",
|
|
357
|
+
"level:78",
|
|
358
|
+
"level:79",
|
|
359
|
+
"level:80",
|
|
360
|
+
"level:81",
|
|
361
|
+
"level:82",
|
|
362
|
+
"level:83",
|
|
363
|
+
"level:84",
|
|
364
|
+
"level:54",
|
|
365
|
+
"level:55",
|
|
366
|
+
],
|
|
367
|
+
"Procedures": [
|
|
368
|
+
# "level:85",
|
|
369
|
+
# "level:52",
|
|
370
|
+
# "level:60",
|
|
371
|
+
# "level:86",
|
|
372
|
+
# "level:62",
|
|
373
|
+
# "level:87",
|
|
374
|
+
# "level:61",
|
|
327
375
|
],
|
|
328
|
-
"Procedures": ["85", "52", "60", "86", "62", "87", "61"],
|
|
329
376
|
"Blockly Brain Teasers": [
|
|
330
|
-
"56",
|
|
331
|
-
"57",
|
|
332
|
-
"58",
|
|
333
|
-
"59",
|
|
334
|
-
"88",
|
|
335
|
-
"91",
|
|
336
|
-
"90",
|
|
337
|
-
"89",
|
|
338
|
-
"110",
|
|
339
|
-
"111",
|
|
340
|
-
"112",
|
|
341
|
-
"92",
|
|
377
|
+
"level:56",
|
|
378
|
+
"level:57",
|
|
379
|
+
"level:58",
|
|
380
|
+
"level:59",
|
|
381
|
+
"level:88",
|
|
382
|
+
"level:91",
|
|
383
|
+
"level:90",
|
|
384
|
+
"level:89",
|
|
385
|
+
"level:110",
|
|
386
|
+
"level:111",
|
|
387
|
+
"level:112",
|
|
388
|
+
"level:92",
|
|
342
389
|
],
|
|
343
390
|
"Introduction to Python": [
|
|
344
|
-
"93",
|
|
345
|
-
"63",
|
|
346
|
-
"64",
|
|
347
|
-
"65",
|
|
348
|
-
"94",
|
|
349
|
-
"66",
|
|
350
|
-
"67",
|
|
351
|
-
"68",
|
|
352
|
-
"95",
|
|
353
|
-
"69",
|
|
354
|
-
"96",
|
|
355
|
-
"97",
|
|
391
|
+
"level:93",
|
|
392
|
+
"level:63",
|
|
393
|
+
"level:64",
|
|
394
|
+
"level:65",
|
|
395
|
+
"level:94",
|
|
396
|
+
"level:66",
|
|
397
|
+
"level:67",
|
|
398
|
+
"level:68",
|
|
399
|
+
"level:95",
|
|
400
|
+
"level:69",
|
|
401
|
+
"level:96",
|
|
402
|
+
"level:97",
|
|
356
403
|
],
|
|
357
404
|
"Python": [
|
|
358
|
-
"98",
|
|
359
|
-
"70",
|
|
360
|
-
"71",
|
|
361
|
-
"73",
|
|
362
|
-
"72",
|
|
363
|
-
"99",
|
|
364
|
-
"74",
|
|
365
|
-
"75",
|
|
366
|
-
"100",
|
|
367
|
-
"101",
|
|
368
|
-
"102",
|
|
369
|
-
"103",
|
|
370
|
-
"104",
|
|
371
|
-
"105",
|
|
372
|
-
"106",
|
|
373
|
-
"107",
|
|
374
|
-
"108",
|
|
375
|
-
"109",
|
|
405
|
+
"level:98",
|
|
406
|
+
"level:70",
|
|
407
|
+
"level:71",
|
|
408
|
+
"level:73",
|
|
409
|
+
"level:72",
|
|
410
|
+
"level:99",
|
|
411
|
+
"level:74",
|
|
412
|
+
"level:75",
|
|
413
|
+
"level:100",
|
|
414
|
+
"level:101",
|
|
415
|
+
"level:102",
|
|
416
|
+
"level:103",
|
|
417
|
+
"level:104",
|
|
418
|
+
"level:105",
|
|
419
|
+
"level:106",
|
|
420
|
+
"level:107",
|
|
421
|
+
"level:108",
|
|
422
|
+
"level:109",
|
|
376
423
|
],
|
|
377
424
|
"level_control_submit": "",
|
|
378
425
|
}
|
|
@@ -406,9 +453,7 @@ class TestClass(TestCase):
|
|
|
406
453
|
|
|
407
454
|
c = Client()
|
|
408
455
|
|
|
409
|
-
url = reverse(
|
|
410
|
-
"teacher_edit_class", kwargs={"access_code": access_code1}
|
|
411
|
-
)
|
|
456
|
+
url = reverse("teacher_edit_class", kwargs={"access_code": access_code1})
|
|
412
457
|
data = {"new_teacher": teacher2.id, "class_move_submit": ""}
|
|
413
458
|
|
|
414
459
|
# Login as first teacher and transfer class to the second teacher
|
|
@@ -435,12 +480,7 @@ class TestClassFrontend(BaseTest):
|
|
|
435
480
|
def test_create(self):
|
|
436
481
|
email, password = signup_teacher_directly()
|
|
437
482
|
create_organisation_directly(email)
|
|
438
|
-
page = (
|
|
439
|
-
self.go_to_homepage()
|
|
440
|
-
.go_to_teacher_login_page()
|
|
441
|
-
.login_no_class(email, password)
|
|
442
|
-
.open_classes_tab()
|
|
443
|
-
)
|
|
483
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login_no_class(email, password).open_classes_tab()
|
|
444
484
|
|
|
445
485
|
assert page.does_not_have_classes()
|
|
446
486
|
|
|
@@ -455,34 +495,19 @@ class TestClassFrontend(BaseTest):
|
|
|
455
495
|
join_teacher_to_organisation(email2, school.name)
|
|
456
496
|
|
|
457
497
|
# Check teacher 2 doesn't have any classes
|
|
458
|
-
page = (
|
|
459
|
-
self.go_to_homepage()
|
|
460
|
-
.go_to_teacher_login_page()
|
|
461
|
-
.login(email2, password2)
|
|
462
|
-
.open_classes_tab()
|
|
463
|
-
)
|
|
498
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login(email2, password2).open_classes_tab()
|
|
464
499
|
assert page.does_not_have_classes()
|
|
465
500
|
page.logout()
|
|
466
501
|
|
|
467
502
|
# Log in as the first teacher and create a class for the second one
|
|
468
|
-
page = (
|
|
469
|
-
self.go_to_homepage()
|
|
470
|
-
.go_to_teacher_login_page()
|
|
471
|
-
.login(email1, password1)
|
|
472
|
-
.open_classes_tab()
|
|
473
|
-
)
|
|
503
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login(email1, password1).open_classes_tab()
|
|
474
504
|
page, class_name = create_class(page, teacher_id=teacher2.id)
|
|
475
505
|
page = TeachClassPage(page.browser)
|
|
476
506
|
assert is_class_created_message_showing(self.selenium, class_name)
|
|
477
507
|
page.logout()
|
|
478
508
|
|
|
479
509
|
# Check teacher 2 now has the class
|
|
480
|
-
page = (
|
|
481
|
-
self.go_to_homepage()
|
|
482
|
-
.go_to_teacher_login_page()
|
|
483
|
-
.login(email2, password2)
|
|
484
|
-
.open_classes_tab()
|
|
485
|
-
)
|
|
510
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login(email2, password2).open_classes_tab()
|
|
486
511
|
assert page.has_classes()
|
|
487
512
|
|
|
488
513
|
def test_create_dashboard(self):
|
|
@@ -491,12 +516,7 @@ class TestClassFrontend(BaseTest):
|
|
|
491
516
|
klass, name, access_code = create_class_directly(email)
|
|
492
517
|
create_school_student_directly(access_code)
|
|
493
518
|
|
|
494
|
-
page = (
|
|
495
|
-
self.go_to_homepage()
|
|
496
|
-
.go_to_teacher_login_page()
|
|
497
|
-
.login(email, password)
|
|
498
|
-
.open_classes_tab()
|
|
499
|
-
)
|
|
519
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login(email, password).open_classes_tab()
|
|
500
520
|
|
|
501
521
|
page, class_name = create_class(page)
|
|
502
522
|
|
|
@@ -512,12 +532,7 @@ class TestClassFrontend(BaseTest):
|
|
|
512
532
|
klass_2, class_name_2, access_code_2 = create_class_directly(email_2)
|
|
513
533
|
create_school_student_directly(access_code_2)
|
|
514
534
|
|
|
515
|
-
page = (
|
|
516
|
-
self.go_to_homepage()
|
|
517
|
-
.go_to_teacher_login_page()
|
|
518
|
-
.login(email_2, password_2)
|
|
519
|
-
.open_classes_tab()
|
|
520
|
-
)
|
|
535
|
+
page = self.go_to_homepage().go_to_teacher_login_page().login(email_2, password_2).open_classes_tab()
|
|
521
536
|
|
|
522
537
|
page, class_name_3 = create_class(page)
|
|
523
538
|
|
portal/views/teacher/teach.py
CHANGED
|
@@ -33,14 +33,13 @@ from django.shortcuts import get_object_or_404, render
|
|
|
33
33
|
from django.urls import reverse, reverse_lazy
|
|
34
34
|
from django.utils import timezone
|
|
35
35
|
from django.views.decorators.http import require_POST
|
|
36
|
+
from game.models import Level
|
|
36
37
|
from game.views.level_selection import get_blockly_episodes, get_python_episodes
|
|
37
38
|
from reportlab.lib.colors import black, red
|
|
38
39
|
from reportlab.lib.pagesizes import A4
|
|
39
40
|
from reportlab.lib.utils import ImageReader
|
|
40
41
|
from reportlab.pdfgen import canvas
|
|
41
42
|
|
|
42
|
-
from game.models import Level
|
|
43
|
-
|
|
44
43
|
from portal.forms.teach import (
|
|
45
44
|
BaseTeacherDismissStudentsFormSet,
|
|
46
45
|
BaseTeacherMoveStudentsDisambiguationFormSet,
|
|
@@ -58,7 +57,6 @@ from portal.forms.teach import (
|
|
|
58
57
|
from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
|
|
59
58
|
from portal.views.registration import handle_reset_password_tracking
|
|
60
59
|
|
|
61
|
-
|
|
62
60
|
STUDENT_PASSWORD_LENGTH = 6
|
|
63
61
|
REMINDER_CARDS_PDF_ROWS = 8
|
|
64
62
|
REMINDER_CARDS_PDF_COLUMNS = 1
|
|
@@ -391,7 +389,7 @@ def process_edit_class_form(request, klass, form):
|
|
|
391
389
|
return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": klass.access_code}))
|
|
392
390
|
|
|
393
391
|
|
|
394
|
-
def process_level_control_form(request, klass, blockly_episodes, python_episodes):
|
|
392
|
+
def process_level_control_form(request, klass: Class, blockly_episodes, python_episodes):
|
|
395
393
|
"""
|
|
396
394
|
Find the levels that the user wants to lock and lock them for the specific class.
|
|
397
395
|
:param request: The request sent by the user submitting the form.
|
|
@@ -401,12 +399,16 @@ def process_level_control_form(request, klass, blockly_episodes, python_episodes
|
|
|
401
399
|
:return: A redirect to the teacher dashboard with a success message.
|
|
402
400
|
"""
|
|
403
401
|
levels_to_lock_ids = []
|
|
402
|
+
locked_worksheet_ids = []
|
|
404
403
|
|
|
405
|
-
mark_levels_to_lock_in_episodes(request, blockly_episodes, levels_to_lock_ids)
|
|
406
|
-
mark_levels_to_lock_in_episodes(request, python_episodes, levels_to_lock_ids)
|
|
404
|
+
mark_levels_to_lock_in_episodes(request, blockly_episodes, levels_to_lock_ids, locked_worksheet_ids)
|
|
405
|
+
mark_levels_to_lock_in_episodes(request, python_episodes, levels_to_lock_ids, locked_worksheet_ids)
|
|
407
406
|
|
|
408
407
|
klass.locked_levels.clear()
|
|
409
408
|
[klass.locked_levels.add(levels_to_lock_id) for levels_to_lock_id in levels_to_lock_ids]
|
|
409
|
+
klass.locked_worksheets.clear()
|
|
410
|
+
for locked_worksheet_id in locked_worksheet_ids:
|
|
411
|
+
klass.locked_worksheets.add(locked_worksheet_id)
|
|
410
412
|
|
|
411
413
|
messages.success(request, "Your level preferences have been saved.")
|
|
412
414
|
activity_today = DailyActivity.objects.get_or_create(date=datetime.now().date())[0]
|
|
@@ -416,7 +418,7 @@ def process_level_control_form(request, klass, blockly_episodes, python_episodes
|
|
|
416
418
|
return HttpResponseRedirect(reverse_lazy("dashboard"))
|
|
417
419
|
|
|
418
420
|
|
|
419
|
-
def mark_levels_to_lock_in_episodes(request, episodes, levels_to_lock_ids):
|
|
421
|
+
def mark_levels_to_lock_in_episodes(request, episodes, levels_to_lock_ids, locked_worksheet_ids: list):
|
|
420
422
|
"""
|
|
421
423
|
For a given set of Episodes, find which Levels are to be locked. This is done by checking the POST request data.
|
|
422
424
|
If a Level ID is missing from the request.POST, it means it needs to be locked, and if the entire Episode is missing
|
|
@@ -428,14 +430,21 @@ def mark_levels_to_lock_in_episodes(request, episodes, levels_to_lock_ids):
|
|
|
428
430
|
for episode in episodes:
|
|
429
431
|
episode_name = episode["name"]
|
|
430
432
|
episode_levels = episode["levels"]
|
|
433
|
+
episode_worksheets = episode["worksheets"]
|
|
431
434
|
if episode_name in request.POST:
|
|
432
435
|
[
|
|
433
436
|
levels_to_lock_ids.append(episode_level["id"])
|
|
434
437
|
for episode_level in episode_levels
|
|
435
|
-
if
|
|
438
|
+
if f'level:{episode_level["id"]}' not in request.POST.getlist(episode_name)
|
|
436
439
|
]
|
|
440
|
+
for episode_worksheet in episode_worksheets:
|
|
441
|
+
worksheet_id = episode_worksheet["id"]
|
|
442
|
+
if f"worksheet:{worksheet_id}" not in request.POST.getlist(episode_name):
|
|
443
|
+
locked_worksheet_ids.append(worksheet_id)
|
|
437
444
|
else:
|
|
438
445
|
[levels_to_lock_ids.append(episode_level["id"]) for episode_level in episode_levels]
|
|
446
|
+
for episode_worksheet in episode_worksheets:
|
|
447
|
+
locked_worksheet_ids.append(episode_worksheet["id"])
|
|
439
448
|
|
|
440
449
|
|
|
441
450
|
def process_move_class_form(request, klass, form):
|
|
File without changes
|
|
File without changes
|