codeforlife-portal 8.6.2__py2.py3-none-any.whl → 8.6.4__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.4
2
2
  Name: codeforlife-portal
3
- Version: 8.6.2
3
+ Version: 8.6.4
4
4
  Classifier: Programming Language :: Python
5
5
  Classifier: Programming Language :: Python :: 3.12
6
6
  Classifier: Framework :: Django
@@ -8,7 +8,7 @@ Description-Content-Type: text/markdown
8
8
  License-File: LICENSE.md
9
9
  Requires-Dist: asgiref==3.8.1; python_version >= "3.8"
10
10
  Requires-Dist: certifi==2025.1.31; python_version >= "3.6"
11
- Requires-Dist: cfl-common==8.6.2
11
+ Requires-Dist: cfl-common==8.6.4
12
12
  Requires-Dist: chardet==5.2.0; python_version >= "3.7"
13
13
  Requires-Dist: charset-normalizer==3.4.1; python_version >= "3.7"
14
14
  Requires-Dist: diff-match-patch==20241021; python_version >= "3.7"
@@ -27,7 +27,7 @@ Requires-Dist: django-recaptcha==4.0.0
27
27
  Requires-Dist: django-sekizai==4.1.0; python_version >= "3.8"
28
28
  Requires-Dist: django-treebeard==4.7.1; python_version >= "3.8"
29
29
  Requires-Dist: django-two-factor-auth==1.17.0; python_version >= "3.8"
30
- Requires-Dist: djangorestframework==3.15.2; python_version >= "3.8"
30
+ Requires-Dist: djangorestframework==3.16.0; python_version >= "3.9"
31
31
  Requires-Dist: idna==3.10; python_version >= "3.6"
32
32
  Requires-Dist: importlib-metadata==4.13.0; python_version >= "3.7"
33
33
  Requires-Dist: libsass==0.23.0; python_version >= "3.8"
@@ -49,37 +49,68 @@ Requires-Dist: setuptools==78.1.0; python_version >= "3.9"
49
49
  Requires-Dist: six==1.17.0; python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3"
50
50
  Requires-Dist: sqlparse==0.5.3; python_version >= "3.8"
51
51
  Requires-Dist: tablib==3.7.0; python_version >= "3.9"
52
- Requires-Dist: typing-extensions==4.13.0; python_version >= "3.8"
52
+ Requires-Dist: typing-extensions==4.13.1; python_version >= "3.8"
53
53
  Requires-Dist: tzdata==2025.2; python_version >= "2"
54
54
  Requires-Dist: urllib3==2.3.0; python_version >= "3.9"
55
55
  Requires-Dist: wheel==0.45.1; python_version >= "3.8"
56
56
  Requires-Dist: zipp==3.21.0; python_version >= "3.9"
57
57
  Provides-Extra: dev
58
58
  Requires-Dist: asgiref==3.8.1; python_version >= "3.8" and extra == "dev"
59
+ Requires-Dist: asttokens==3.0.0; python_version >= "3.8" and extra == "dev"
59
60
  Requires-Dist: attrs==25.3.0; python_version >= "3.8" and extra == "dev"
60
61
  Requires-Dist: black==25.1.0; python_version >= "3.9" and extra == "dev"
61
62
  Requires-Dist: certifi==2025.1.31; python_version >= "3.6" and extra == "dev"
63
+ Requires-Dist: cfl-common==8.6.4; extra == "dev"
62
64
  Requires-Dist: charset-normalizer==3.4.1; python_version >= "3.7" and extra == "dev"
63
65
  Requires-Dist: click==8.1.8; python_version >= "3.7" and extra == "dev"
64
66
  Requires-Dist: coverage[toml]==7.8.0; python_version >= "3.9" and extra == "dev"
67
+ Requires-Dist: decorator==5.2.1; python_version >= "3.8" and extra == "dev"
68
+ Requires-Dist: diff-match-patch==20241021; python_version >= "3.7" and extra == "dev"
65
69
  Requires-Dist: django==5.1.8; python_version >= "3.10" and extra == "dev"
70
+ Requires-Dist: django-countries==7.6.1; extra == "dev"
71
+ Requires-Dist: django-csp==3.8; extra == "dev"
72
+ Requires-Dist: django-formtools==2.5.1; python_version >= "3.8" and extra == "dev"
73
+ Requires-Dist: django-import-export==4.2.0; python_version >= "3.9" and extra == "dev"
74
+ Requires-Dist: django-otp==1.6.0; python_version >= "3.7" and extra == "dev"
75
+ Requires-Dist: django-phonenumber-field==8.0.0; python_version >= "3.8" and extra == "dev"
76
+ Requires-Dist: django-pipeline==4.0.0; python_version >= "3.9" and extra == "dev"
66
77
  Requires-Dist: django-reverse-js==0.1.7; python_version >= "3.10" and extra == "dev"
67
78
  Requires-Dist: django-selenium-clean==1.0.1; extra == "dev"
68
79
  Requires-Dist: django-test-migrations==1.4.0; (python_version >= "3.9" and python_version < "4.0") and extra == "dev"
80
+ Requires-Dist: django-two-factor-auth==1.17.0; python_version >= "3.8" and extra == "dev"
81
+ Requires-Dist: djangorestframework==3.16.0; python_version >= "3.9" and extra == "dev"
69
82
  Requires-Dist: execnet==2.1.1; python_version >= "3.8" and extra == "dev"
83
+ Requires-Dist: executing==2.2.0; python_version >= "3.8" and extra == "dev"
70
84
  Requires-Dist: fastdiff==0.3.0; extra == "dev"
71
85
  Requires-Dist: h11==0.14.0; python_version >= "3.7" and extra == "dev"
72
86
  Requires-Dist: idna==3.10; python_version >= "3.6" and extra == "dev"
73
87
  Requires-Dist: iniconfig==2.1.0; python_version >= "3.8" and extra == "dev"
88
+ Requires-Dist: ipython==9.0.2; python_version >= "3.11" and extra == "dev"
89
+ Requires-Dist: ipython-pygments-lexers==1.1.1; python_version >= "3.8" and extra == "dev"
74
90
  Requires-Dist: isort==6.0.1; python_full_version >= "3.9.0" and extra == "dev"
91
+ Requires-Dist: jedi==0.19.2; python_version >= "3.6" and extra == "dev"
92
+ Requires-Dist: libsass==0.23.0; python_version >= "3.8" and extra == "dev"
93
+ Requires-Dist: matplotlib-inline==0.1.7; python_version >= "3.8" and extra == "dev"
94
+ Requires-Dist: more-itertools==8.7.0; python_version >= "3.5" and extra == "dev"
75
95
  Requires-Dist: mypy-extensions==1.0.0; python_version >= "3.5" and extra == "dev"
96
+ Requires-Dist: numpy==2.2.4; python_version >= "3.10" and extra == "dev"
76
97
  Requires-Dist: outcome==1.3.0.post0; python_version >= "3.7" and extra == "dev"
77
98
  Requires-Dist: packaging==24.2; python_version >= "3.8" and extra == "dev"
99
+ Requires-Dist: pandas==2.2.3; python_version >= "3.9" and extra == "dev"
100
+ Requires-Dist: parso==0.8.4; python_version >= "3.6" and extra == "dev"
78
101
  Requires-Dist: pathspec==0.12.1; python_version >= "3.8" and extra == "dev"
102
+ Requires-Dist: pexpect==4.9.0; (sys_platform != "win32" and sys_platform != "emscripten") and extra == "dev"
103
+ Requires-Dist: pgeocode==0.4.0; python_version >= "3.8" and extra == "dev"
79
104
  Requires-Dist: platformdirs==4.3.7; python_version >= "3.9" and extra == "dev"
80
105
  Requires-Dist: pluggy==1.5.0; python_version >= "3.8" and extra == "dev"
106
+ Requires-Dist: prompt-toolkit==3.0.50; python_full_version >= "3.8.0" and extra == "dev"
107
+ Requires-Dist: ptyprocess==0.7.0; extra == "dev"
108
+ Requires-Dist: pure-eval==0.2.3; extra == "dev"
109
+ Requires-Dist: pygments==2.19.1; python_version >= "3.8" and extra == "dev"
81
110
  Requires-Dist: pyhamcrest==2.0.2; python_version >= "3.5" and extra == "dev"
111
+ Requires-Dist: pyjwt==2.6.0; python_version >= "3.7" and extra == "dev"
82
112
  Requires-Dist: pypdf==5.1.0; python_version >= "3.8" and extra == "dev"
113
+ Requires-Dist: pypng==0.20220715.0; extra == "dev"
83
114
  Requires-Dist: pysocks==1.7.1; extra == "dev"
84
115
  Requires-Dist: pytest==8.3.5; python_version >= "3.8" and extra == "dev"
85
116
  Requires-Dist: pytest-cov==6.1.0; python_version >= "3.9" and extra == "dev"
@@ -87,23 +118,34 @@ Requires-Dist: pytest-django==4.8.0; python_version >= "3.8" and extra == "dev"
87
118
  Requires-Dist: pytest-mock==3.14.0; python_version >= "3.8" and extra == "dev"
88
119
  Requires-Dist: pytest-order==1.3.0; python_version >= "3.7" and extra == "dev"
89
120
  Requires-Dist: pytest-xdist==3.6.1; python_version >= "3.8" and extra == "dev"
121
+ Requires-Dist: python-dateutil==2.9.0.post0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3") and extra == "dev"
122
+ Requires-Dist: pytz==2025.2; extra == "dev"
90
123
  Requires-Dist: pyvirtualdisplay==3.0; extra == "dev"
91
- Requires-Dist: rapid-router==7.3.6; extra == "dev"
124
+ Requires-Dist: qrcode==7.4.2; python_version >= "3.7" and extra == "dev"
125
+ Requires-Dist: rapid-router==7.5.1; extra == "dev"
92
126
  Requires-Dist: requests==2.32.3; python_version >= "3.8" and extra == "dev"
93
127
  Requires-Dist: responses==0.18.0; python_version >= "3.7" and extra == "dev"
94
128
  Requires-Dist: selenium==4.29.0; python_version >= "3.9" and extra == "dev"
129
+ Requires-Dist: setuptools==78.1.0; python_version >= "3.9" and extra == "dev"
130
+ Requires-Dist: six==1.17.0; (python_version >= "2.7" and python_version not in "3.0, 3.1, 3.2, 3.3") and extra == "dev"
95
131
  Requires-Dist: snapshottest==1.0.0a1; extra == "dev"
96
132
  Requires-Dist: sniffio==1.3.1; python_version >= "3.7" and extra == "dev"
97
133
  Requires-Dist: sortedcontainers==2.4.0; extra == "dev"
98
134
  Requires-Dist: sqlparse==0.5.3; python_version >= "3.8" and extra == "dev"
135
+ Requires-Dist: stack-data==0.6.3; extra == "dev"
136
+ Requires-Dist: tablib==3.7.0; python_version >= "3.9" and extra == "dev"
99
137
  Requires-Dist: termcolor==3.0.1; python_version >= "3.9" and extra == "dev"
138
+ Requires-Dist: traitlets==5.14.3; python_version >= "3.8" and extra == "dev"
100
139
  Requires-Dist: trio==0.29.0; python_version >= "3.9" and extra == "dev"
101
140
  Requires-Dist: trio-websocket==0.12.2; python_version >= "3.8" and extra == "dev"
102
- Requires-Dist: typing-extensions==4.13.0; python_version >= "3.8" and extra == "dev"
141
+ Requires-Dist: typing-extensions==4.13.1; python_version >= "3.8" and extra == "dev"
142
+ Requires-Dist: tzdata==2025.2; python_version >= "2" and extra == "dev"
103
143
  Requires-Dist: urllib3==2.3.0; python_version >= "3.9" and extra == "dev"
104
144
  Requires-Dist: wasmer==1.1.0; extra == "dev"
105
145
  Requires-Dist: wasmer-compiler-cranelift==1.1.0; extra == "dev"
146
+ Requires-Dist: wcwidth==0.2.13; extra == "dev"
106
147
  Requires-Dist: websocket-client==1.8.0; python_version >= "3.8" and extra == "dev"
148
+ Requires-Dist: wheel==0.45.1; python_version >= "3.8" and extra == "dev"
107
149
  Requires-Dist: wsproto==1.2.0; python_full_version >= "3.7.0" and extra == "dev"
108
150
  Dynamic: classifier
109
151
  Dynamic: description
@@ -87,7 +87,7 @@ cfl_common/common/tests/utils/organisation.py,sha256=vNgKFtU3VPcWRnZfh82yCS90PLA
87
87
  cfl_common/common/tests/utils/student.py,sha256=PLd980iSlxmMoB8J3C2pVjNC5xHdVxfAkJXzhv_dRhg,3814
88
88
  cfl_common/common/tests/utils/teacher.py,sha256=KQ_NAl4yQqiX_zwcULQjkovc29JPhnkLR5Nk3Ljzbpg,2661
89
89
  cfl_common/common/tests/utils/user.py,sha256=NvLzZLVP4jy5Hn1iztOYF_BTQ9WsbSmuWMEzGzhAsRU,919
90
- codeforlife_portal-8.6.2.dist-info/licenses/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
90
+ codeforlife_portal-8.6.4.dist-info/licenses/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
91
91
  deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
92
  deploy/captcha.py,sha256=MbOBuGnbT_SOIltSjP1XMOLrfo1DldCilaVAEim0vM4,23
93
93
  deploy/views.py,sha256=7mY2zNPkaBFrlWGByJHp2zFqHIHSMc0YArjE_sFWMMU,131
@@ -111,7 +111,7 @@ example_project/portal_test_settings.py,sha256=1eTweQoCt1okixE5eoEg-f9iX7idSLNdJ
111
111
  example_project/settings.py,sha256=YS-8YYtH8hZMUhZALA3eHJ1bdM2VJfpD1v3ItjBMGaQ,5936
112
112
  example_project/urls.py,sha256=FUTzHPlUS1O5kqMHjL5V4L552N2ln7uTDXcw9wjKUto,422
113
113
  example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
114
- portal/__init__.py,sha256=hcrlnXfppsJwYIQ7twFAMd9cmK-pVAsCRmoxmu3wdHw,22
114
+ portal/__init__.py,sha256=k1XSqRNf3b5rBrVKQzu8VQRZtnwbZ6aZjNyFBdwJEFo,22
115
115
  portal/admin.py,sha256=RKJizTF6dPJKmGPZw7nZUM0X8jkiTjgyKhLQxtvHJ0I,6148
116
116
  portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
117
117
  portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
@@ -609,11 +609,11 @@ portal/tests/utils/messages.py,sha256=tUGzJzhZwvzmO9H3CPxpWUfi2aXTpAWfkDQ2u2T3Lb
609
609
  portal/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
610
610
  portal/views/about.py,sha256=-muXy17UhxCSKkjnMAkSLXiCvT_pBPlf2ykTYr794dI,443
611
611
  portal/views/admin.py,sha256=4Xt3zEyQH7sUwQSrwuRtoCodWidjOzd7gJUwWU96pXY,957
612
- portal/views/api.py,sha256=mdWmFkV5mxmR-mvj6ttIe8uwW9tbcx9-5ykk5dpX0LI,7047
612
+ portal/views/api.py,sha256=ZCRApdZi2F6Pqo9p3V6cctzeeskxyrlFZn2AcHGpGdQ,6932
613
613
  portal/views/dotmailer.py,sha256=OH06IXuqqjhQbEie8g8y2ZY1oZvsCtNHhkQRLa-julg,2467
614
614
  portal/views/email.py,sha256=V3wXRxIjeZ4OJBVqGCQrPn-GQWKZK1PCXbR1f2Zpa_4,2174
615
615
  portal/views/google_analytics.py,sha256=cbNq9apCVpjoXCdovjrwo2jshWu5tUOItB-fTr-losw,769
616
- portal/views/home.py,sha256=8leK4ADxRg-gK-bm7D08CR44bhV3I8lt5pCV59HXMkk,9619
616
+ portal/views/home.py,sha256=puQesHCyV1jMXNjgflf_QhJl7hoV2Y4z9UlkGtEiqTo,9266
617
617
  portal/views/legal.py,sha256=USOEJy0Ry73cKReglKfMxgM3qWoKORUfVl_RkwPewQ4,342
618
618
  portal/views/organisation.py,sha256=sPDbiM7hdtpF8GKyh_4n4VPl2a-WnAgnF4q9aSvQCVI,3341
619
619
  portal/views/play_landing_page.py,sha256=FFmjUFub3ZdlbMqkB8yX3jAImCzqrUqgb8AZcpKywZ4,308
@@ -623,7 +623,7 @@ portal/views/cron/__init__.py,sha256=5rxXyhJmLOExRdrYZ1VJttTsyRIPRybzdftbUDwFByI
623
623
  portal/views/cron/user.py,sha256=iKM_FOcSQvrXtRSZUtxSiMFD3M869JP5jvEfRWHLpvM,10731
624
624
  portal/views/login/__init__.py,sha256=xSCtyFPSI87BRUybBgqa86ekFEolX5gUDbBSfBUMTyI,399
625
625
  portal/views/login/independent_student.py,sha256=3dFULhwMAlX4VDrJl-Znril6a9M5xKBSHO1eWvujfS0,2662
626
- portal/views/login/student.py,sha256=dt6cMfWepBJsVCRcADltfYSHVpyeP1WGLKSogMJ22E0,5539
626
+ portal/views/login/student.py,sha256=7UbJpjA4BsDY8bxGTFSdloNo50GbLiukaMr5rKvG6uo,5306
627
627
  portal/views/login/teacher.py,sha256=kRugP7TPbZIb_BmYMYxFeugxZy8UbCry_q0_jJDJ_Mw,1975
628
628
  portal/views/student/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
629
629
  portal/views/student/edit_account_details.py,sha256=Ba-3D_zzKbX5N01NG5qqBS0ud10B8D5SN8hOpLiGa9U,8468
@@ -635,7 +635,7 @@ portal/views/two_factor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
635
635
  portal/views/two_factor/core.py,sha256=Lk32z2SN2Pg0rRkK-N-LXMvXC1kKKsH3l692kiSDQ4E,964
636
636
  portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
637
637
  portal/views/two_factor/profile.py,sha256=SHSg_xHccE5PtD-OfuOkYhREYz_er4bj5ro1RjJ88Yw,393
638
- codeforlife_portal-8.6.2.dist-info/METADATA,sha256=kOFvRK_urBNoRSKyShwC_92noVBm-GAWKpOyJsBo7Hg,9176
639
- codeforlife_portal-8.6.2.dist-info/WHEEL,sha256=MAQBAzGbXNI3bUmkDsiV_duv8i-gcdnLzw7cfUFwqhU,109
640
- codeforlife_portal-8.6.2.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
641
- codeforlife_portal-8.6.2.dist-info/RECORD,,
638
+ codeforlife_portal-8.6.4.dist-info/METADATA,sha256=OboHurEZ4kEN13sGMjks_eb0AqI5bTTzgsuNtc4sdw8,12345
639
+ codeforlife_portal-8.6.4.dist-info/WHEEL,sha256=MAQBAzGbXNI3bUmkDsiV_duv8i-gcdnLzw7cfUFwqhU,109
640
+ codeforlife_portal-8.6.4.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
641
+ codeforlife_portal-8.6.4.dist-info/RECORD,,
portal/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "8.6.2"
1
+ __version__ = "8.6.4"
portal/views/api.py CHANGED
@@ -1,5 +1,4 @@
1
1
  import datetime
2
- import logging
3
2
  import uuid
4
3
 
5
4
  from common.models import Class, School, Student, Teacher, UserProfile
@@ -15,7 +14,6 @@ from rest_framework.reverse import reverse_lazy
15
14
 
16
15
  from portal.app_settings import IS_CLOUD_SCHEDULER_FUNCTION
17
16
 
18
- LOGGER = logging.getLogger(__name__)
19
17
  THREE_YEARS_IN_DAYS = 1095
20
18
 
21
19
 
@@ -199,7 +197,6 @@ class AnonymiseOrphanSchoolsView(generics.ListAPIView):
199
197
  pk__gte=start_id, new_user__is_active=False
200
198
  ):
201
199
  anonymise(teacher.new_user)
202
- LOGGER.info(f"Anonymised teacher ID {teacher.pk}")
203
200
 
204
201
  # Anonymise schools without any teachers
205
202
  for school in School.objects.filter(teacher_school__isnull=True):
portal/views/home.py CHANGED
@@ -1,4 +1,3 @@
1
- import logging
2
1
  import math
3
2
 
4
3
  from common.helpers.emails import (
@@ -36,8 +35,6 @@ from portal.strings.ten_year_map import (
36
35
  TEN_YEAR_MAP_HEADLINE,
37
36
  )
38
37
 
39
- LOGGER = logging.getLogger(__name__)
40
-
41
38
 
42
39
  def register_view(request):
43
40
  if request.user.is_authenticated:
@@ -131,10 +128,6 @@ def process_signup_form(request, data):
131
128
  ),
132
129
  },
133
130
  )
134
- else:
135
- LOGGER.warn(
136
- f"Ratelimit teacher {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}"
137
- )
138
131
  else:
139
132
  teacher = Teacher.objects.factory(
140
133
  first_name=data["teacher_first_name"],
@@ -180,10 +173,7 @@ def process_independent_student_signup_form(request, data):
180
173
  ),
181
174
  },
182
175
  )
183
- else:
184
- LOGGER.warning(
185
- f"Ratelimit independent {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}"
186
- )
176
+
187
177
  return render(
188
178
  request,
189
179
  "portal/email_verification_needed.html",
@@ -1,5 +1,3 @@
1
- import logging
2
-
3
1
  from common.models import UserSession, Student, Class
4
2
  from django.contrib import messages
5
3
  from django.contrib.auth import authenticate, login
@@ -14,8 +12,6 @@ from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
14
12
  from portal.helpers.request_handlers import get_access_code_from_request
15
13
  from portal.views.login import has_user_lockout_expired
16
14
 
17
- LOGGER = logging.getLogger(__name__)
18
-
19
15
 
20
16
  class StudentClassCodeView(FormView):
21
17
  template_name = "portal/login/student_class_code.html"
@@ -76,12 +72,7 @@ class StudentLoginView(LoginView):
76
72
  students = Student.objects.filter(
77
73
  new_user__first_name__iexact=name, class_field=klass
78
74
  )
79
- try:
80
- student = students[0]
81
- except IndexError:
82
- msg = f"Student {name} in class {class_code} is not found!"
83
- LOGGER.error(msg)
84
- raise Exception(msg)
75
+ student = students[0]
85
76
 
86
77
  # Log the login time, class, and login type
87
78
  session = UserSession(