codeforlife-portal 7.4.8__py2.py3-none-any.whl → 8.0.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.

portal/urls.py CHANGED
@@ -1,11 +1,11 @@
1
1
  from common.permissions import teacher_verified
2
- from django.conf.urls import include, url
3
2
  from django.http import HttpResponse
4
- from django.urls import path
3
+ from django.urls import include, path, re_path
5
4
  from django.views.generic import RedirectView
6
5
  from django.views.generic.base import TemplateView
7
6
  from django.views.i18n import JavaScriptCatalog
8
7
  from game.views.level import play_default_level
8
+ from two_factor.urls import urlpatterns as tf_urls
9
9
  from two_factor.views import (
10
10
  BackupTokensView,
11
11
  ProfileView,
@@ -114,26 +114,28 @@ from portal.views.two_factor.profile import CustomDisableView
114
114
  js_info_dict = {"packages": ("conf.locale",)}
115
115
 
116
116
  two_factor_patterns = [
117
- url(
117
+ re_path(
118
118
  r"^account/two_factor/setup/$", CustomSetupView.as_view(), name="setup"
119
119
  ),
120
- url(r"^account/two_factor/qrcode/$", QRGeneratorView.as_view(), name="qr"),
121
- url(
120
+ re_path(
121
+ r"^account/two_factor/qrcode/$", QRGeneratorView.as_view(), name="qr"
122
+ ),
123
+ re_path(
122
124
  r"^account/two_factor/setup/complete/$",
123
125
  SetupCompleteView.as_view(),
124
126
  name="setup_complete",
125
127
  ),
126
- url(
128
+ re_path(
127
129
  r"^account/two_factor/backup/tokens/$",
128
130
  teacher_verified(BackupTokensView.as_view()),
129
131
  name="backup_tokens",
130
132
  ),
131
- url(
133
+ re_path(
132
134
  r"^account/two_factor/$",
133
135
  teacher_verified(ProfileView.as_view()),
134
136
  name="profile",
135
137
  ),
136
- url(
138
+ re_path(
137
139
  r"^account/two_factor/disable/$",
138
140
  teacher_verified(CustomDisableView.as_view()),
139
141
  name="disable",
@@ -186,45 +188,45 @@ urlpatterns = [
186
188
  ]
187
189
  ),
188
190
  ),
189
- url(
191
+ re_path(
190
192
  r"^favicon\.ico$",
191
193
  RedirectView.as_view(
192
194
  url="/static/portal/img/favicon.ico", permanent=True
193
195
  ),
194
196
  ),
195
- url(
197
+ re_path(
196
198
  r"^administration/password_change/$",
197
199
  AdminChangePasswordView.as_view(),
198
200
  name="administration_password_change",
199
201
  ),
200
- url(
202
+ re_path(
201
203
  r"^administration/password_change_done/$",
202
204
  AdminChangePasswordDoneView.as_view(),
203
205
  name="administration_password_change_done",
204
206
  ),
205
- url(
207
+ re_path(
206
208
  r"^users/inactive/", InactiveUsersView.as_view(), name="inactive_users"
207
209
  ),
208
- url(
210
+ re_path(
209
211
  r"^locked_out/$",
210
212
  TemplateView.as_view(template_name="portal/locked_out.html"),
211
213
  name="locked_out",
212
214
  ),
213
- url(
215
+ re_path(
214
216
  r"^",
215
217
  include((two_factor_patterns, "two_factor"), namespace="two_factor"),
216
218
  ),
217
- url(r"^i18n/", include("django.conf.urls.i18n")),
218
- url(r"^jsi18n/$", JavaScriptCatalog.as_view(), js_info_dict),
219
- url(
219
+ re_path(r"^i18n/", include("django.conf.urls.i18n")),
220
+ re_path(r"^jsi18n/$", JavaScriptCatalog.as_view(), js_info_dict),
221
+ re_path(
220
222
  r"^(?P<level_name>[A-Z0-9]+)/$",
221
223
  play_default_level,
222
224
  name="play_default_level",
223
225
  ),
224
- url(r"^$", home, name="home"),
225
- url(r"^home-learning", home_learning, name="home-learning"),
226
- url(r"^register_form", register_view, name="register"),
227
- url(
226
+ re_path(r"^$", home, name="home"),
227
+ re_path(r"^home-learning", home_learning, name="home-learning"),
228
+ re_path(r"^register_form", register_view, name="register"),
229
+ re_path(
228
230
  r"^login/teacher/$",
229
231
  # The ratelimit decorator checks how often a POST request is performed on that view.
230
232
  # It checks against the username value specifically. If the number of requests
@@ -238,7 +240,7 @@ urlpatterns = [
238
240
  )(TeacherLoginView.as_view()),
239
241
  name="teacher_login",
240
242
  ),
241
- url(
243
+ re_path(
242
244
  rf"^login/student/(?P<access_code>{ACCESS_CODE_REGEX})/(?:(?P<login_type>classform)/)?$",
243
245
  ratelimit(
244
246
  group=RATELIMIT_LOGIN_GROUP,
@@ -250,17 +252,17 @@ urlpatterns = [
250
252
  )(StudentLoginView.as_view()),
251
253
  name="student_login",
252
254
  ),
253
- url(
255
+ re_path(
254
256
  r"^login/student/$",
255
257
  StudentClassCodeView.as_view(),
256
258
  name="student_login_access_code",
257
259
  ),
258
- url(
260
+ re_path(
259
261
  r"^u/(?P<user_id>[0-9]+)/(?P<login_id>[a-z0-9]+)/$",
260
262
  student_direct_login,
261
263
  name="student_direct_login",
262
264
  ),
263
- url(
265
+ re_path(
264
266
  r"^login/independent/$",
265
267
  ratelimit(
266
268
  group=RATELIMIT_LOGIN_GROUP,
@@ -272,106 +274,110 @@ urlpatterns = [
272
274
  )(IndependentStudentLoginView.as_view()),
273
275
  name="independent_student_login",
274
276
  ),
275
- url(r"^login_form", old_login_form_redirect, name="old_login_form"),
276
- url(r"^logout/$", logout_view, name="logout_view"),
277
- url(
277
+ re_path(r"^login_form", old_login_form_redirect, name="old_login_form"),
278
+ re_path(r"^logout/$", logout_view, name="logout_view"),
279
+ re_path(
278
280
  r"^news_signup/$",
279
281
  process_newsletter_form,
280
282
  name="process_newsletter_form",
281
283
  ),
282
- url(r"^donate_signup/$", process_donate_form, name="process_donate_form"),
283
- url(r"^consent_form/$", dotmailer_consent_form, name="consent_form"),
284
- url(
284
+ re_path(
285
+ r"^donate_signup/$", process_donate_form, name="process_donate_form"
286
+ ),
287
+ re_path(r"^consent_form/$", dotmailer_consent_form, name="consent_form"),
288
+ re_path(
285
289
  r"^verify_email/$",
286
290
  TemplateView.as_view(
287
291
  template_name="portal/email_verification_needed.html"
288
292
  ),
289
293
  name="email_verification",
290
294
  ),
291
- url(
295
+ re_path(
292
296
  rf"^verify_email/(?P<token>{JWT_REGEX})/$",
293
297
  verify_email,
294
298
  name="verify_email",
295
299
  ),
296
- url(
300
+ re_path(
297
301
  r"^user/password/reset/student/$",
298
302
  student_password_reset,
299
303
  name="student_password_reset",
300
304
  ),
301
- url(
305
+ re_path(
302
306
  r"^user/password/reset/teacher/$",
303
307
  teacher_password_reset,
304
308
  name="teacher_password_reset",
305
309
  ),
306
- url(
310
+ re_path(
307
311
  r"^user/password/reset/done/$",
308
312
  password_reset_done,
309
313
  name="reset_password_email_sent",
310
314
  ),
311
- url(
315
+ re_path(
312
316
  r"^user/password/reset/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$",
313
317
  password_reset_check_and_confirm,
314
318
  name="password_reset_check_and_confirm",
315
319
  ),
316
- url(
320
+ re_path(
317
321
  r"^user/reset_screentime_warning/$",
318
322
  reset_screentime_warning,
319
323
  name="reset_screentime_warning",
320
324
  ),
321
- url(
325
+ re_path(
322
326
  r"^user/reset_session_time/$",
323
327
  lambda _: HttpResponse(status=204),
324
328
  name="reset_session_time",
325
329
  ),
326
- url(
330
+ re_path(
327
331
  r"^teacher/password/reset/complete/$",
328
332
  TemplateView.as_view(template_name="portal/reset_password_done.html"),
329
333
  name="password_reset_complete",
330
334
  ),
331
- url(r"^teach/$", teach, name="teach"),
332
- url(
335
+ re_path(r"^teach/$", teach, name="teach"),
336
+ re_path(
333
337
  r"^teach/onboarding-organisation/$",
334
338
  organisation_manage,
335
339
  name="onboarding-organisation",
336
340
  ),
337
- url(
341
+ re_path(
338
342
  r"^teach/onboarding-classes",
339
343
  teacher_onboarding_create_class,
340
344
  name="onboarding-classes",
341
345
  ),
342
- url(
346
+ re_path(
343
347
  rf"^teach/onboarding-class/(?P<access_code>{ACCESS_CODE_REGEX})$",
344
348
  teacher_onboarding_edit_class,
345
349
  name="onboarding-class",
346
350
  ),
347
- url(
351
+ re_path(
348
352
  rf"^teach/onboarding-class/(?P<access_code>{ACCESS_CODE_REGEX})/print_reminder_cards/$",
349
353
  teacher_print_reminder_cards,
350
354
  name="teacher_print_reminder_cards",
351
355
  ),
352
- url(
356
+ re_path(
353
357
  rf"^teach/onboarding-class/(?P<access_code>{ACCESS_CODE_REGEX})/download_csv/$",
354
358
  teacher_download_csv,
355
359
  name="teacher_download_csv",
356
360
  ),
357
- url(
361
+ re_path(
358
362
  r"^invited_teacher/(?P<token>[0-9a-f]+)/$",
359
363
  invited_teacher,
360
364
  name="invited_teacher",
361
365
  ),
362
- url(r"^play/$", play_landing_page, name="play"),
363
- url(
366
+ re_path(r"^play/$", play_landing_page, name="play"),
367
+ re_path(
364
368
  r"^play/details/$",
365
369
  SchoolStudentDashboard.as_view(),
366
370
  name="student_details",
367
371
  ),
368
- url(
372
+ re_path(
369
373
  r"^play/details/independent$",
370
374
  IndependentStudentDashboard.as_view(),
371
375
  name="independent_student_details",
372
376
  ),
373
- url(r"^play/account/$", student_edit_account, name="student_edit_account"),
374
- url(
377
+ re_path(
378
+ r"^play/account/$", student_edit_account, name="student_edit_account"
379
+ ),
380
+ re_path(
375
381
  r"^play/account/independent/$",
376
382
  ratelimit(
377
383
  group=RATELIMIT_LOGIN_GROUP,
@@ -383,136 +389,136 @@ urlpatterns = [
383
389
  )(independentStudentEditAccountView),
384
390
  name="independent_edit_account",
385
391
  ),
386
- url(
392
+ re_path(
387
393
  r"^play/account/school_student/$",
388
394
  SchoolStudentEditAccountView.as_view(),
389
395
  name="school_student_edit_account",
390
396
  ),
391
- url(
397
+ re_path(
392
398
  r"^play/join/$",
393
399
  student_join_organisation,
394
400
  name="student_join_organisation",
395
401
  ),
396
- url(r"^about", about, name="about"),
397
- url(r"^getinvolved", getinvolved, name="getinvolved"),
398
- url(r"^contribute", contribute, name="contribute"),
399
- url(r"^terms", terms, name="terms"),
400
- url(r"^privacy-notice/$", privacy_notice, name="privacy_notice"),
401
- url(
402
+ re_path(r"^about", about, name="about"),
403
+ re_path(r"^getinvolved", getinvolved, name="getinvolved"),
404
+ re_path(r"^contribute", contribute, name="contribute"),
405
+ re_path(r"^terms", terms, name="terms"),
406
+ re_path(r"^privacy-notice/$", privacy_notice, name="privacy_notice"),
407
+ re_path(
402
408
  r"^privacy-policy/$", privacy_notice, name="privacy_policy"
403
409
  ), # Keeping this to route from old URL
404
- url(r"^teach/dashboard/$", dashboard_manage, name="dashboard"),
405
- url(
410
+ re_path(r"^teach/dashboard/$", dashboard_manage, name="dashboard"),
411
+ re_path(
406
412
  r"^teach/dashboard/kick/(?P<pk>[0-9]+)/$",
407
413
  organisation_kick,
408
414
  name="organisation_kick",
409
415
  ),
410
- url(
416
+ re_path(
411
417
  r"^teach/dashboard/toggle_admin/(?P<pk>[0-9]+)/$",
412
418
  organisation_toggle_admin,
413
419
  name="organisation_toggle_admin",
414
420
  ),
415
- url(
421
+ re_path(
416
422
  r"^teach/dashboard/disable_2FA/(?P<pk>[0-9]+)/$",
417
423
  teacher_disable_2FA,
418
424
  name="teacher_disable_2FA",
419
425
  ),
420
- url(
426
+ re_path(
421
427
  r"^teach/dashboard/school/leave/$",
422
428
  organisation_leave,
423
429
  name="organisation_leave",
424
430
  ),
425
- url(
431
+ re_path(
426
432
  r"^teach/dashboard/student/accept/(?P<pk>[0-9]+)/$",
427
433
  teacher_accept_student_request,
428
434
  name="teacher_accept_student_request",
429
435
  ),
430
- url(
436
+ re_path(
431
437
  r"^teach/dashboard/student/reject/(?P<pk>[0-9]+)/$",
432
438
  teacher_reject_student_request,
433
439
  name="teacher_reject_student_request",
434
440
  ),
435
- url(
441
+ re_path(
436
442
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})$",
437
443
  teacher_view_class,
438
444
  name="view_class",
439
445
  ),
440
- url(
446
+ re_path(
441
447
  rf"^teach/class/delete/(?P<access_code>{ACCESS_CODE_REGEX})$",
442
448
  teacher_delete_class,
443
449
  name="teacher_delete_class",
444
450
  ),
445
- url(
451
+ re_path(
446
452
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})/students/delete/$",
447
453
  teacher_delete_students,
448
454
  name="teacher_delete_students",
449
455
  ),
450
- url(
456
+ re_path(
451
457
  rf"^teach/class/edit/(?P<access_code>{ACCESS_CODE_REGEX})$",
452
458
  teacher_edit_class,
453
459
  name="teacher_edit_class",
454
460
  ),
455
- url(
461
+ re_path(
456
462
  r"^teach/class/student/edit/(?P<pk>[0-9]+)/$",
457
463
  teacher_edit_student,
458
464
  name="teacher_edit_student",
459
465
  ),
460
- url(
466
+ re_path(
461
467
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})/password_reset/$",
462
468
  teacher_class_password_reset,
463
469
  name="teacher_class_password_reset",
464
470
  ),
465
- url(
471
+ re_path(
466
472
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})/students/dismiss/$",
467
473
  teacher_dismiss_students,
468
474
  name="teacher_dismiss_students",
469
475
  ),
470
- url(
476
+ re_path(
471
477
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})/students/move/$",
472
478
  teacher_move_students,
473
479
  name="teacher_move_students",
474
480
  ),
475
- url(
481
+ re_path(
476
482
  r"^teach/dashboard/resend_invite/(?P<token>[0-9a-f]+)/$",
477
483
  resend_invite_teacher,
478
484
  name="resend_invite_teacher",
479
485
  ),
480
- url(
486
+ re_path(
481
487
  r"^teach/dashboard/toggle_admin_invite/(?P<invite_id>[0-9]+)/$",
482
488
  invite_toggle_admin,
483
489
  name="invite_toggle_admin",
484
490
  ),
485
- url(
491
+ re_path(
486
492
  r"^teach/dashboard/delete_teacher_invite/(?P<token>[0-9a-f]+)$",
487
493
  delete_teacher_invite,
488
494
  name="delete_teacher_invite",
489
495
  ),
490
- url(
496
+ re_path(
491
497
  rf"^teach/class/(?P<access_code>{ACCESS_CODE_REGEX})/students/move/disambiguate/$",
492
498
  teacher_move_students_to_class,
493
499
  name="teacher_move_students_to_class",
494
500
  ),
495
- url(r"^delete/account/$", delete_account, name="delete_account"),
496
- url(
501
+ re_path(r"^delete/account/$", delete_account, name="delete_account"),
502
+ re_path(
497
503
  r"^schools/anonymise/(?P<start_id>\d+)/",
498
504
  AnonymiseOrphanSchoolsView.as_view(),
499
505
  name="anonymise_orphan_schools",
500
506
  ),
501
- url(
507
+ re_path(
502
508
  r"^api/",
503
509
  include(
504
510
  [
505
- url(
511
+ re_path(
506
512
  r"^registered/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$",
507
513
  registered_users,
508
514
  name="registered-users",
509
515
  ),
510
- url(
516
+ re_path(
511
517
  r"^lastconnectedsince/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$",
512
518
  last_connected_since,
513
519
  name="last-connected-since",
514
520
  ),
515
- url(
521
+ re_path(
516
522
  r"^userspercountry/(?P<country>(AF|AX|AL|DZ|AS|AD|AO|AI|AQ|AG|AR|AM|AW|AU|AT|AZ|BS|BH|BD|BB|BY|BE|BZ|BJ|BM|BT|BO|BQ|BA|BW|BV|BR|IO|BN|BG|BF|BI|KH|CM|CA|CV|KY|CF|TD|CL|CN|CX|CC|CO|KM|CG|CD|CK|CR|CI|HR|CU|CW|CY|CZ|DK|DJ|DM|DO|EC|EG|SV|GQ|ER|EE|ET|FK|FO|FJ|FI|FR|GF|PF|TF|GA|GM|GE|DE|GH|GI|GR|GL|GD|GP|GU|GT|GG|GN|GW|GY|HT|HM|VA|HN|HK|HU|IS|IN|ID|IR|IQ|IE|IM|IL|IT|JM|JP|JE|JO|KZ|KE|KI|KP|KR|KW|KG|LA|LV|LB|LS|LR|LY|LI|LT|LU|MO|MK|MG|MW|MY|MV|ML|MT|MH|MQ|MR|MU|YT|MX|FM|MD|MC|MN|ME|MS|MA|MZ|MM|NA|NR|NP|NL|NC|NZ|NI|NE|NG|NU|NF|MP|NO|OM|PK|PW|PS|PA|PG|PY|PE|PH|PN|PL|PT|PR|QA|RE|RO|RU|RW|BL|SH|KN|LC|MF|PM|VC|WS|SM|ST|SA|SN|RS|SC|SL|SG|SX|SK|SI|SB|SO|ZA|GS|SS|ES|LK|SD|SR|SJ|SZ|SE|CH|SY|TW|TJ|TZ|TH|TL|TG|TK|TO|TT|TN|TR|TM|TC|TV|UG|UA|AE|GB|US|UM|UY|UZ|VU|VE|VN|VG|VI|WF|EH|YE|ZM|ZW))/$",
517
523
  number_users_per_country,
518
524
  name="number_users_per_country",
@@ -520,16 +526,16 @@ urlpatterns = [
520
526
  ]
521
527
  ),
522
528
  ),
523
- url(r"^codingClub/$", coding_club, name="codingClub"),
524
- url(
529
+ re_path(r"^codingClub/$", coding_club, name="codingClub"),
530
+ re_path(
525
531
  r"^codingClub/(?P<student_pack_type>[3-4])/",
526
532
  download_student_pack,
527
533
  name="download_student_pack",
528
534
  ),
529
- url(
535
+ re_path(
530
536
  r"^removeFakeAccounts/",
531
537
  RemoveFakeAccounts.as_view(),
532
538
  name="remove_fake_accounts",
533
539
  ),
534
- url(r"^celebrate/", ten_year_map_page, name="celebrate"),
540
+ re_path(r"^celebrate/", ten_year_map_page, name="celebrate"),
535
541
  ]
portal/views/api.py CHANGED
@@ -5,16 +5,16 @@ import uuid
5
5
  from common.models import Class, School, Student, Teacher, UserProfile
6
6
  from django.contrib.auth.decorators import login_required
7
7
  from django.contrib.auth.models import User
8
- from django.db.models import Exists, OuterRef
9
8
  from django.http import HttpRequest, HttpResponse
10
9
  from django.utils import timezone
11
- from portal.app_settings import IS_CLOUD_SCHEDULER_FUNCTION
12
10
  from rest_framework import generics, permissions, serializers, status
13
11
  from rest_framework.authentication import SessionAuthentication
14
12
  from rest_framework.decorators import api_view
15
13
  from rest_framework.response import Response
16
14
  from rest_framework.reverse import reverse_lazy
17
15
 
16
+ from portal.app_settings import IS_CLOUD_SCHEDULER_FUNCTION
17
+
18
18
  LOGGER = logging.getLogger(__name__)
19
19
  THREE_YEARS_IN_DAYS = 1095
20
20
 
@@ -23,7 +23,11 @@ THREE_YEARS_IN_DAYS = 1095
23
23
  @login_required(login_url=reverse_lazy("administration_login"))
24
24
  def registered_users(request, year, month, day):
25
25
  try:
26
- nbr_reg = User.objects.filter(date_joined__startswith=datetime.date(int(year), int(month), int(day))).count()
26
+ nbr_reg = User.objects.filter(
27
+ date_joined__startswith=datetime.date(
28
+ int(year), int(month), int(day)
29
+ )
30
+ ).count()
27
31
  return Response(nbr_reg)
28
32
  except ValueError:
29
33
  return HttpResponse(status=404)
@@ -33,7 +37,9 @@ def registered_users(request, year, month, day):
33
37
  @login_required(login_url=reverse_lazy("administration_login"))
34
38
  def last_connected_since(request, year, month, day):
35
39
  try:
36
- nbr_active_users = User.objects.filter(last_login__gte=datetime.date(int(year), int(month), int(day))).count()
40
+ nbr_active_users = User.objects.filter(
41
+ last_login__gte=datetime.date(int(year), int(month), int(day))
42
+ ).count()
37
43
  return Response(nbr_active_users)
38
44
  except ValueError:
39
45
  return HttpResponse(status=404)
@@ -45,7 +51,9 @@ def number_users_per_country(request, country):
45
51
  try:
46
52
  nbr_reg = (
47
53
  Teacher.objects.filter(school__country__exact=country).count()
48
- + Student.objects.filter(class_field__teacher__school__country__exact=country).count()
54
+ + Student.objects.filter(
55
+ class_field__teacher__school__country__exact=country
56
+ ).count()
49
57
  )
50
58
  return Response(nbr_reg)
51
59
  except ValueError:
@@ -67,7 +75,9 @@ class IsAdminOrGoogleAppEngine(permissions.IsAdminUser):
67
75
  """Checks whether the request is from a Google App Engine cron job."""
68
76
 
69
77
  def has_permission(self, request: HttpRequest, view):
70
- is_admin = super(IsAdminOrGoogleAppEngine, self).has_permission(request, view)
78
+ is_admin = super(IsAdminOrGoogleAppEngine, self).has_permission(
79
+ request, view
80
+ )
71
81
  return IS_CLOUD_SCHEDULER_FUNCTION(request) or is_admin
72
82
 
73
83
 
@@ -107,7 +117,9 @@ def anonymise(user):
107
117
 
108
118
  # if user is admin and the school does not have another admin, appoint another teacher as admin
109
119
  if is_admin:
110
- teachers = Teacher.objects.filter(school=school).order_by("new_user__last_name", "new_user__first_name")
120
+ teachers = Teacher.objects.filter(school=school).order_by(
121
+ "new_user__last_name", "new_user__first_name"
122
+ )
111
123
  if not teachers:
112
124
  # no other teacher, anonymise the school
113
125
  school.anonymise()
@@ -134,10 +146,14 @@ class InactiveUsersView(generics.ListAPIView):
134
146
  """
135
147
 
136
148
  queryset = User.objects.filter(is_active=True) & (
137
- User.objects.filter(last_login__lte=timezone.now() - timezone.timedelta(days=THREE_YEARS_IN_DAYS))
149
+ User.objects.filter(
150
+ last_login__lte=timezone.now()
151
+ - timezone.timedelta(days=THREE_YEARS_IN_DAYS)
152
+ )
138
153
  | User.objects.filter(
139
154
  last_login__isnull=True,
140
- date_joined__lte=timezone.now() - timezone.timedelta(days=THREE_YEARS_IN_DAYS),
155
+ date_joined__lte=timezone.now()
156
+ - timezone.timedelta(days=THREE_YEARS_IN_DAYS),
141
157
  )
142
158
  )
143
159
  authentication_classes = (SessionAuthentication,)
@@ -156,6 +172,7 @@ class RemoveFakeAccounts(generics.ListAPIView):
156
172
  """
157
173
  This API endpoint will delete suspicious accounts that have the same first and last name and who are not verified
158
174
  """
175
+
159
176
  authentication_classes = (SessionAuthentication,)
160
177
  serializer_class = InactiveUserSerializer
161
178
  permission_classes = (IsAdminOrGoogleAppEngine,)
@@ -178,17 +195,14 @@ class AnonymiseOrphanSchoolsView(generics.ListAPIView):
178
195
 
179
196
  def get(self, request: HttpRequest, start_id):
180
197
  # Re-anonymise all inactive teachers so their schools (if necessary) and classes/students are anonymised
181
- for teacher in Teacher._base_manager.filter(pk__gte=start_id, new_user__is_active=False):
198
+ for teacher in Teacher._base_manager.filter(
199
+ pk__gte=start_id, new_user__is_active=False
200
+ ):
182
201
  anonymise(teacher.new_user)
183
202
  LOGGER.info(f"Anonymised teacher ID {teacher.pk}")
184
203
 
185
204
  # Anonymise schools without any teachers
186
- for school in School.objects.filter(
187
- Exists(
188
- Teacher._base_manager.filter(school=OuterRef("pk")),
189
- negated=True,
190
- )
191
- ):
205
+ for school in School.objects.filter(teacher_school__isnull=True):
192
206
  school.anonymise()
193
207
 
194
208
  return Response(status=status.HTTP_204_NO_CONTENT)