codeforlife-portal 6.46.1__py2.py3-none-any.whl → 7.1.0__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.

Files changed (69) hide show
  1. cfl_common/common/csp_config.py +0 -2
  2. cfl_common/common/mail.py +31 -6
  3. cfl_common/common/migrations/0005_add_worksheets.py +1 -5
  4. cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +1 -5
  5. cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
  6. cfl_common/common/models.py +0 -25
  7. {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/METADATA +3 -4
  8. {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/RECORD +44 -68
  9. example_project/portal_test_settings.py +0 -1
  10. example_project/settings.py +0 -1
  11. example_project/urls.py +0 -2
  12. portal/__init__.py +1 -1
  13. portal/static/portal/sass/partials/_banners.scss +0 -177
  14. portal/static/portal/sass/partials/_buttons.scss +0 -12
  15. portal/static/portal/sass/partials/_grids.scss +0 -53
  16. portal/static/portal/sass/partials/_text.scss +1 -10
  17. portal/static/portal/sass/styles.scss +0 -1
  18. portal/strings/play.py +1 -2
  19. portal/strings/teacher_resources.py +0 -10
  20. portal/templates/portal/about.html +91 -60
  21. portal/templates/portal/contribute.html +45 -49
  22. portal/templates/portal/partials/header.html +0 -12
  23. portal/templates/portal/play/independent_student_dashboard.html +12 -25
  24. portal/templates/portal/play/student_dashboard.html +16 -34
  25. portal/templates/portal/play.html +36 -49
  26. portal/templates/portal/register.html +1 -1
  27. portal/templates/portal/teach.html +37 -55
  28. portal/templates/portal/ten_year_map.html +9 -9
  29. portal/templatetags/app_tags.py +13 -28
  30. portal/tests/conftest.py +4 -16
  31. portal/tests/pageObjects/portal/base_page.py +20 -20
  32. portal/tests/snapshots/snap_test_partials.py +0 -452
  33. portal/tests/test_class.py +213 -45
  34. portal/tests/test_independent_student.py +0 -9
  35. portal/tests/test_partials.py +6 -56
  36. portal/tests/test_teacher.py +221 -285
  37. portal/tests/test_views.py +257 -73
  38. portal/urls.py +38 -20
  39. portal/views/cron/user.py +158 -15
  40. portal/views/student/play.py +36 -25
  41. portal/views/teacher/teach.py +0 -5
  42. cfl_common/common/tests/test_migration_aimmo_characters.py +0 -29
  43. portal/forms/add_game.py +0 -29
  44. portal/static/portal/img/kurono_hero.jpg +0 -0
  45. portal/static/portal/img/kurono_landing_hero.png +0 -0
  46. portal/static/portal/img/kurono_logo.svg +0 -1
  47. portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
  48. portal/static/portal/img/kurono_logo_mark.svg +0 -1
  49. portal/static/portal/img/kurono_resources_hero.jpg +0 -0
  50. portal/static/portal/img/kurono_story.png +0 -0
  51. portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
  52. portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
  53. portal/static/portal/img/thumbnail_play_kurono.png +0 -0
  54. portal/static/portal/js/aimmoGame.js +0 -106
  55. portal/static/portal/sass/partials/_videos.scss +0 -10
  56. portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
  57. portal/strings/student_aimmo_dashboard.py +0 -6
  58. portal/templates/portal/partials/aimmo_games_table.html +0 -89
  59. portal/templates/portal/play/student_aimmo_dashboard.html +0 -46
  60. portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
  61. portal/templatetags/character_list_tags.py +0 -16
  62. portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
  63. portal/tests/test_aimmo_dashboards.py +0 -206
  64. portal/tests/utils/aimmo_games.py +0 -30
  65. portal/views/aimmo/__init__.py +0 -0
  66. portal/views/aimmo/dashboard.py +0 -105
  67. {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/LICENSE.md +0 -0
  68. {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/WHEEL +0 -0
  69. {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/top_level.txt +0 -0
@@ -6,9 +6,7 @@ from unittest.mock import ANY, Mock, patch
6
6
  from uuid import uuid4
7
7
 
8
8
  import jwt
9
- from aimmo.models import Game
10
9
  from common.mail import campaign_ids
11
- from common.models import Class, Student, Teacher
12
10
  from common.tests.utils import email as email_utils
13
11
  from common.tests.utils.classes import create_class_directly
14
12
  from common.tests.utils.organisation import (
@@ -50,229 +48,6 @@ from .utils.messages import (
50
48
 
51
49
 
52
50
  class TestTeacher(TestCase):
53
- def test_new_student_can_play_games(self):
54
- """
55
- Given a teacher has a kurono game,
56
- When they add a new student to their class,
57
- Then the new student should be able to play that class's games
58
- """
59
- email, password = signup_teacher_directly()
60
- create_organisation_directly(email)
61
- klass, _, access_code = create_class_directly(email)
62
- create_school_student_directly(access_code)
63
-
64
- c = Client()
65
- c.login(username=email, password=password)
66
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass.id})
67
- c.post(reverse("view_class", kwargs={"access_code": access_code}), {"names": "Florian"})
68
-
69
- game = Game.objects.get(id=1)
70
- new_student = Student.objects.last()
71
- assert game.can_user_play(new_student.new_user)
72
-
73
- def test_accepted_independent_student_can_play_games(self):
74
- """
75
- Given an independent student requests access to a class,
76
- When the teacher for that class accepts the request,
77
- Then the new student should have access to that class's games
78
- """
79
- email, password = signup_teacher_directly()
80
- create_organisation_directly(email)
81
- klass, _, access_code = create_class_directly(email)
82
- klass.always_accept_requests = True
83
- klass.save()
84
- create_school_student_directly(access_code)
85
- indep_username, indep_password, indep_student = create_independent_student_directly()
86
-
87
- c = Client()
88
-
89
- c.login(username=indep_username, password=indep_password)
90
- c.post(reverse("student_join_organisation"), {"access_code": access_code, "class_join_request": "Request"})
91
- c.logout()
92
-
93
- c.login(username=email, password=password)
94
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass.pk})
95
- c.post(reverse("teacher_accept_student_request", kwargs={"pk": indep_student.pk}), {"name": "Florian"})
96
-
97
- game: Game = Game.objects.get(id=1)
98
- new_student = Student.objects.last()
99
- assert game.can_user_play(new_student.new_user)
100
-
101
- def test_moved_class_has_correct_permissions_for_students_and_teachers(self):
102
- """
103
- Given two teachers each with a class and an aimmo game,
104
- When teacher 1 transfers their class to teacher 2,
105
- Then:
106
- - Students in each class still only have access to their class games
107
- - Teacher 2 has access to both games and teacher 1 has access to none
108
- """
109
-
110
- # Create teacher 1 -> class 1 -> student 1
111
- email1, password1 = signup_teacher_directly()
112
- school = create_organisation_directly(email1)
113
- klass1, _, access_code1 = create_class_directly(email1, "Class 1")
114
- create_school_student_directly(access_code1)
115
-
116
- # Create teacher 2 -> class 2 -> student 2
117
- email2, password2 = signup_teacher_directly()
118
- join_teacher_to_organisation(email2, school.name)
119
- klass2, _, access_code2 = create_class_directly(email2, "Class 2")
120
- create_school_student_directly(access_code2)
121
-
122
- teacher2: Teacher = Teacher.objects.get(new_user__email=email2)
123
- # make teacher1 non admin to remove extra permissions
124
- teacher1: Teacher = Teacher.objects.get(new_user__email=email1)
125
- teacher1.is_admin = False
126
- teacher1.save()
127
-
128
- c = Client()
129
-
130
- # Create game 1 under class 1
131
- c.login(username=email1, password=password1)
132
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass1.pk})
133
- c.logout()
134
-
135
- # Create game 2 under class 2
136
- c.login(username=email2, password=password2)
137
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass2.pk})
138
- c.logout()
139
-
140
- game1: Game = Game.objects.get(owner=teacher1.new_user)
141
- game2: Game = Game.objects.get(owner=teacher2.new_user)
142
-
143
- student1: Student = Student.objects.get(class_field=klass1)
144
- student2: Student = Student.objects.get(class_field=klass2)
145
-
146
- # Check student permissions for each game
147
- assert game1.can_user_play(student1.new_user)
148
- assert game2.can_user_play(student2.new_user)
149
- assert not game1.can_user_play(student2.new_user)
150
- assert not game2.can_user_play(student1.new_user)
151
-
152
- # Check teacher permissions for each game
153
- assert game1.can_user_play(teacher1.new_user)
154
- assert game2.can_user_play(teacher2.new_user)
155
- assert not game1.can_user_play(teacher2.new_user)
156
- assert not game2.can_user_play(teacher1.new_user)
157
-
158
- # Transfer class 1 over to teacher 2
159
- c.login(username=email1, password=password1)
160
- response = c.post(
161
- reverse("teacher_edit_class", kwargs={"access_code": access_code1}),
162
- {"new_teacher": teacher2.pk, "class_move_submit": ""},
163
- )
164
- assert response.status_code == 302
165
- c.logout()
166
-
167
- # Refresh model instances
168
- klass1: Class = Class.objects.get(pk=klass1.pk)
169
- game1 = Game.objects.get(pk=game1.pk)
170
- game2 = Game.objects.get(pk=game2.pk)
171
-
172
- # Check teacher 2 is the teacher for class 1
173
- assert klass1.teacher == teacher2
174
-
175
- # Check that the students' permissions have not changed
176
- assert game1.can_user_play(student1.new_user)
177
- assert game2.can_user_play(student2.new_user)
178
- assert not game1.can_user_play(student2.new_user)
179
- assert not game2.can_user_play(student1.new_user)
180
-
181
- # Check that teacher 1 cannot access class 1's game 1 anymore
182
- assert not game1.can_user_play(teacher1.new_user)
183
-
184
- # Check that teacher 2 can access game 1
185
- assert game1.can_user_play(teacher2.new_user)
186
-
187
- def test_moved_student_has_access_to_only_new_teacher_games(self):
188
- """
189
- Given a student in a class,
190
- When a teacher transfers them to another class with a new teacher,
191
- Then the student should only have access to the new teacher's games
192
- """
193
-
194
- email1, password1 = signup_teacher_directly()
195
- school = create_organisation_directly(email1)
196
- klass1, _, access_code1 = create_class_directly(email1, "Class 1")
197
- create_school_student_directly(access_code1)
198
-
199
- email2, password2 = signup_teacher_directly()
200
- join_teacher_to_organisation(email2, school.name)
201
- klass2, _, access_code2 = create_class_directly(email2, "Class 2")
202
- create_school_student_directly(access_code2)
203
-
204
- teacher1 = Teacher.objects.get(new_user__email=email1)
205
- teacher2 = Teacher.objects.get(new_user__email=email2)
206
-
207
- c = Client()
208
- c.login(username=email2, password=password2)
209
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass2.pk})
210
- c.logout()
211
-
212
- c.login(username=email1, password=password1)
213
- c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass1.pk})
214
-
215
- game1 = Game.objects.get(owner=teacher1.new_user)
216
- game2 = Game.objects.get(owner=teacher2.new_user)
217
-
218
- student1 = Student.objects.get(class_field=klass1)
219
- student2 = Student.objects.get(class_field=klass2)
220
-
221
- assert game1.can_user_play(student1.new_user)
222
- assert game2.can_user_play(student2.new_user)
223
-
224
- c.post(
225
- reverse("teacher_move_students", kwargs={"access_code": access_code1}), {"transfer_students": student1.pk}
226
- )
227
- c.post(
228
- reverse("teacher_move_students_to_class", kwargs={"access_code": access_code1}),
229
- {
230
- "form-0-name": student1.user.user.first_name,
231
- "form-MAX_NUM_FORMS": 1000,
232
- "form-0-orig_name": student1.user.user.first_name,
233
- "form-TOTAL_FORMS": 1,
234
- "form-MIN_NUM_FORMS": 0,
235
- "submit_disambiguation": "",
236
- "form-INITIAL_FORMS": 1,
237
- "new_class": klass2.pk,
238
- },
239
- )
240
- c.logout()
241
-
242
- game1 = Game.objects.get(owner=teacher1.new_user)
243
- game2 = Game.objects.get(owner=teacher2.new_user)
244
-
245
- assert not game1.can_user_play(student1.new_user)
246
- assert game2.can_user_play(student1.new_user)
247
-
248
- def test_teacher_cannot_create_duplicate_game(self):
249
- """
250
- Given a teacher, a class and a worksheet,
251
- When the teacher creates a game for that class and worksheet, and then tries to
252
- create the exact same game again,
253
- Then the class should only have one game, and an error message should appear.
254
- """
255
-
256
- email, password = signup_teacher_directly()
257
- create_organisation_directly(email)
258
- klass, _, _ = create_class_directly(email)
259
-
260
- c = Client()
261
- c.login(username=email, password=password)
262
- game1_response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass.pk})
263
-
264
- assert game1_response.status_code == 302
265
- assert Game.objects.filter(game_class=klass, is_archived=False).count() == 1
266
- assert klass.active_game is not None
267
- messages = list(game1_response.wsgi_request._messages)
268
- assert len([m for m in messages if m.tags == "warning"]) == 0
269
-
270
- game2_response = c.post(reverse("teacher_aimmo_dashboard"), {"game_class": klass.pk})
271
-
272
- messages = list(game2_response.wsgi_request._messages)
273
- assert len([m for m in messages if m.tags == "warning"]) == 1
274
- assert messages[0].message == "An active game already exists for this class"
275
-
276
51
  def test_signup_short_password_fails(self):
277
52
  c = Client()
278
53
 
@@ -404,7 +179,9 @@ class TestTeacher(TestCase):
404
179
  assert bad_verification_response.status_code == 200
405
180
 
406
181
  # Get verification link from function call
407
- verification_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["VERIFICATION_LINK"]
182
+ verification_url = mock_send_dotdigital_email.call_args.kwargs[
183
+ "personalization_values"
184
+ ]["VERIFICATION_LINK"]
408
185
 
409
186
  # Verify the email properly
410
187
  verification_response = c.get(verification_url)
@@ -424,7 +201,14 @@ class TestTeacherFrontend(BaseTest):
424
201
  def test_password_too_common(self):
425
202
  self.selenium.get(self.live_server_url)
426
203
  page = HomePage(self.selenium).go_to_signup_page()
427
- page = page.signup("first_name", "last_name", "e@ma.il", "Password123$", "Password123$", success=False)
204
+ page = page.signup(
205
+ "first_name",
206
+ "last_name",
207
+ "e@ma.il",
208
+ "Password123$",
209
+ "Password123$",
210
+ success=False,
211
+ )
428
212
  try:
429
213
  submit_button = WebDriverWait(self.selenium, 10).until(
430
214
  EC.element_to_be_clickable((By.NAME, "teacher_signup"))
@@ -432,7 +216,8 @@ class TestTeacherFrontend(BaseTest):
432
216
  submit_button.click()
433
217
  except:
434
218
  assert page.was_form_invalid(
435
- "form-reg-teacher", "Password is too common, consider using a different password."
219
+ "form-reg-teacher",
220
+ "Password is too common, consider using a different password.",
436
221
  )
437
222
 
438
223
  def test_signup_without_newsletter(self):
@@ -467,8 +252,12 @@ class TestTeacherFrontend(BaseTest):
467
252
  self.selenium.get(self.live_server_url)
468
253
  page = HomePage(self.selenium)
469
254
  page = page.go_to_teacher_login_page()
470
- page = page.login_failure("non-existent-email@codeforlife.com", "Incorrect password")
471
- assert page.has_login_failed("form-login-teacher", INVALID_LOGIN_MESSAGE)
255
+ page = page.login_failure(
256
+ "non-existent-email@codeforlife.com", "Incorrect password"
257
+ )
258
+ assert page.has_login_failed(
259
+ "form-login-teacher", INVALID_LOGIN_MESSAGE
260
+ )
472
261
 
473
262
  def test_login_success(self):
474
263
  email, password = signup_teacher_directly()
@@ -492,9 +281,13 @@ class TestTeacherFrontend(BaseTest):
492
281
  page = page.go_to_teacher_login_page()
493
282
  page = page.login_failure(email, password)
494
283
 
495
- assert page.has_login_failed("form-login-teacher", INVALID_LOGIN_MESSAGE)
284
+ assert page.has_login_failed(
285
+ "form-login-teacher", INVALID_LOGIN_MESSAGE
286
+ )
496
287
 
497
- verification_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["VERIFICATION_LINK"]
288
+ verification_url = mock_send_dotdigital_email.call_args.kwargs[
289
+ "personalization_values"
290
+ ]["VERIFICATION_LINK"]
498
291
 
499
292
  verify_email(page, verification_url)
500
293
 
@@ -518,15 +311,26 @@ class TestTeacherFrontend(BaseTest):
518
311
  create_school_student_directly(access_code)
519
312
 
520
313
  self.selenium.get(self.live_server_url)
521
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password).open_account_tab()
314
+ page = (
315
+ HomePage(self.selenium)
316
+ .go_to_teacher_login_page()
317
+ .login(email, password)
318
+ .open_account_tab()
319
+ )
522
320
 
523
321
  page = page.change_teacher_details(
524
- {"first_name": "Paulina", "last_name": "Koch", "current_password": "$RFVBGT%6yhn"}
322
+ {
323
+ "first_name": "Paulina",
324
+ "last_name": "Koch",
325
+ "current_password": "$RFVBGT%6yhn",
326
+ }
525
327
  )
526
328
  assert self.is_dashboard_page(page)
527
329
  assert is_teacher_details_updated_message_showing(self.selenium)
528
330
 
529
- assert page.check_account_details({"first_name": "Paulina", "last_name": "Koch"})
331
+ assert page.check_account_details(
332
+ {"first_name": "Paulina", "last_name": "Koch"}
333
+ )
530
334
 
531
335
  def test_edit_details_non_admin(self):
532
336
  email_1, _ = signup_teacher_directly()
@@ -539,15 +343,26 @@ class TestTeacherFrontend(BaseTest):
539
343
  create_school_student_directly(access_code_2)
540
344
 
541
345
  self.selenium.get(self.live_server_url)
542
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email_2, password_2).open_account_tab()
346
+ page = (
347
+ HomePage(self.selenium)
348
+ .go_to_teacher_login_page()
349
+ .login(email_2, password_2)
350
+ .open_account_tab()
351
+ )
543
352
 
544
353
  page = page.change_teacher_details(
545
- {"first_name": "Florian", "last_name": "Aucomte", "current_password": password_2}
354
+ {
355
+ "first_name": "Florian",
356
+ "last_name": "Aucomte",
357
+ "current_password": password_2,
358
+ }
546
359
  )
547
360
  assert self.is_dashboard_page(page)
548
361
  assert is_teacher_details_updated_message_showing(self.selenium)
549
362
 
550
- assert page.check_account_details({"first_name": "Florian", "last_name": "Aucomte"})
363
+ assert page.check_account_details(
364
+ {"first_name": "Florian", "last_name": "Aucomte"}
365
+ )
551
366
 
552
367
  @patch("common.helpers.emails.send_dotdigital_email")
553
368
  def test_change_email(self, mock_send_dotdigital_email):
@@ -559,7 +374,11 @@ class TestTeacherFrontend(BaseTest):
559
374
  other_email, _ = signup_teacher_directly()
560
375
 
561
376
  page = self.go_to_homepage()
562
- page = page.go_to_teacher_login_page().login(email, password).open_account_tab()
377
+ page = (
378
+ page.go_to_teacher_login_page()
379
+ .login(email, password)
380
+ .open_account_tab()
381
+ )
563
382
 
564
383
  # Try changing email to an existing email, should fail
565
384
  page = page.change_email("Test", "Teacher", other_email, password)
@@ -567,24 +386,36 @@ class TestTeacherFrontend(BaseTest):
567
386
  assert is_email_updated_message_showing(self.selenium)
568
387
 
569
388
  mock_send_dotdigital_email.assert_called_with(
570
- campaign_ids["email_change_notification"], ANY, personalization_values=ANY
389
+ campaign_ids["email_change_notification"],
390
+ ANY,
391
+ personalization_values=ANY,
571
392
  )
572
393
 
573
394
  # Try changing email to an existing indy student's email, should fail
574
395
  indy_email, _, _ = create_independent_student_directly()
575
396
  page = self.go_to_homepage()
576
- page = page.go_to_teacher_login_page().login(email, password).open_account_tab()
397
+ page = (
398
+ page.go_to_teacher_login_page()
399
+ .login(email, password)
400
+ .open_account_tab()
401
+ )
577
402
 
578
403
  page = page.change_email("Test", "Teacher", indy_email, password)
579
404
  assert self.is_email_verification_page(page)
580
405
  assert is_email_updated_message_showing(self.selenium)
581
406
 
582
407
  mock_send_dotdigital_email.assert_called_with(
583
- campaign_ids["email_change_notification"], ANY, personalization_values=ANY
408
+ campaign_ids["email_change_notification"],
409
+ ANY,
410
+ personalization_values=ANY,
584
411
  )
585
412
 
586
413
  page = self.go_to_homepage()
587
- page = page.go_to_teacher_login_page().login(email, password).open_account_tab()
414
+ page = (
415
+ page.go_to_teacher_login_page()
416
+ .login(email, password)
417
+ .open_account_tab()
418
+ )
588
419
 
589
420
  # Try changing email to a new one, should succeed
590
421
  new_email = "another-email@codeforlife.com"
@@ -594,21 +425,33 @@ class TestTeacherFrontend(BaseTest):
594
425
 
595
426
  # Check user can still log in with old account before verifying new email
596
427
  self.selenium.get(self.live_server_url)
597
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password)
428
+ page = (
429
+ HomePage(self.selenium)
430
+ .go_to_teacher_login_page()
431
+ .login(email, password)
432
+ )
598
433
  assert self.is_dashboard_page(page)
599
434
 
600
435
  page = page.logout()
601
436
 
602
437
  mock_send_dotdigital_email.assert_called_with(
603
- campaign_ids["email_change_verification"], ANY, personalization_values=ANY
438
+ campaign_ids["email_change_verification"],
439
+ ANY,
440
+ personalization_values=ANY,
604
441
  )
605
- verification_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["VERIFICATION_LINK"]
442
+ verification_url = mock_send_dotdigital_email.call_args.kwargs[
443
+ "personalization_values"
444
+ ]["VERIFICATION_LINK"]
606
445
 
607
- page = email_utils.follow_change_email_link_to_dashboard(page, verification_url)
446
+ page = email_utils.follow_change_email_link_to_dashboard(
447
+ page, verification_url
448
+ )
608
449
 
609
450
  page = page.login(new_email, password).open_account_tab()
610
451
 
611
- assert page.check_account_details({"first_name": "Test", "last_name": "Teacher"})
452
+ assert page.check_account_details(
453
+ {"first_name": "Test", "last_name": "Teacher"}
454
+ )
612
455
 
613
456
  def test_change_password(self):
614
457
  email, password = signup_teacher_directly()
@@ -617,7 +460,12 @@ class TestTeacherFrontend(BaseTest):
617
460
  create_school_student_directly(access_code)
618
461
 
619
462
  self.selenium.get(self.live_server_url)
620
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password).open_account_tab()
463
+ page = (
464
+ HomePage(self.selenium)
465
+ .go_to_teacher_login_page()
466
+ .login(email, password)
467
+ .open_account_tab()
468
+ )
621
469
 
622
470
  new_password = "AnotherPassword12!"
623
471
  page = page.change_password("Test", "Teacher", new_password, password)
@@ -639,20 +487,28 @@ class TestTeacherFrontend(BaseTest):
639
487
 
640
488
  page.reset_email_submit(email)
641
489
 
642
- mock_send_dotdigital_email.assert_called_with(campaign_ids["reset_password"], ANY, personalization_values=ANY)
490
+ mock_send_dotdigital_email.assert_called_with(
491
+ campaign_ids["reset_password"], ANY, personalization_values=ANY
492
+ )
643
493
 
644
- reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
645
- "RESET_PASSWORD_LINK"
646
- ]
494
+ reset_password_url = mock_send_dotdigital_email.call_args.kwargs[
495
+ "personalization_values"
496
+ ]["RESET_PASSWORD_LINK"]
647
497
 
648
- page = email_utils.follow_reset_email_link(self.selenium, reset_password_url)
498
+ page = email_utils.follow_reset_email_link(
499
+ self.selenium, reset_password_url
500
+ )
649
501
 
650
502
  new_password = "AnotherPassword12!"
651
503
 
652
504
  page.teacher_reset_password(new_password)
653
505
 
654
506
  self.selenium.get(self.live_server_url)
655
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email, new_password)
507
+ page = (
508
+ HomePage(self.selenium)
509
+ .go_to_teacher_login_page()
510
+ .login(email, new_password)
511
+ )
656
512
  assert self.is_dashboard_page(page)
657
513
 
658
514
  @patch("portal.forms.registration.send_dotdigital_email")
@@ -666,18 +522,25 @@ class TestTeacherFrontend(BaseTest):
666
522
 
667
523
  page.reset_email_submit(email)
668
524
 
669
- mock_send_dotdigital_email.assert_called_with(campaign_ids["reset_password"], ANY, personalization_values=ANY)
525
+ mock_send_dotdigital_email.assert_called_with(
526
+ campaign_ids["reset_password"], ANY, personalization_values=ANY
527
+ )
670
528
 
671
- reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
672
- "RESET_PASSWORD_LINK"
673
- ]
529
+ reset_password_url = mock_send_dotdigital_email.call_args.kwargs[
530
+ "personalization_values"
531
+ ]["RESET_PASSWORD_LINK"]
674
532
 
675
- page = email_utils.follow_reset_email_link(self.selenium, reset_password_url)
533
+ page = email_utils.follow_reset_email_link(
534
+ self.selenium, reset_password_url
535
+ )
676
536
 
677
537
  page.reset_password_fail(password)
678
538
 
679
539
  message = page.browser.find_element(By.CLASS_NAME, "errorlist")
680
- assert "Please choose a password that you haven't used before" in message.text
540
+ assert (
541
+ "Please choose a password that you haven't used before"
542
+ in message.text
543
+ )
681
544
 
682
545
  @patch("portal.forms.registration.send_dotdigital_email")
683
546
  def test_reset_password_fail(self, mock_send_dotdigital_email: Mock):
@@ -698,7 +561,10 @@ class TestTeacherFrontend(BaseTest):
698
561
  join_teacher_to_organisation(standard_email, school.name)
699
562
 
700
563
  page = (
701
- self.go_to_homepage().go_to_teacher_login_page().login(standard_email, standard_password).open_classes_tab()
564
+ self.go_to_homepage()
565
+ .go_to_teacher_login_page()
566
+ .login(standard_email, standard_password)
567
+ .open_classes_tab()
702
568
  )
703
569
 
704
570
  assert page.element_does_not_exist_by_id(f"class-code-{access_code}")
@@ -710,8 +576,15 @@ class TestTeacherFrontend(BaseTest):
710
576
  admin_email, admin_password = signup_teacher_directly()
711
577
  join_teacher_to_organisation(admin_email, school.name, is_admin=True)
712
578
 
713
- page = self.go_to_homepage().go_to_teacher_login_page().login(admin_email, admin_password).open_classes_tab()
714
- class_code_field = page.browser.find_element(By.ID, f"class-code-{access_code}")
579
+ page = (
580
+ self.go_to_homepage()
581
+ .go_to_teacher_login_page()
582
+ .login(admin_email, admin_password)
583
+ .open_classes_tab()
584
+ )
585
+ class_code_field = page.browser.find_element(
586
+ By.ID, f"class-code-{access_code}"
587
+ )
715
588
  assert class_code_field.text == access_code
716
589
 
717
590
  def test_admin_student_edit(self):
@@ -719,13 +592,20 @@ class TestTeacherFrontend(BaseTest):
719
592
  school = create_organisation_directly(email)
720
593
 
721
594
  klass, _, access_code = create_class_directly(email, "class123")
722
- student_name, student_password, student_student = create_school_student_directly(access_code)
595
+ (
596
+ student_name,
597
+ student_password,
598
+ student_student,
599
+ ) = create_school_student_directly(access_code)
723
600
 
724
601
  joining_email, joining_password = signup_teacher_directly()
725
602
  join_teacher_to_organisation(joining_email, school.name, is_admin=True)
726
603
 
727
604
  page = (
728
- self.go_to_homepage().go_to_teacher_login_page().login(joining_email, joining_password).open_classes_tab()
605
+ self.go_to_homepage()
606
+ .go_to_teacher_login_page()
607
+ .login(joining_email, joining_password)
608
+ .open_classes_tab()
729
609
  )
730
610
 
731
611
  class_button = WebDriverWait(self.selenium, WAIT_TIME).until(
@@ -739,21 +619,34 @@ class TestTeacherFrontend(BaseTest):
739
619
  edit_student_button.click()
740
620
 
741
621
  title = page.browser.find_element(By.ID, "student_details")
742
- assert title.text == f"Edit student details for {student_name} from class {klass} ({access_code})"
622
+ assert (
623
+ title.text
624
+ == f"Edit student details for {student_name} from class {klass} ({access_code})"
625
+ )
743
626
 
744
627
  def test_make_admin_popup(self):
745
628
  email, password = signup_teacher_directly()
746
629
  school = create_organisation_directly(email)
747
- page = self.go_to_homepage().go_to_teacher_login_page().login(email, password)
630
+ page = (
631
+ self.go_to_homepage()
632
+ .go_to_teacher_login_page()
633
+ .login(email, password)
634
+ )
748
635
  joining_email, _ = signup_teacher_directly()
749
636
 
750
- invite_data = {"teacher_first_name": "Real", "teacher_last_name": "Name", "teacher_email": "ren@me.me"}
637
+ invite_data = {
638
+ "teacher_first_name": "Real",
639
+ "teacher_last_name": "Name",
640
+ "teacher_email": "ren@me.me",
641
+ }
751
642
 
752
643
  for key in invite_data.keys():
753
644
  field = page.browser.find_element(By.NAME, key)
754
645
  field.send_keys(invite_data[key])
755
646
 
756
- invite_button = page.browser.find_element(By.NAME, "invite_teacher_button")
647
+ invite_button = page.browser.find_element(
648
+ By.NAME, "invite_teacher_button"
649
+ )
757
650
  invite_button.click()
758
651
 
759
652
  # Once invite sent test the make admin button
@@ -764,7 +657,11 @@ class TestTeacherFrontend(BaseTest):
764
657
  make_admin_button.click()
765
658
  """
766
659
 
767
- button_ids = ["make_admin_button_invite", "cancel_admin_popup_button", "delete-invite"]
660
+ button_ids = [
661
+ "make_admin_button_invite",
662
+ "cancel_admin_popup_button",
663
+ "delete-invite",
664
+ ]
768
665
  click_buttons_by_id(page, self, button_ids)
769
666
 
770
667
  # Delete the invite and check if the form invite with
@@ -797,27 +694,40 @@ class TestTeacherFrontend(BaseTest):
797
694
  create_organisation_directly(email)
798
695
 
799
696
  self.selenium.get(self.live_server_url)
800
- page = HomePage(self.selenium).go_to_teacher_login_page().login(email, password).open_account_tab()
697
+ page = (
698
+ HomePage(self.selenium)
699
+ .go_to_teacher_login_page()
700
+ .login(email, password)
701
+ .open_account_tab()
702
+ )
801
703
 
802
704
  # test incorrect password
803
- page.browser.find_element(By.ID, "id_delete_password").send_keys("IncorrectPassword")
705
+ page.browser.find_element(By.ID, "id_delete_password").send_keys(
706
+ "IncorrectPassword"
707
+ )
804
708
  page.browser.find_element(By.ID, "delete_account_button").click()
805
709
  is_message_showing(page.browser, "Your account was not deleted")
806
710
 
807
711
  # test cancel (no class)
808
712
  time.sleep(FADE_TIME)
809
713
  page.browser.find_element(By.ID, "id_delete_password").clear()
810
- page.browser.find_element(By.ID, "id_delete_password").send_keys(password)
714
+ page.browser.find_element(By.ID, "id_delete_password").send_keys(
715
+ password
716
+ )
811
717
  page.browser.find_element(By.ID, "delete_account_button").click()
812
718
 
813
719
  time.sleep(FADE_TIME)
814
- assert page.browser.find_element(By.ID, "popup-delete-review").is_displayed()
720
+ assert page.browser.find_element(
721
+ By.ID, "popup-delete-review"
722
+ ).is_displayed()
815
723
  page.browser.find_element(By.ID, "cancel_popup_button").click()
816
724
  time.sleep(FADE_TIME)
817
725
 
818
726
  # test close button in the corner
819
727
  page.browser.find_element(By.ID, "id_delete_password").clear()
820
- page.browser.find_element(By.ID, "id_delete_password").send_keys(password)
728
+ page.browser.find_element(By.ID, "id_delete_password").send_keys(
729
+ password
730
+ )
821
731
  page.browser.find_element(By.ID, "delete_account_button").click()
822
732
 
823
733
  time.sleep(FADE_TIME)
@@ -829,11 +739,15 @@ class TestTeacherFrontend(BaseTest):
829
739
  create_school_student_directly(access_code)
830
740
 
831
741
  # delete then review classes
832
- page.browser.find_element(By.ID, "id_delete_password").send_keys(password)
742
+ page.browser.find_element(By.ID, "id_delete_password").send_keys(
743
+ password
744
+ )
833
745
  page.browser.find_element(By.ID, "delete_account_button").click()
834
746
 
835
747
  time.sleep(FADE_TIME)
836
- assert page.browser.find_element(By.ID, "popup-delete-review").is_displayed()
748
+ assert page.browser.find_element(
749
+ By.ID, "popup-delete-review"
750
+ ).is_displayed()
837
751
  page.browser.find_element(By.ID, "review_button").click()
838
752
  time.sleep(FADE_TIME)
839
753
 
@@ -841,7 +755,9 @@ class TestTeacherFrontend(BaseTest):
841
755
  page = page.open_account_tab()
842
756
 
843
757
  # test actual deletion
844
- page.browser.find_element(By.ID, "id_delete_password").send_keys(password)
758
+ page.browser.find_element(By.ID, "id_delete_password").send_keys(
759
+ password
760
+ )
845
761
  page.browser.find_element(By.ID, "delete_account_button").click()
846
762
 
847
763
  time.sleep(FADE_TIME)
@@ -851,29 +767,49 @@ class TestTeacherFrontend(BaseTest):
851
767
  assert page.browser.find_element(By.CLASS_NAME, "banner--homepage")
852
768
 
853
769
  # user should not be able to login now
854
- page = HomePage(self.selenium).go_to_teacher_login_page().login_failure(email, password)
770
+ page = (
771
+ HomePage(self.selenium)
772
+ .go_to_teacher_login_page()
773
+ .login_failure(email, password)
774
+ )
855
775
 
856
- assert page.has_login_failed("form-login-teacher", INVALID_LOGIN_MESSAGE)
776
+ assert page.has_login_failed(
777
+ "form-login-teacher", INVALID_LOGIN_MESSAGE
778
+ )
857
779
 
858
780
  def test_onboarding_complete(self):
859
781
  email, password = signup_teacher_directly()
860
782
 
861
783
  self.selenium.get(self.live_server_url)
862
- page = HomePage(self.selenium).go_to_teacher_login_page().login_no_school(email, password)
784
+ page = (
785
+ HomePage(self.selenium)
786
+ .go_to_teacher_login_page()
787
+ .login_no_school(email, password)
788
+ )
863
789
 
864
790
  page = page.create_organisation("Test school", "W1", "GB")
865
791
  page = page.create_class("Test class", True)
866
- page = page.type_student_name("Test Student").create_students().complete_setup()
792
+ page = (
793
+ page.type_student_name("Test Student")
794
+ .create_students()
795
+ .complete_setup()
796
+ )
867
797
 
868
798
  assert page.has_onboarding_complete_popup()
869
799
 
870
800
  def get_to_forgotten_password_page(self):
871
801
  self.selenium.get(self.live_server_url)
872
- page = HomePage(self.selenium).go_to_teacher_login_page().go_to_teacher_forgotten_password_page()
802
+ page = (
803
+ HomePage(self.selenium)
804
+ .go_to_teacher_login_page()
805
+ .go_to_teacher_forgotten_password_page()
806
+ )
873
807
  return page
874
808
 
875
809
  def wait_for_email(self):
876
- WebDriverWait(self.selenium, 2).until(lambda driver: len(mail.outbox) == 1)
810
+ WebDriverWait(self.selenium, 2).until(
811
+ lambda driver: len(mail.outbox) == 1
812
+ )
877
813
 
878
814
  def is_dashboard_page(self, page):
879
815
  return page.__class__.__name__ == "TeachDashboardPage"