codeforlife-portal 7.4.9__py2.py3-none-any.whl → 8.0.1__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/setup.py +10 -5
- {codeforlife_portal-7.4.9.dist-info → codeforlife_portal-8.0.1.dist-info}/METADATA +7 -14
- {codeforlife_portal-7.4.9.dist-info → codeforlife_portal-8.0.1.dist-info}/RECORD +29 -29
- {codeforlife_portal-7.4.9.dist-info → codeforlife_portal-8.0.1.dist-info}/WHEEL +1 -1
- deploy/middleware/security.py +4 -5
- example_project/portal_test_settings.py +1 -1
- example_project/settings.py +2 -2
- example_project/urls.py +4 -5
- portal/__init__.py +1 -1
- portal/admin.py +26 -24
- portal/forms/play.py +2 -2
- portal/forms/registration.py +2 -2
- portal/forms/teach.py +2 -2
- portal/helpers/decorators.py +18 -18
- portal/templates/{captcha → django_recaptcha}/includes/js_v2_invisible.html +3 -3
- portal/templates/{captcha → django_recaptcha}/widget_v2_invisible.html +2 -2
- portal/templates/two_factor/core/login.html +66 -59
- portal/templates/two_factor/core/setup.html +58 -49
- portal/templates/two_factor/profile/profile.html +35 -17
- portal/tests/test_captcha_forms.py +2 -2
- portal/tests/test_middleware.py +32 -10
- portal/urls.py +94 -88
- portal/views/api.py +30 -16
- portal/views/home.py +45 -15
- portal/views/registration.py +3 -3
- portal/views/two_factor/core.py +22 -19
- portal/views/two_factor/profile.py +2 -2
- {codeforlife_portal-7.4.9.dist-info → codeforlife_portal-8.0.1.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-7.4.9.dist-info → codeforlife_portal-8.0.1.dist-info}/top_level.txt +0 -0
cfl_common/setup.py
CHANGED
|
@@ -17,12 +17,17 @@ setup(
|
|
|
17
17
|
version=version,
|
|
18
18
|
include_package_data=True,
|
|
19
19
|
install_requires=[
|
|
20
|
-
"django==
|
|
21
|
-
"
|
|
22
|
-
"django-
|
|
23
|
-
"django-
|
|
24
|
-
"
|
|
20
|
+
"django==4.2.16",
|
|
21
|
+
"django-countries==7.6.1",
|
|
22
|
+
"django-csp==3.8",
|
|
23
|
+
"django-import-export==4.2.0",
|
|
24
|
+
"django-pipeline==3.1.0",
|
|
25
|
+
"django-two-factor-auth==1.17.0",
|
|
26
|
+
"djangorestframework==3.15.1",
|
|
27
|
+
"libsass==0.23.0",
|
|
28
|
+
"more-itertools==8.7.0",
|
|
25
29
|
"pgeocode==0.4.0",
|
|
30
|
+
"pyjwt==2.6.0",
|
|
26
31
|
],
|
|
27
32
|
tests_require=[],
|
|
28
33
|
test_suite="tests",
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codeforlife-portal
|
|
3
|
-
Version:
|
|
3
|
+
Version: 8.0.1
|
|
4
4
|
Classifier: Programming Language :: Python
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.12
|
|
6
6
|
Classifier: Framework :: Django
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE.md
|
|
9
|
-
Requires-Dist: django-
|
|
10
|
-
Requires-Dist: django-recaptcha==2.0.6
|
|
9
|
+
Requires-Dist: django-recaptcha==4.0.0
|
|
11
10
|
Requires-Dist: pyyaml==6.0.2
|
|
12
11
|
Requires-Dist: importlib-metadata==4.13.0
|
|
13
|
-
Requires-Dist: rapid-router>=6.3.6
|
|
14
12
|
Requires-Dist: reportlab==3.6.13
|
|
15
|
-
Requires-Dist: django-formtools==2.
|
|
16
|
-
Requires-Dist: django-otp==1.
|
|
13
|
+
Requires-Dist: django-formtools==2.5.1
|
|
14
|
+
Requires-Dist: django-otp==1.5.4
|
|
17
15
|
Requires-Dist: requests==2.32.2
|
|
18
|
-
Requires-Dist: django-treebeard==4.
|
|
19
|
-
Requires-Dist: django-sekizai==
|
|
20
|
-
Requires-Dist: django-classy-tags==
|
|
21
|
-
Requires-Dist: libsass==0.23.0
|
|
16
|
+
Requires-Dist: django-treebeard==4.7.1
|
|
17
|
+
Requires-Dist: django-sekizai==4.1.0
|
|
18
|
+
Requires-Dist: django-classy-tags==4.1.0
|
|
22
19
|
Requires-Dist: phonenumbers==8.12.12
|
|
23
|
-
Requires-Dist: more-itertools==8.7.0
|
|
24
|
-
Requires-Dist: cfl-common==7.4.9
|
|
25
20
|
Requires-Dist: django-ratelimit==3.0.1
|
|
26
21
|
Requires-Dist: django-preventconcurrentlogins==0.8.2
|
|
27
|
-
Requires-Dist: django-csp==3.7
|
|
28
22
|
Requires-Dist: setuptools==74.0.0
|
|
29
|
-
Requires-Dist: django-import-export
|
|
30
23
|
|
|
31
24
|
# Code for Life Portal
|
|
32
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
cfl_common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
cfl_common/setup.py,sha256=
|
|
2
|
+
cfl_common/setup.py,sha256=XLMyrOLiz1PqXQbnMUcYZEmT5dscDfDjlYF_8r7UmxI,978
|
|
3
3
|
cfl_common/common/__init__.py,sha256=XlncBOpKp_gekbKH7Y_i6yu1qy5tJc3Y8sn8cDy-Vgk,48
|
|
4
4
|
cfl_common/common/app_settings.py,sha256=Bw1DXkZpNIdwUJ-cIOjZnngH5_NbMXC0koW7NgQ0pKY,2495
|
|
5
5
|
cfl_common/common/apps.py,sha256=49UXZ3bSkFKvIEOL4zM7y1sAhccQJyRtsoOg5XVd_8Y,129
|
|
@@ -93,7 +93,7 @@ deploy/middleware/admin_access.py,sha256=-uF9Wgm7WPmNCEQ2Ti-rBXMrYJb0NnrIfnUdRIX
|
|
|
93
93
|
deploy/middleware/basicauth.py,sha256=DiSImGc9mepmsVK1Be5hc2iLnGzsOFx-S2i8AQnXMwY,1170
|
|
94
94
|
deploy/middleware/exceptionlogging.py,sha256=qE3fJnaCwEslrCpF3k8jK1MeqldnvALPnlrUsiqV-5g,474
|
|
95
95
|
deploy/middleware/screentime_warning.py,sha256=-YmaOn9_RQwTU8C6VxDLWct_0G3Y5oHjAv9AvKZSvIw,1152
|
|
96
|
-
deploy/middleware/security.py,sha256=
|
|
96
|
+
deploy/middleware/security.py,sha256=LOZ-OUFo2dVhbRzI_KdSCMh4TItcJhhqzZg5zNAH-6Q,870
|
|
97
97
|
deploy/middleware/session_timeout.py,sha256=Vfl6_9d8KwPsWRvCIcpBm7kWjgvHC8I7exJOejbyI4k,1023
|
|
98
98
|
deploy/static/apple-touch-icon-120x120.png,sha256=7GwelKO6CNbvjJJ1nqMvDGkPoQWqYomMKKP5EB5gmfM,24583
|
|
99
99
|
deploy/static/apple-touch-icon-152x152.png,sha256=V57OGP0VeeKHen_iYVa72sHe_rEaMAJzU1FAiHWWBwY,36276
|
|
@@ -104,19 +104,19 @@ deploy/static/robots.txt,sha256=5cS4RITuQhbpNzvpk4AyDCXdlIBfmfCoBYRvCHY2VT8,24
|
|
|
104
104
|
deploy/templates/deploy/csrf_failure.html,sha256=-pBRPn4Y7nUdYHGpTHCokT9Boi-isuwuivF8V2K1SgM,412
|
|
105
105
|
example_project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
106
|
example_project/manage.py,sha256=EUgybZlZ7xk2Zf2KCwBbK_z7gf7Ifqs0_bl4Kijhdgo,242
|
|
107
|
-
example_project/portal_test_settings.py,sha256=
|
|
108
|
-
example_project/settings.py,sha256=
|
|
109
|
-
example_project/urls.py,sha256=
|
|
107
|
+
example_project/portal_test_settings.py,sha256=7Q7SdosA0Ba85qz-xkAe3EHyMPpSIQ61CSlwYL4uNog,7321
|
|
108
|
+
example_project/settings.py,sha256=NjFhtDNLwdY5vhUAtqk9a9m3GRfcuWRVqIqnJ3u0o6E,5658
|
|
109
|
+
example_project/urls.py,sha256=FUTzHPlUS1O5kqMHjL5V4L552N2ln7uTDXcw9wjKUto,422
|
|
110
110
|
example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
|
|
111
|
-
portal/__init__.py,sha256=
|
|
112
|
-
portal/admin.py,sha256=
|
|
111
|
+
portal/__init__.py,sha256=qR-61NMOca8p2Rty8s6xwXQSXLDufw2os6i4zdyqfak,22
|
|
112
|
+
portal/admin.py,sha256=RKJizTF6dPJKmGPZw7nZUM0X8jkiTjgyKhLQxtvHJ0I,6148
|
|
113
113
|
portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
|
|
114
114
|
portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
|
|
115
115
|
portal/beta.py,sha256=0TCC-9_KZoM1nuzJ9FiuKR5n9JITdMYenHGQtRvn9UU,255
|
|
116
116
|
portal/context_processors.py,sha256=Q68UhmArLPRchS2KmfVR4hKrijllXal3sO5cHYWC2Fc,222
|
|
117
117
|
portal/handlers.py,sha256=gF99OfQrGcIGDnUyONhvylZNU8sl6XHYEurwu0fuiss,422
|
|
118
118
|
portal/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
119
|
-
portal/urls.py,sha256=
|
|
119
|
+
portal/urls.py,sha256=_EJQ7XNVzeqN6g9pbtKg7DHZHlz31-HgWgft6_kOwXw,18415
|
|
120
120
|
portal/wsgi.py,sha256=3yRcNxBQG30NhzrVi93bX-DrbXtsIQBc70HiW5wbOyE,401
|
|
121
121
|
portal/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
122
122
|
portal/forms/admin.py,sha256=Cdl8-wvasAzvMfgUlFYzQjYeuyC7gIsSiy8V_-jMp7w,2080
|
|
@@ -124,12 +124,12 @@ portal/forms/dotmailer.py,sha256=j-o9qthQc7xmOsHSQGEEoHvaEyOpzlWrj6bOnV0PpsI,156
|
|
|
124
124
|
portal/forms/error_messages.py,sha256=8d3z_3e2L-5zwj5hFhnUByC5k2CEpIVVuJg2nYkCUQ8,148
|
|
125
125
|
portal/forms/invite_teacher.py,sha256=jkDNcCfkts4_lXRzhcI3xBam21Zn2yX9wMpMVhDtW1w,880
|
|
126
126
|
portal/forms/organisation.py,sha256=QcQyd7AiqBmvt4y8uQSQylguUbKOKqo2pjqWIkpWjDg,7433
|
|
127
|
-
portal/forms/play.py,sha256=
|
|
128
|
-
portal/forms/registration.py,sha256=
|
|
129
|
-
portal/forms/teach.py,sha256=
|
|
127
|
+
portal/forms/play.py,sha256=j_QYAKb4qyW0uy0VUUG49dmzDLINc3jR6ddK-djrbc4,11523
|
|
128
|
+
portal/forms/registration.py,sha256=a-TuzikRc0Q-BAYs3rJ3Sz1wmQ1o_rTEtZmWdF7-xss,6008
|
|
129
|
+
portal/forms/teach.py,sha256=VutOzDz3ATbL08cs09mcyfWDIX4NV1UQEJWs_OYEvUQ,22706
|
|
130
130
|
portal/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
131
131
|
portal/helpers/captcha.py,sha256=Amwg3HZ9eIh1LGYVYWYruk1ccNj6P3nYP_evufOY8BY,254
|
|
132
|
-
portal/helpers/decorators.py,sha256=
|
|
132
|
+
portal/helpers/decorators.py,sha256=Bs6AVCvcgxfHLdJVWzTmZpxlYbJZXJh5e9AGRXf7cwo,3617
|
|
133
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
|
|
@@ -430,8 +430,8 @@ portal/templates/404.html,sha256=Tk6HmuzDdIT4ojoIHvH2MibU_0OekU5gmuJmk5M4K_Q,563
|
|
|
430
430
|
portal/templates/500.html,sha256=aqJfDXPzaEw9K6LToPpE4rARuunLSxiIrJ_GnuJr8pI,1703
|
|
431
431
|
portal/templates/email.html,sha256=MXB64zc1Sd34eIq8mGT1HhrjAiZUNvRx0_XjZllfKUU,268
|
|
432
432
|
portal/templates/email.txt,sha256=z3bkT2WnkCrVa1RLVbGd-pE81cLEHlZ_QowfbSQAOvg,19
|
|
433
|
-
portal/templates/
|
|
434
|
-
portal/templates/
|
|
433
|
+
portal/templates/django_recaptcha/widget_v2_invisible.html,sha256=3t5JHgyr_so5FQEUtbq501kEjz80KYBOoVz3PuU1JOc,318
|
|
434
|
+
portal/templates/django_recaptcha/includes/js_v2_invisible.html,sha256=QQnBzZBqdtPeJeYFOIihJM18YoSUWbsGjuoMy-5gxNM,1408
|
|
435
435
|
portal/templates/portal/about.html,sha256=_iD0GCP6q3-XuZ2LC-9O0KYY-mKL6c9qk3O-NRRqsRM,10321
|
|
436
436
|
portal/templates/portal/base.html,sha256=4xLACNgKmRQTdEsdNNGYhLzMozzYzWIIzk31HrLGBf0,12109
|
|
437
437
|
portal/templates/portal/base_no_userprofile.html,sha256=PlRufyYmUUGWBZ6CvbYhJWOMTqKqdcee4xnO5--AogA,447
|
|
@@ -512,11 +512,11 @@ portal/templates/two_factor/_wizard_forms_token.html,sha256=5JwDoRj_X1EM8RBISx6C
|
|
|
512
512
|
portal/templates/two_factor/backup_token.html,sha256=5JwDoRj_X1EM8RBISx6Ckb_QZioHknwk_Xi04jUD19U,262
|
|
513
513
|
portal/templates/two_factor/setup_wizard_token.html,sha256=Z0Et2sknJNLtFYvPnVZssG4zCsADuH77xllPIQb22rg,266
|
|
514
514
|
portal/templates/two_factor/core/backup_tokens.html,sha256=u0T-LqtZtGRitlT6lwx_-U8DLPMQERRL2uh_rRL77rI,1442
|
|
515
|
-
portal/templates/two_factor/core/login.html,sha256=
|
|
516
|
-
portal/templates/two_factor/core/setup.html,sha256=
|
|
515
|
+
portal/templates/two_factor/core/login.html,sha256=Pd9sEvuif-C9W5TcHzUT79v_MCetelotFt-uS3TPMWQ,2198
|
|
516
|
+
portal/templates/two_factor/core/setup.html,sha256=B4lg0htUt9JzmTTGG9jGm_1H04FICoMTRwZ-VyQk2E8,3025
|
|
517
517
|
portal/templates/two_factor/core/setup_complete.html,sha256=aE67CIwicwn6W8-JwUqf-bSgje_9G_2Nm9XfnXU-Uhk,600
|
|
518
518
|
portal/templates/two_factor/profile/disable.html,sha256=fKIxqmB8RqN_DQrNMiZPTcSmoH-hChNcGWR0HKl1r-s,1010
|
|
519
|
-
portal/templates/two_factor/profile/profile.html,sha256=
|
|
519
|
+
portal/templates/two_factor/profile/profile.html,sha256=31dWbU-IL1ogn4mNvLYaPix4WQwmoP1Ho-UW66jXywI,2333
|
|
520
520
|
portal/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
521
521
|
portal/templatetags/app_tags.py,sha256=SvOc4sPGNYpUtnJYxS80EmWYSE-C2mzmvxgRqUHet_o,3794
|
|
522
522
|
portal/templatetags/banner_tags.py,sha256=7jk8avxiot0jMM1xWnUbs2QDsOg1v2aJDJA4p0-SJF0,823
|
|
@@ -533,14 +533,14 @@ portal/tests/selenium_test_case.py,sha256=eWUF_5SqkI178bkay5SUDa06r0QTIKUUT8jTAh
|
|
|
533
533
|
portal/tests/test_2FA.py,sha256=0N4C9Ab3TvO9W__oQLCo-fLDH1Ho3CiGGsSg-2TiZUE,3597
|
|
534
534
|
portal/tests/test_admin.py,sha256=AM2dgv8j9m4L-SDO-sMA9tQvQH9GwRBrlwRG9OgqtfI,1451
|
|
535
535
|
portal/tests/test_api.py,sha256=Yo5s_nEGOoG35jA39yZ6nuDOUZvuCZ8o8o8XhZos61w,13819
|
|
536
|
-
portal/tests/test_captcha_forms.py,sha256=
|
|
536
|
+
portal/tests/test_captcha_forms.py,sha256=Yn_VYO_6jbq6AeKeLcv-YFL1YwXZpU0C3y7SK8fRUm4,1033
|
|
537
537
|
portal/tests/test_class.py,sha256=43g2HslNosbSuSnnMBzM6VWk4LaV0HXkWS3f8VKVRmw,15930
|
|
538
538
|
portal/tests/test_emails.py,sha256=pLr06j3uMBxP1raoZQWzUTBVFvsEDFtUh85J8OnqCwE,9238
|
|
539
539
|
portal/tests/test_global_forms.py,sha256=A5JpAe4AYK-wpu0o1qU4THmeNv_wr7lhzaMbjz5czpY,1543
|
|
540
540
|
portal/tests/test_helper_methods.py,sha256=-SQCDZm2XUtyXGEp0CHIb_SSC9CPD-XOSnpnY8QclHk,890
|
|
541
541
|
portal/tests/test_independent_student.py,sha256=NrRjTEr6V4WXpCE74N8LYNVocvLSvddkjuo3dYpfAZc,27245
|
|
542
542
|
portal/tests/test_invite_teacher.py,sha256=gUe1spFp60v3i6kMqGoNgJd0OlBEcwplPPNYLomTJS4,12269
|
|
543
|
-
portal/tests/test_middleware.py,sha256=
|
|
543
|
+
portal/tests/test_middleware.py,sha256=HV7AdgWyvgrtPyDMw3np5YDbUstFpKif7Qqw-e8gs5s,8258
|
|
544
544
|
portal/tests/test_organisation.py,sha256=kCMUNzLN6EzaMUBcFkqXwnqLGgOuQxQWIHHt63nhqBs,7574
|
|
545
545
|
portal/tests/test_partials.py,sha256=cSLNLjdsriROjPxkZlM3HKD3CSKDuKgpaDIdL3fPyBs,1794
|
|
546
546
|
portal/tests/test_ratelimit.py,sha256=XWq1A9XgRrlcMHibGoJ0kc4gLc5U_u5UhKHjthxCfYA,19376
|
|
@@ -606,14 +606,14 @@ portal/tests/utils/messages.py,sha256=LeYqCEU-ubEO1lrPSAaXF6WsM8M7C-ZIfVwwlbAFT2
|
|
|
606
606
|
portal/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
607
607
|
portal/views/about.py,sha256=-muXy17UhxCSKkjnMAkSLXiCvT_pBPlf2ykTYr794dI,443
|
|
608
608
|
portal/views/admin.py,sha256=4Xt3zEyQH7sUwQSrwuRtoCodWidjOzd7gJUwWU96pXY,957
|
|
609
|
-
portal/views/api.py,sha256=
|
|
609
|
+
portal/views/api.py,sha256=mdWmFkV5mxmR-mvj6ttIe8uwW9tbcx9-5ykk5dpX0LI,7047
|
|
610
610
|
portal/views/dotmailer.py,sha256=x49p89TtwA1MLysRLtq5yRRzVtIpzGoU__Xb5hPuHak,3208
|
|
611
611
|
portal/views/email.py,sha256=V3wXRxIjeZ4OJBVqGCQrPn-GQWKZK1PCXbR1f2Zpa_4,2174
|
|
612
|
-
portal/views/home.py,sha256=
|
|
612
|
+
portal/views/home.py,sha256=cKCby5xDYImMeJqNnrnfkDbb3tAcQX-lw6IgBS7RmR4,10050
|
|
613
613
|
portal/views/legal.py,sha256=nUunsTHnhMcXBcDlg1GmUal86k9Vhinne4A2FWfq78M,342
|
|
614
614
|
portal/views/organisation.py,sha256=sPDbiM7hdtpF8GKyh_4n4VPl2a-WnAgnF4q9aSvQCVI,3341
|
|
615
615
|
portal/views/play_landing_page.py,sha256=FFmjUFub3ZdlbMqkB8yX3jAImCzqrUqgb8AZcpKywZ4,308
|
|
616
|
-
portal/views/registration.py,sha256=
|
|
616
|
+
portal/views/registration.py,sha256=9cDKFVXVyJcMJBVZLwHoucMI4UwsOhbUxMdcxIEOixs,10889
|
|
617
617
|
portal/views/teach.py,sha256=nzlyTcgq9ImAjnqrF3esqi212qBLH5Ww1LKE2gSjoRY,210
|
|
618
618
|
portal/views/cron/__init__.py,sha256=5rxXyhJmLOExRdrYZ1VJttTsyRIPRybzdftbUDwFByI,20
|
|
619
619
|
portal/views/cron/user.py,sha256=iKM_FOcSQvrXtRSZUtxSiMFD3M869JP5jvEfRWHLpvM,10731
|
|
@@ -628,11 +628,11 @@ portal/views/teacher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
628
628
|
portal/views/teacher/dashboard.py,sha256=pjzOOCz29d4VHukaCI5QhkDsu-RPvy7SXC9dDcPo50k,27422
|
|
629
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
|
-
portal/views/two_factor/core.py,sha256=
|
|
631
|
+
portal/views/two_factor/core.py,sha256=Lk32z2SN2Pg0rRkK-N-LXMvXC1kKKsH3l692kiSDQ4E,964
|
|
632
632
|
portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
|
|
633
|
-
portal/views/two_factor/profile.py,sha256=
|
|
634
|
-
codeforlife_portal-
|
|
635
|
-
codeforlife_portal-
|
|
636
|
-
codeforlife_portal-
|
|
637
|
-
codeforlife_portal-
|
|
638
|
-
codeforlife_portal-
|
|
633
|
+
portal/views/two_factor/profile.py,sha256=SHSg_xHccE5PtD-OfuOkYhREYz_er4bj5ro1RjJ88Yw,393
|
|
634
|
+
codeforlife_portal-8.0.1.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
|
|
635
|
+
codeforlife_portal-8.0.1.dist-info/METADATA,sha256=BAFsVDbndsTRtpvEE-hMJgpxZyEF-bfL8L2CuBMjZs4,3078
|
|
636
|
+
codeforlife_portal-8.0.1.dist-info/WHEEL,sha256=QyeGbh-t8WT0nt0_LNSP02jN-g4ymd1egk1U3osCGMU,110
|
|
637
|
+
codeforlife_portal-8.0.1.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
|
|
638
|
+
codeforlife_portal-8.0.1.dist-info/RECORD,,
|
deploy/middleware/security.py
CHANGED
|
@@ -4,8 +4,8 @@ from django.middleware.security import SecurityMiddleware
|
|
|
4
4
|
class CustomSecurityMiddleware(SecurityMiddleware):
|
|
5
5
|
"""
|
|
6
6
|
Extends Django's Security Middleware.
|
|
7
|
-
See https://docs.djangoproject.com/en/
|
|
8
|
-
the source code, as well as https://docs.djangoproject.com/en/
|
|
7
|
+
See https://docs.djangoproject.com/en/4.2/_modules/django/middleware/security/ for
|
|
8
|
+
the source code, as well as https://docs.djangoproject.com/en/4.2/ref/middleware/#module-django.middleware.security
|
|
9
9
|
for docs on security middleware.
|
|
10
10
|
"""
|
|
11
11
|
|
|
@@ -13,10 +13,9 @@ class CustomSecurityMiddleware(SecurityMiddleware):
|
|
|
13
13
|
"""
|
|
14
14
|
Extends the original security middleware to ensure the X-XSS-Protection header
|
|
15
15
|
is set to 1.
|
|
16
|
+
https://docs.djangoproject.com/en/5.1/releases/4.0/#securitymiddleware-no-longer-sets-the-x-xss-protection-header
|
|
16
17
|
"""
|
|
17
18
|
super().process_response(request, response)
|
|
18
|
-
|
|
19
|
-
if self.xss_filter:
|
|
20
|
-
response["X-XSS-Protection"] = "1"
|
|
19
|
+
response.headers.setdefault("X-XSS-Protection", "1; mode=block")
|
|
21
20
|
|
|
22
21
|
return response
|
example_project/settings.py
CHANGED
|
@@ -36,13 +36,13 @@ LOGIN_REDIRECT_URL = "/teach/dashboard/"
|
|
|
36
36
|
|
|
37
37
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
|
38
38
|
|
|
39
|
-
SILENCED_SYSTEM_CHECKS = ["
|
|
39
|
+
SILENCED_SYSTEM_CHECKS = ["django_recaptcha.recaptcha_test_key_error"]
|
|
40
40
|
|
|
41
41
|
INSTALLED_APPS = [
|
|
42
42
|
"game",
|
|
43
43
|
"pipeline",
|
|
44
44
|
"portal",
|
|
45
|
-
"
|
|
45
|
+
"django_recaptcha",
|
|
46
46
|
"common",
|
|
47
47
|
"django.contrib.admin",
|
|
48
48
|
"django.contrib.admindocs",
|
example_project/urls.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
from django.conf.urls import include, url
|
|
2
1
|
from django.contrib import admin
|
|
3
|
-
from django.urls import path
|
|
2
|
+
from django.urls import include, path, re_path
|
|
4
3
|
from game import python_den_urls
|
|
5
4
|
from game import urls as game_urls
|
|
6
5
|
|
|
@@ -9,8 +8,8 @@ from portal import urls as portal_urls
|
|
|
9
8
|
admin.autodiscover()
|
|
10
9
|
|
|
11
10
|
urlpatterns = [
|
|
12
|
-
|
|
11
|
+
re_path(r"^", include(portal_urls)),
|
|
13
12
|
path("administration/", admin.site.urls),
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
re_path(r"^rapidrouter/", include(game_urls)),
|
|
14
|
+
re_path(r"^pythonden/", include(python_den_urls)),
|
|
16
15
|
]
|
portal/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "
|
|
1
|
+
__version__ = "8.0.1"
|
portal/admin.py
CHANGED
|
@@ -12,7 +12,7 @@ from common.models import (
|
|
|
12
12
|
UserProfile,
|
|
13
13
|
)
|
|
14
14
|
from django.contrib import admin
|
|
15
|
-
from django.contrib.auth.admin import UserAdmin
|
|
15
|
+
from django.contrib.auth.admin import UserAdmin as _UserAdmin
|
|
16
16
|
from django.contrib.auth.models import User
|
|
17
17
|
from django.http import HttpResponse
|
|
18
18
|
from import_export.admin import ExportActionMixin
|
|
@@ -172,38 +172,40 @@ class TotalActivityAdmin(admin.ModelAdmin, ExportActionMixin):
|
|
|
172
172
|
return False
|
|
173
173
|
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
anonymise(user)
|
|
175
|
+
_UserAdmin.list_display += ("date_joined", "id")
|
|
176
|
+
_UserAdmin.list_filter += ("date_joined",)
|
|
178
177
|
|
|
179
178
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
]
|
|
179
|
+
class UserAdmin(_UserAdmin):
|
|
180
|
+
actions = ["anonymise_user", "export_as_csv"]
|
|
181
|
+
add_form = AdminUserCreationForm
|
|
182
|
+
change_password_form = AdminChangeUserPasswordForm
|
|
185
183
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
def anonymise_user(self, request, queryset):
|
|
185
|
+
for user in queryset:
|
|
186
|
+
anonymise(user)
|
|
189
187
|
|
|
190
|
-
|
|
191
|
-
for obj in queryset:
|
|
192
|
-
writer.writerow([getattr(obj, field) for field in field_names])
|
|
188
|
+
anonymise_user.short_description = "Anonymise selected users"
|
|
193
189
|
|
|
194
|
-
|
|
190
|
+
def export_as_csv(self, request, queryset):
|
|
191
|
+
meta = self.model._meta
|
|
192
|
+
field_names = [
|
|
193
|
+
field.name for field in meta.fields if field.name != "password"
|
|
194
|
+
]
|
|
195
195
|
|
|
196
|
+
response = HttpResponse(content_type="text/csv")
|
|
197
|
+
response["Content-Disposition"] = "attachment; filename={}.csv".format(
|
|
198
|
+
meta
|
|
199
|
+
)
|
|
200
|
+
writer = csv.writer(response)
|
|
196
201
|
|
|
197
|
-
|
|
198
|
-
|
|
202
|
+
writer.writerow(field_names)
|
|
203
|
+
for obj in queryset:
|
|
204
|
+
writer.writerow([getattr(obj, field) for field in field_names])
|
|
199
205
|
|
|
206
|
+
return response
|
|
200
207
|
|
|
201
|
-
|
|
202
|
-
UserAdmin.list_filter += ("date_joined",)
|
|
203
|
-
UserAdmin.add_form = AdminUserCreationForm
|
|
204
|
-
UserAdmin.change_password_form = AdminChangeUserPasswordForm
|
|
205
|
-
UserAdmin.actions.append(anonymise_user)
|
|
206
|
-
UserAdmin.actions.append(export_as_csv)
|
|
208
|
+
export_as_csv.short_description = "Export selected users data as CSV"
|
|
207
209
|
|
|
208
210
|
|
|
209
211
|
admin.site.register(Class, ClassAdmin)
|
portal/forms/play.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import re
|
|
2
2
|
from datetime import timedelta, date
|
|
3
3
|
|
|
4
|
-
from captcha.fields import ReCaptchaField
|
|
5
|
-
from captcha.widgets import ReCaptchaV2Invisible
|
|
6
4
|
from common.helpers.emails import send_verification_email
|
|
7
5
|
from common.models import Class, Student, stripStudentName
|
|
8
6
|
from common.permissions import logged_in_as_independent_student
|
|
@@ -10,6 +8,8 @@ from django import forms
|
|
|
10
8
|
from django.contrib.auth import authenticate
|
|
11
9
|
from django.contrib.auth.forms import AuthenticationForm
|
|
12
10
|
from django.utils import timezone
|
|
11
|
+
from django_recaptcha.fields import ReCaptchaField
|
|
12
|
+
from django_recaptcha.widgets import ReCaptchaV2Invisible
|
|
13
13
|
|
|
14
14
|
from portal.forms.error_messages import INVALID_LOGIN_MESSAGE
|
|
15
15
|
from portal.helpers.password import PasswordStrength, form_clean_password
|
portal/forms/registration.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from captcha.fields import ReCaptchaField
|
|
2
|
-
from captcha.widgets import ReCaptchaV2Invisible
|
|
3
1
|
from common.mail import campaign_ids, send_dotdigital_email
|
|
4
2
|
from common.models import Student, Teacher
|
|
5
3
|
from django import forms
|
|
@@ -10,6 +8,8 @@ from django.contrib.sites.shortcuts import get_current_site
|
|
|
10
8
|
from django.urls import reverse_lazy
|
|
11
9
|
from django.utils.encoding import force_bytes
|
|
12
10
|
from django.utils.http import urlsafe_base64_encode
|
|
11
|
+
from django_recaptcha.fields import ReCaptchaField
|
|
12
|
+
from django_recaptcha.widgets import ReCaptchaV2Invisible
|
|
13
13
|
|
|
14
14
|
from portal.helpers.password import PasswordStrength, form_clean_password
|
|
15
15
|
|
portal/forms/teach.py
CHANGED
|
@@ -2,14 +2,14 @@ import itertools
|
|
|
2
2
|
import re
|
|
3
3
|
from builtins import map, range, str
|
|
4
4
|
|
|
5
|
-
from captcha.fields import ReCaptchaField
|
|
6
|
-
from captcha.widgets import ReCaptchaV2Invisible
|
|
7
5
|
from common.helpers.emails import send_verification_email
|
|
8
6
|
from common.models import Student, stripStudentName, UserSession, Teacher
|
|
9
7
|
from django import forms
|
|
10
8
|
from django.contrib.auth import authenticate
|
|
11
9
|
from django.contrib.auth.forms import AuthenticationForm
|
|
12
10
|
from django.contrib.auth.models import User
|
|
11
|
+
from django_recaptcha.fields import ReCaptchaField
|
|
12
|
+
from django_recaptcha.widgets import ReCaptchaV2Invisible
|
|
13
13
|
from game.models import Episode
|
|
14
14
|
|
|
15
15
|
from portal.forms.error_messages import INVALID_LOGIN_MESSAGE
|
portal/helpers/decorators.py
CHANGED
|
@@ -1,28 +1,24 @@
|
|
|
1
1
|
from __future__ import absolute_import
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
|
-
import
|
|
5
|
-
import re
|
|
6
|
-
|
|
4
|
+
from functools import wraps
|
|
7
5
|
|
|
6
|
+
import pytz
|
|
8
7
|
from common.models import Teacher, Student
|
|
9
8
|
from django.contrib.auth import logout
|
|
10
9
|
from django.shortcuts import render
|
|
11
|
-
from functools import wraps
|
|
12
10
|
from ratelimit import ALL, UNSAFE
|
|
13
11
|
|
|
14
12
|
from portal.helpers.ratelimit import is_ratelimited
|
|
15
|
-
from portal.templatetags.app_tags import is_logged_in
|
|
16
|
-
from portal.views.registration import blocked_and_not_expired
|
|
17
|
-
from portal.views.login import has_user_lockout_expired
|
|
18
|
-
from portal.helpers.ratelimit import get_ratelimit_count_for_user
|
|
19
|
-
|
|
20
13
|
from portal.helpers.request_handlers import get_access_code_from_request
|
|
14
|
+
from portal.templatetags.app_tags import is_logged_in
|
|
21
15
|
|
|
22
16
|
__all__ = ["ratelimit"]
|
|
23
17
|
|
|
24
18
|
|
|
25
|
-
def ratelimit(
|
|
19
|
+
def ratelimit(
|
|
20
|
+
group=None, key=None, rate=None, method=ALL, block=False, is_teacher=True
|
|
21
|
+
):
|
|
26
22
|
"""
|
|
27
23
|
Ratelimit decorator, adding custom functionality to django-ratelimit's default
|
|
28
24
|
decorator. On block, the user is logged out, redirected to the "locked out" page,
|
|
@@ -63,25 +59,29 @@ def ratelimit(group=None, key=None, rate=None, method=ALL, block=False, is_teach
|
|
|
63
59
|
|
|
64
60
|
access_code = get_access_code_from_request(request)
|
|
65
61
|
model_finder = model.objects.get
|
|
66
|
-
# look for school student
|
|
67
|
-
# if
|
|
68
|
-
#
|
|
69
|
-
# move on to another try block
|
|
70
|
-
# similar logic followed afterwards
|
|
62
|
+
# look for school student if access code not found
|
|
63
|
+
# (AttributeError) if student not found (IndexError) move
|
|
64
|
+
# on to another try block similar logic followed afterwards
|
|
71
65
|
if access_code:
|
|
72
66
|
user_to_lockout = model_finder(
|
|
73
67
|
new_user__first_name=username,
|
|
74
68
|
class_field__access_code=access_code, # extract the found text from regex
|
|
75
69
|
)
|
|
76
|
-
lockout_template =
|
|
70
|
+
lockout_template = (
|
|
71
|
+
"portal/locked_out_school_student.html"
|
|
72
|
+
)
|
|
77
73
|
# look for indy student or teacher
|
|
78
74
|
else:
|
|
79
|
-
user_to_lockout = model_finder(
|
|
75
|
+
user_to_lockout = model_finder(
|
|
76
|
+
new_user__username=username
|
|
77
|
+
)
|
|
80
78
|
else:
|
|
81
79
|
user_to_lockout = model.objects.get(new_user=request.user)
|
|
82
80
|
|
|
83
81
|
if user_to_lockout:
|
|
84
|
-
user_to_lockout.blocked_time = datetime.datetime.now(
|
|
82
|
+
user_to_lockout.blocked_time = datetime.datetime.now(
|
|
83
|
+
tz=pytz.utc
|
|
84
|
+
)
|
|
85
85
|
user_to_lockout.save()
|
|
86
86
|
|
|
87
87
|
if is_logged_in(request.user):
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<!-- This is adapted from django-recaptcha 4.0.0 to work on multiple
|
|
2
|
+
reCAPTCHA's on the same page
|
|
3
|
+
See verifyCaptcha_{{ widget_uuid}} for the edit #} -->
|
|
3
4
|
<script src="https://{{ recaptcha_domain }}/recaptcha/api.js{% if api_params %}?{{ api_params }}{% endif %}"></script>
|
|
4
5
|
<script type="text/javascript">
|
|
5
|
-
|
|
6
6
|
// Submit function to be called, after reCAPTCHA was successful.
|
|
7
7
|
var onSubmit_{{ widget_uuid }} = function(token) {
|
|
8
8
|
console.log("reCAPTCHA validated for 'data-widget-uuid=\"{{ widget_uuid }}\"'. Submitting form...")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
{% include "
|
|
1
|
+
<!-- copied from django-recaptcha 4.0.0 -->
|
|
2
|
+
{% include "django_recaptcha/includes/js_v2_invisible.html" %}
|
|
3
3
|
<div class="g-recaptcha"
|
|
4
4
|
{% for name, value in widget.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}
|
|
5
5
|
>
|