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

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 7.4.7
3
+ Version: 7.4.9
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -21,7 +21,7 @@ Requires-Dist: django-classy-tags==2.0.0
21
21
  Requires-Dist: libsass==0.23.0
22
22
  Requires-Dist: phonenumbers==8.12.12
23
23
  Requires-Dist: more-itertools==8.7.0
24
- Requires-Dist: cfl-common==7.4.7
24
+ Requires-Dist: cfl-common==7.4.9
25
25
  Requires-Dist: django-ratelimit==3.0.1
26
26
  Requires-Dist: django-preventconcurrentlogins==0.8.2
27
27
  Requires-Dist: django-csp==3.7
@@ -108,7 +108,7 @@ example_project/portal_test_settings.py,sha256=_gI7-HMoPJ-cDGO6n5UlEIHKHuTR5SC_X
108
108
  example_project/settings.py,sha256=HgGSG0n6Xggd0NieFVoJgn8vKGqyRbCddoB3CRuoT-Y,5640
109
109
  example_project/urls.py,sha256=3SsP5jvPAXV5xmduka4zbSZB5PbXggjsalu1ojY5KIo,434
110
110
  example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
111
- portal/__init__.py,sha256=u4NoBVHR1T-STbqzVWCh66zP8QxD3S_5n4P87Q_xWOA,22
111
+ portal/__init__.py,sha256=4Oq5cK6u8vYJtO-kHkWgMNQEUpUB1YbKJ_fc_Ehjwqk,22
112
112
  portal/admin.py,sha256=on1-zNRnZvf2cwBN6GVRVYRhkaksrCgfzX8XPWtkvz8,6062
113
113
  portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
114
114
  portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
@@ -130,7 +130,7 @@ portal/forms/teach.py,sha256=Fd7zOdwpKTFmxxa3q_Tsj1E9B_M5DZlStF5YXiCA-ys,22688
130
130
  portal/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  portal/helpers/captcha.py,sha256=Amwg3HZ9eIh1LGYVYWYruk1ccNj6P3nYP_evufOY8BY,254
132
132
  portal/helpers/decorators.py,sha256=AnHbcRg42cUYkpMnJMImEMueSKHZRBZ0o67B7_Wp_Zs,3695
133
- portal/helpers/password.py,sha256=SCs-CgBp2y-k7PdEocgNZp03MYzkKZvXsW7Ed68qs_Q,5371
133
+ portal/helpers/password.py,sha256=tvCRwul_70XE7D_RkEbs7Ox7kMZlECzZEhDVn_0yfFw,5546
134
134
  portal/helpers/ratelimit.py,sha256=AyQ31YbhPUIE6JFyc8RARiTzLoMDeCSwKFNIZ7u0MNM,6744
135
135
  portal/helpers/regexes.py,sha256=LlMsbmjGow70QWUh__3PnQWVIce4W9kKSzKnYSGN9AA,813
136
136
  portal/helpers/request_handlers.py,sha256=eRubxSYj17tpwnLqpO90Sk0qt8W0bg3kTmzKsoJItZA,354
@@ -548,7 +548,7 @@ portal/tests/test_school_student.py,sha256=bFZwY4twaFHQLp0cltMq8cLNDZGgCHTZBCZHK
548
548
  portal/tests/test_security.py,sha256=FGrlRfnzi-Xx2_bn4fTZlYORKm7w_GhGkD3havvplwc,3239
549
549
  portal/tests/test_teacher.py,sha256=vjnJi_aj_x48OJOMMRIBr0JTCxy4tFxqrLfCgw0fRxQ,29315
550
550
  portal/tests/test_teacher_student.py,sha256=NWITbUw1kijqu3c8eRHLHJKaYQMOsOMvl7PAVx5QghI,21567
551
- portal/tests/test_views.py,sha256=krg_3ZPbpPti7WNFyQkP7Mg4yX4_1dErZAX2iRJ2hu0,46751
551
+ portal/tests/test_views.py,sha256=fBh8fZkS4p9iMEqeMgSSAcL09nH6TCohwdX4BuysxjQ,47389
552
552
  portal/tests/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
553
553
  portal/tests/migrations/test_migration_make_portaladmin_teacher.py,sha256=ekMRb6cU97oT0k9gCKW7IUB7oPuGmv4uWJCqInQN7x8,2589
554
554
  portal/tests/migrations/test_migration_preview_user_remove.py,sha256=K6D-FZT9YFEA8oMxHz9VTglVV6MZOTRYVlvwWwXc2vU,555
@@ -626,13 +626,13 @@ portal/views/student/edit_account_details.py,sha256=Ba-3D_zzKbX5N01NG5qqBS0ud10B
626
626
  portal/views/student/play.py,sha256=GMxk65bxWOe1Ds2kb6rvuOd1GoAtt5v_9AihLNXoUL0,8768
627
627
  portal/views/teacher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
628
628
  portal/views/teacher/dashboard.py,sha256=pjzOOCz29d4VHukaCI5QhkDsu-RPvy7SXC9dDcPo50k,27422
629
- portal/views/teacher/teach.py,sha256=yWe2K0FHEQB_K3vzPJO8MR0gU2ZaDrXGw8gXMJBH0T0,35765
629
+ portal/views/teacher/teach.py,sha256=-9zzpNLR2oRkyBFXzXjL0_ew_Qpk27w7uca5rKNeCgE,35988
630
630
  portal/views/two_factor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
631
631
  portal/views/two_factor/core.py,sha256=O_wcBeFqdPYSGNGv-pT_vbs5-Dj1Z-Jfkd6f9-E5yZI,760
632
632
  portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
633
633
  portal/views/two_factor/profile.py,sha256=tkl_ludo8arMtd5LKNmohM66vpC_YQiP-0nspTSJiJ4,383
634
- codeforlife_portal-7.4.7.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
635
- codeforlife_portal-7.4.7.dist-info/METADATA,sha256=s2XuydXH4SnXsts2aElQJ_FeKkJShvHfoJgWIC7v24I,3317
636
- codeforlife_portal-7.4.7.dist-info/WHEEL,sha256=fS9sRbCBHs7VFcwJLnLXN1MZRR0_TVTxvXKzOnaSFs8,110
637
- codeforlife_portal-7.4.7.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
638
- codeforlife_portal-7.4.7.dist-info/RECORD,,
634
+ codeforlife_portal-7.4.9.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
635
+ codeforlife_portal-7.4.9.dist-info/METADATA,sha256=uWpHk0_w6eliUYC6nAqgBP9jZEO3OBBn4qlreDTiGUk,3317
636
+ codeforlife_portal-7.4.9.dist-info/WHEEL,sha256=fS9sRbCBHs7VFcwJLnLXN1MZRR0_TVTxvXKzOnaSFs8,110
637
+ codeforlife_portal-7.4.9.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
638
+ codeforlife_portal-7.4.9.dist-info/RECORD,,
portal/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "7.4.7"
1
+ __version__ = "7.4.9"
@@ -1,16 +1,14 @@
1
+ import hashlib
1
2
  import re
2
3
  from enum import Enum, auto
3
4
 
5
+ import requests
4
6
  from django import forms
5
7
  from django.contrib.auth import update_session_auth_hash
6
8
  from django.contrib.auth.hashers import PBKDF2PasswordHasher as ph
7
9
  from django.core.exceptions import ValidationError
8
10
 
9
11
 
10
- import hashlib
11
- import requests
12
-
13
-
14
12
  def is_password_pwned(password):
15
13
  # Create SHA1 hash of the password
16
14
  sha1_hash = hashlib.sha1(password.encode()).hexdigest()
@@ -41,56 +39,56 @@ class PasswordStrength(Enum):
41
39
  TEACHER = auto()
42
40
 
43
41
  def password_test(self, password):
44
- if self is PasswordStrength.STUDENT:
45
- minimum_password_length = 6
46
- # Make student password case insensitive
47
- password = password.lower()
48
- if password and not password_strength_test(
49
- password=password,
50
- minimum_password_length=minimum_password_length,
51
- upper=False,
52
- lower=False,
53
- numbers=False,
54
- special_char=False,
55
- ):
56
- raise forms.ValidationError(
57
- f"Password not strong enough, consider using at least {minimum_password_length} characters and making it hard to guess."
58
- )
59
- if is_password_pwned(password):
60
- raise forms.ValidationError("Password is too common, consider using a different password.")
61
-
62
- elif self is PasswordStrength.INDEPENDENT:
63
- minimum_password_length = 8
64
- if password and not password_strength_test(
65
- password=password,
66
- minimum_password_length=minimum_password_length,
67
- upper=True,
68
- lower=True,
69
- numbers=True,
70
- special_char=False,
71
- ):
72
- raise forms.ValidationError(
73
- f"Password not strong enough, consider using at least {minimum_password_length} characters, "
74
- "upper and lower case letters, and numbers and making it hard to guess."
75
- )
76
- if is_password_pwned(password):
77
- raise forms.ValidationError("Password is too common, consider using a different password.")
78
- else:
79
- minimum_password_length = 10
80
- if password and not password_strength_test(
81
- password=password,
82
- minimum_password_length=minimum_password_length,
83
- upper=True,
84
- lower=True,
85
- numbers=True,
86
- special_char=True,
87
- ):
88
- raise forms.ValidationError(
89
- f"Password not strong enough, consider using at least {minimum_password_length} characters, "
90
- "upper and lower case letters, numbers, special characters and making it hard to guess."
91
- )
92
- if is_password_pwned(password):
93
- raise forms.ValidationError("Password is too common, consider using a different password.")
42
+ if password:
43
+ if self is PasswordStrength.STUDENT:
44
+ minimum_password_length = 6
45
+ # Make student password case insensitive
46
+ password = password.lower()
47
+ if not password_strength_test(
48
+ password=password,
49
+ minimum_password_length=minimum_password_length,
50
+ upper=False,
51
+ lower=False,
52
+ numbers=False,
53
+ special_char=False,
54
+ ):
55
+ raise forms.ValidationError(
56
+ f"Password not strong enough, consider using at least {minimum_password_length} characters and making it hard to guess."
57
+ )
58
+ if is_password_pwned(password):
59
+ raise forms.ValidationError("Password is too common, consider using a different password.")
60
+ elif self is PasswordStrength.INDEPENDENT:
61
+ minimum_password_length = 8
62
+ if not password_strength_test(
63
+ password=password,
64
+ minimum_password_length=minimum_password_length,
65
+ upper=True,
66
+ lower=True,
67
+ numbers=True,
68
+ special_char=False,
69
+ ):
70
+ raise forms.ValidationError(
71
+ f"Password not strong enough, consider using at least {minimum_password_length} characters, "
72
+ "upper and lower case letters, and numbers and making it hard to guess."
73
+ )
74
+ if is_password_pwned(password):
75
+ raise forms.ValidationError("Password is too common, consider using a different password.")
76
+ else:
77
+ minimum_password_length = 10
78
+ if not password_strength_test(
79
+ password=password,
80
+ minimum_password_length=minimum_password_length,
81
+ upper=True,
82
+ lower=True,
83
+ numbers=True,
84
+ special_char=True,
85
+ ):
86
+ raise forms.ValidationError(
87
+ f"Password not strong enough, consider using at least {minimum_password_length} characters, "
88
+ "upper and lower case letters, numbers, special characters and making it hard to guess."
89
+ )
90
+ if is_password_pwned(password):
91
+ raise forms.ValidationError("Password is too common, consider using a different password.")
94
92
 
95
93
  return password
96
94
 
@@ -252,11 +252,24 @@ class TestTeacherViews(TestCase):
252
252
  assert response.status_code == 302
253
253
 
254
254
  student = Student.objects.get(pk=self.student.pk)
255
+
255
256
  assert student.user.is_verified
256
257
 
257
258
  c.logout()
258
259
  c.login(username=self.email, password=self.password)
259
260
 
261
+ teacher = Teacher.objects.factory("the", "teacher", "theteacher@foo.com", "password")
262
+ level = Level.objects.create()
263
+
264
+ level.owner = student.new_user.userprofile
265
+ level.shared_with.add(teacher.new_user)
266
+ level.save()
267
+
268
+ students_levels = Level.objects.filter(owner=student.new_user.userprofile).all()
269
+
270
+ for level in students_levels.all():
271
+ assert level.shared_with.exists()
272
+
260
273
  release_url = reverse(
261
274
  "teacher_dismiss_students", args=[self.class_access_code]
262
275
  )
@@ -279,6 +292,11 @@ class TestTeacherViews(TestCase):
279
292
  student = Student.objects.get(pk=self.student.pk)
280
293
  assert not student.user.is_verified
281
294
 
295
+ students_levels = Level.objects.filter(owner=student.new_user.userprofile).all()
296
+
297
+ for level in students_levels.all():
298
+ assert not level.shared_with.exists()
299
+
282
300
 
283
301
  class TestLoginViews(TestCase):
284
302
  @classmethod
@@ -39,6 +39,8 @@ from reportlab.lib.pagesizes import A4
39
39
  from reportlab.lib.utils import ImageReader
40
40
  from reportlab.pdfgen import canvas
41
41
 
42
+ from game.models import Level
43
+
42
44
  from portal.forms.teach import (
43
45
  BaseTeacherDismissStudentsFormSet,
44
46
  BaseTeacherMoveStudentsDisambiguationFormSet,
@@ -56,6 +58,7 @@ from portal.forms.teach import (
56
58
  from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
57
59
  from portal.views.registration import handle_reset_password_tracking
58
60
 
61
+
59
62
  STUDENT_PASSWORD_LENGTH = 6
60
63
  REMINDER_CARDS_PDF_ROWS = 8
61
64
  REMINDER_CARDS_PDF_COLUMNS = 1
@@ -616,6 +619,11 @@ def process_dismiss_student_form(request, formset, klass, access_code):
616
619
  new_user__first_name__iexact=data["orig_name"],
617
620
  )
618
621
 
622
+ students_levels = Level.objects.filter(owner=student.new_user.userprofile).all()
623
+ for level in students_levels:
624
+ level.shared_with.set([])
625
+ level.save()
626
+
619
627
  student.class_field = None
620
628
  student.new_user.first_name = data["name"]
621
629
  student.new_user.username = data["email"]