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

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: codeforlife-portal
3
- Version: 8.1.3
3
+ Version: 8.2.1
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -94,6 +94,7 @@ deploy/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
94
94
  deploy/middleware/admin_access.py,sha256=-uF9Wgm7WPmNCEQ2Ti-rBXMrYJb0NnrIfnUdRIXzlWs,1207
95
95
  deploy/middleware/basicauth.py,sha256=DiSImGc9mepmsVK1Be5hc2iLnGzsOFx-S2i8AQnXMwY,1170
96
96
  deploy/middleware/exceptionlogging.py,sha256=qE3fJnaCwEslrCpF3k8jK1MeqldnvALPnlrUsiqV-5g,474
97
+ deploy/middleware/maintenance.py,sha256=JhlQD7FowzxnRxk1_uGXYRQ2Aas6v3C9BRxYgN1HLAY,932
97
98
  deploy/middleware/screentime_warning.py,sha256=-YmaOn9_RQwTU8C6VxDLWct_0G3Y5oHjAv9AvKZSvIw,1152
98
99
  deploy/middleware/security.py,sha256=LOZ-OUFo2dVhbRzI_KdSCMh4TItcJhhqzZg5zNAH-6Q,870
99
100
  deploy/middleware/session_timeout.py,sha256=Vfl6_9d8KwPsWRvCIcpBm7kWjgvHC8I7exJOejbyI4k,1023
@@ -106,11 +107,11 @@ deploy/static/robots.txt,sha256=5cS4RITuQhbpNzvpk4AyDCXdlIBfmfCoBYRvCHY2VT8,24
106
107
  deploy/templates/deploy/csrf_failure.html,sha256=-pBRPn4Y7nUdYHGpTHCokT9Boi-isuwuivF8V2K1SgM,412
107
108
  example_project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
109
  example_project/manage.py,sha256=EUgybZlZ7xk2Zf2KCwBbK_z7gf7Ifqs0_bl4Kijhdgo,242
109
- example_project/portal_test_settings.py,sha256=_Xrz5gtfZvHLybXOWPJGVaoOvtMT9BATJV6V6Rj0hDo,7256
110
- example_project/settings.py,sha256=8eEzp2qS3xvHOO0gcZCP7deSa1BW-8sTIA23eKPm3vA,5593
110
+ example_project/portal_test_settings.py,sha256=mTyObCGkZEI0IQSZkqCjb1WZ7ebjQLwuiT_SykRnP6g,7315
111
+ example_project/settings.py,sha256=pHQDI_A_yXV3u1efj689tc-vPI6nBFma4gMMPBzj0aI,5652
111
112
  example_project/urls.py,sha256=FUTzHPlUS1O5kqMHjL5V4L552N2ln7uTDXcw9wjKUto,422
112
113
  example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
113
- portal/__init__.py,sha256=gnc1sclqzDLnQB9vbqA0LgSMz4H-bYCuu--_P-HWhAc,22
114
+ portal/__init__.py,sha256=lPYx_JLWGM0F2xAcHXVLkIwicje2ZtdqEBMpuaNCsEU,22
114
115
  portal/admin.py,sha256=RKJizTF6dPJKmGPZw7nZUM0X8jkiTjgyKhLQxtvHJ0I,6148
115
116
  portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
116
117
  portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
@@ -118,7 +119,7 @@ portal/beta.py,sha256=0TCC-9_KZoM1nuzJ9FiuKR5n9JITdMYenHGQtRvn9UU,255
118
119
  portal/context_processors.py,sha256=1TrUZqnMqGa5f7ERph9EpBqojSMJvOrcpnJzTdeCLDI,133
119
120
  portal/handlers.py,sha256=gF99OfQrGcIGDnUyONhvylZNU8sl6XHYEurwu0fuiss,422
120
121
  portal/models.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
- portal/urls.py,sha256=pNOIcaNPxoPqrnIvF2BR_Mz0vdPyvU_vcAveX1AXwbM,18072
122
+ portal/urls.py,sha256=LFSumASmTGjFciMcc6OEFvJ1MWgFUS5wNRugGWON40E,18211
122
123
  portal/wsgi.py,sha256=3yRcNxBQG30NhzrVi93bX-DrbXtsIQBc70HiW5wbOyE,401
123
124
  portal/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
125
  portal/forms/admin.py,sha256=Cdl8-wvasAzvMfgUlFYzQjYeuyC7gIsSiy8V_-jMp7w,2080
@@ -128,7 +129,7 @@ portal/forms/invite_teacher.py,sha256=jkDNcCfkts4_lXRzhcI3xBam21Zn2yX9wMpMVhDtW1
128
129
  portal/forms/organisation.py,sha256=QcQyd7AiqBmvt4y8uQSQylguUbKOKqo2pjqWIkpWjDg,7433
129
130
  portal/forms/play.py,sha256=j_QYAKb4qyW0uy0VUUG49dmzDLINc3jR6ddK-djrbc4,11523
130
131
  portal/forms/registration.py,sha256=a-TuzikRc0Q-BAYs3rJ3Sz1wmQ1o_rTEtZmWdF7-xss,6008
131
- portal/forms/teach.py,sha256=wVwHP2odgMmEGGbbPQzak_1tqutcr1GWZcadvC1Bffg,21739
132
+ portal/forms/teach.py,sha256=c0t9XLfQJFd8hDWbnMUGX15Nt_XDXFG2BfwAKizE-Uw,22381
132
133
  portal/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
133
134
  portal/helpers/captcha.py,sha256=Amwg3HZ9eIh1LGYVYWYruk1ccNj6P3nYP_evufOY8BY,254
134
135
  portal/helpers/decorators.py,sha256=Bs6AVCvcgxfHLdJVWzTmZpxlYbJZXJh5e9AGRXf7cwo,3617
@@ -432,6 +433,7 @@ portal/templates/404.html,sha256=Tk6HmuzDdIT4ojoIHvH2MibU_0OekU5gmuJmk5M4K_Q,563
432
433
  portal/templates/500.html,sha256=aqJfDXPzaEw9K6LToPpE4rARuunLSxiIrJ_GnuJr8pI,1703
433
434
  portal/templates/email.html,sha256=MXB64zc1Sd34eIq8mGT1HhrjAiZUNvRx0_XjZllfKUU,268
434
435
  portal/templates/email.txt,sha256=z3bkT2WnkCrVa1RLVbGd-pE81cLEHlZ_QowfbSQAOvg,19
436
+ portal/templates/maintenance.html,sha256=RmPSkcTt9Vs6nGsIK9Q9rMyMAICqbaqMql4FmwL6Rak,1599
435
437
  portal/templates/django_recaptcha/widget_v2_invisible.html,sha256=3t5JHgyr_so5FQEUtbq501kEjz80KYBOoVz3PuU1JOc,318
436
438
  portal/templates/django_recaptcha/includes/js_v2_invisible.html,sha256=QQnBzZBqdtPeJeYFOIihJM18YoSUWbsGjuoMy-5gxNM,1408
437
439
  portal/templates/portal/about.html,sha256=_iD0GCP6q3-XuZ2LC-9O0KYY-mKL6c9qk3O-NRRqsRM,10321
@@ -490,7 +492,7 @@ portal/templates/portal/tag_manager/tag_manager_body.html,sha256=M_c9T2cfmVm6_Gj
490
492
  portal/templates/portal/tag_manager/tag_manager_head.html,sha256=kWQ4ccJ062cWRJOcfTNaWYTxCmzDsB9JD5v_YdyO5Ic,1288
491
493
  portal/templates/portal/teach/base_registering.html,sha256=jpANyRQbsmWO404l9Mez91zolNP9ic1khWi27WW0FMQ,582
492
494
  portal/templates/portal/teach/class.html,sha256=zir7a7y4hbg9E6-zFIC0iv8kccIzF-qkni4DXlvkjgM,6726
493
- portal/templates/portal/teach/dashboard.html,sha256=SwNdLbTDPaz0O7wVlSVkU8KwIWPzBYsOo6ysOxkOwOc,32674
495
+ portal/templates/portal/teach/dashboard.html,sha256=DcY6rcUjAT9h6VbSIA3mq4fyCIATIlWYDH2qMU1LySg,32697
494
496
  portal/templates/portal/teach/invited.html,sha256=lTsydONG5se1E099KaRgsxGuG12qVHxFUL2X0E3HBmQ,4188
495
497
  portal/templates/portal/teach/onboarding_classes.html,sha256=K212dunXG7eByyCg5lhv4ne-SniMz3kcKXrfianIY6g,2872
496
498
  portal/templates/portal/teach/onboarding_print.html,sha256=4vD2ZDNRxERNdCNj3ZNXJWYAFBQPn9C7Pzsz5TZjZHw,8862
@@ -535,7 +537,7 @@ portal/tests/test_2FA.py,sha256=0N4C9Ab3TvO9W__oQLCo-fLDH1Ho3CiGGsSg-2TiZUE,3597
535
537
  portal/tests/test_admin.py,sha256=AM2dgv8j9m4L-SDO-sMA9tQvQH9GwRBrlwRG9OgqtfI,1451
536
538
  portal/tests/test_api.py,sha256=Yo5s_nEGOoG35jA39yZ6nuDOUZvuCZ8o8o8XhZos61w,13819
537
539
  portal/tests/test_captcha_forms.py,sha256=Yn_VYO_6jbq6AeKeLcv-YFL1YwXZpU0C3y7SK8fRUm4,1033
538
- portal/tests/test_class.py,sha256=MfR8fRsi0XjqS5cbeV19y3Be2RVhOLUHsAy_mjm7P70,17644
540
+ portal/tests/test_class.py,sha256=_P2CEtqH67MM9h6MMQB_PxXFyQj4tZZbN42NJQpIJ7o,18308
539
541
  portal/tests/test_emails.py,sha256=pLr06j3uMBxP1raoZQWzUTBVFvsEDFtUh85J8OnqCwE,9238
540
542
  portal/tests/test_global_forms.py,sha256=GIm_oSN4VsfaO--E2SMRu8CwVraan0UBj-_LE_tu8w0,833
541
543
  portal/tests/test_helper_methods.py,sha256=-SQCDZm2XUtyXGEp0CHIb_SSC9CPD-XOSnpnY8QclHk,890
@@ -632,8 +634,8 @@ portal/views/two_factor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
632
634
  portal/views/two_factor/core.py,sha256=Lk32z2SN2Pg0rRkK-N-LXMvXC1kKKsH3l692kiSDQ4E,964
633
635
  portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
634
636
  portal/views/two_factor/profile.py,sha256=SHSg_xHccE5PtD-OfuOkYhREYz_er4bj5ro1RjJ88Yw,393
635
- codeforlife_portal-8.1.3.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
636
- codeforlife_portal-8.1.3.dist-info/METADATA,sha256=WDrFE-Tgdzw0QFNII4sEzxhnay313FCTlhPVMrByFes,3077
637
- codeforlife_portal-8.1.3.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
638
- codeforlife_portal-8.1.3.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
639
- codeforlife_portal-8.1.3.dist-info/RECORD,,
637
+ codeforlife_portal-8.2.1.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
638
+ codeforlife_portal-8.2.1.dist-info/METADATA,sha256=x6DvD4-jLnlOAwIbP6k0mLhRatr4zoTaZMtTpmsCZOQ,3077
639
+ codeforlife_portal-8.2.1.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
640
+ codeforlife_portal-8.2.1.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
641
+ codeforlife_portal-8.2.1.dist-info/RECORD,,
@@ -0,0 +1,25 @@
1
+ from django.http import HttpResponseRedirect
2
+ from django.urls import reverse, reverse_lazy
3
+
4
+
5
+ class MaintenanceMiddleware(object):
6
+ """
7
+ This middleware allows us to turn on "Maintenance Mode". Toggle `MAINTENANCE_MODE` to True in
8
+ `process_view` to redirect all requests in the app to the maintenance holding page.
9
+ """
10
+
11
+ def __init__(self, get_response):
12
+ self.get_response = get_response
13
+
14
+ def __call__(self, request):
15
+ response = self.get_response(request)
16
+ return response
17
+
18
+ def process_view(self, request, callback, callback_args, callback_kwargs):
19
+ MAINTENANCE_MODE = False
20
+
21
+ if MAINTENANCE_MODE and not request.path.startswith(reverse("maintenance")):
22
+ return HttpResponseRedirect(reverse_lazy("maintenance"))
23
+
24
+ if not MAINTENANCE_MODE and request.path.startswith(reverse("maintenance")):
25
+ return HttpResponseRedirect(reverse_lazy("home"))
@@ -157,6 +157,7 @@ MIDDLEWARE = [
157
157
  "preventconcurrentlogins.middleware.PreventConcurrentLoginsMiddleware",
158
158
  "csp.middleware.CSPMiddleware",
159
159
  "deploy.middleware.screentime_warning.ScreentimeWarningMiddleware",
160
+ "deploy.middleware.maintenance.MaintenanceMiddleware",
160
161
  ]
161
162
 
162
163
  TEMPLATES = [
@@ -115,6 +115,7 @@ MIDDLEWARE = [
115
115
  "preventconcurrentlogins.middleware.PreventConcurrentLoginsMiddleware",
116
116
  "csp.middleware.CSPMiddleware",
117
117
  "deploy.middleware.screentime_warning.ScreentimeWarningMiddleware",
118
+ "deploy.middleware.maintenance.MaintenanceMiddleware",
118
119
  ]
119
120
 
120
121
  TEMPLATES = [
portal/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "8.1.3"
1
+ __version__ = "8.2.1"
portal/forms/teach.py CHANGED
@@ -234,6 +234,16 @@ class ClassCreationForm(forms.Form):
234
234
 
235
235
  self.fields["teacher"].choices = teacher_choices
236
236
 
237
+ def clean(self):
238
+ name = self.cleaned_data.get("class_name", "")
239
+
240
+ if re.match(re.compile("^[\w -]+$"), name) is None:
241
+ raise forms.ValidationError(
242
+ "Class name may only contain letters, numbers, dashes, underscores, and spaces."
243
+ )
244
+
245
+ return self.cleaned_data
246
+
237
247
 
238
248
  class ClassEditForm(forms.Form):
239
249
  # select dropdown choices for potentially limiting time in which external students may join
@@ -288,6 +298,16 @@ class ClassEditForm(forms.Form):
288
298
  widget=forms.Select(),
289
299
  )
290
300
 
301
+ def clean(self):
302
+ name = self.cleaned_data.get("name", "")
303
+
304
+ if re.match(re.compile("^[\w -]+$"), name) is None:
305
+ raise forms.ValidationError(
306
+ "Class name may only contain letters, numbers, dashes, underscores, and spaces."
307
+ )
308
+
309
+ return self.cleaned_data
310
+
291
311
 
292
312
  class ClassLevelControlForm(forms.Form):
293
313
  def __init__(self, *args, **kwargs):
@@ -0,0 +1,34 @@
1
+ {% load static %}
2
+ {% load app_tags %}
3
+ <!DOCTYPE html>
4
+ <html>
5
+ <head>
6
+ <title>Code For Life - maintenance</title>
7
+ <link rel="stylesheet" type="text/css" href="{% static 'portal.css' %}">
8
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500&display=swap" rel="stylesheet">
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
10
+ <link rel="shortcut icon" href="{% static 'portal/img/favicon.ico' %}" type="image/x-icon">
11
+ <link rel="icon" href="{% static 'portal/img/favicon.ico' %}" type="image/x-icon">
12
+ </head>
13
+ <body>
14
+ <div class="content-footer-wrapper">
15
+ <div id="contentWrapper">
16
+ {% block topBar %}
17
+ {% include 'portal/partials/header.html' %}
18
+ {% endblock topBar %}
19
+ <div class="content">
20
+ <div class="error-page background container">
21
+ <div class="row mx-0 d-flex justify-content-between">
22
+ <div class="flex-grow-1">
23
+ <h2>Works in progress!</h2>
24
+ <h5>Apologies! Dee is working on something important.</h5>
25
+ <p>The website is temporarily unavailable.</p>
26
+ </div>
27
+ <img title="Dee" alt="Dee" src="{% static 'portal/img/dee.png' %}"/>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </body>
34
+ </html>
@@ -364,7 +364,7 @@
364
364
  </p>
365
365
  {% endif %}
366
366
 
367
- <form autocomplete="off" method="post">
367
+ <form id="form-create-class" autocomplete="off" method="post">
368
368
 
369
369
  {% csrf_token %}
370
370
 
@@ -15,6 +15,7 @@ from django.urls import reverse
15
15
  from game.models import Level
16
16
 
17
17
  from .base_test import BaseTest
18
+ from .pageObjects.portal.home_page import HomePage
18
19
  from .pageObjects.portal.teach.class_page import TeachClassPage
19
20
  from .utils.classes import create_class
20
21
  from .utils.messages import is_class_created_message_showing
@@ -537,3 +538,23 @@ class TestClassFrontend(BaseTest):
537
538
  page, class_name_3 = create_class(page)
538
539
 
539
540
  assert is_class_created_message_showing(self.selenium, class_name_3)
541
+
542
+ def test_create_invalid_name(self):
543
+ email, password = signup_teacher_directly()
544
+ create_organisation_directly(email)
545
+
546
+ class_name = "Class!"
547
+
548
+ self.selenium.get(self.live_server_url)
549
+ page = (
550
+ HomePage(self.selenium)
551
+ .go_to_teacher_login_page()
552
+ .login_no_class(email, password)
553
+ .open_classes_tab()
554
+ )
555
+
556
+ page = page.create_class(class_name, False)
557
+
558
+ assert page.was_form_invalid(
559
+ "form-create-class", "Class name may only contain letters, numbers, dashes, underscores, and spaces."
560
+ )
portal/urls.py CHANGED
@@ -527,4 +527,9 @@ urlpatterns = [
527
527
  name="remove_fake_accounts",
528
528
  ),
529
529
  re_path(r"^celebrate/", ten_year_map_page, name="celebrate"),
530
+ re_path(
531
+ r"^maintenance/$",
532
+ TemplateView.as_view(template_name="maintenance.html"),
533
+ name="maintenance",
534
+ ),
530
535
  ]