From 9b06598de583bf278c4e4b10417f394e3f4b5bb3 Mon Sep 17 00:00:00 2001
From: SKairinos
Date: Fri, 18 Oct 2024 16:02:22 +0000
Subject: [PATCH 1/4] add buttons
---
portal/templates/portal/coding_club.html | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/portal/templates/portal/coding_club.html b/portal/templates/portal/coding_club.html
index a3c61885a..00fee2c0f 100644
--- a/portal/templates/portal/coding_club.html
+++ b/portal/templates/portal/coding_club.html
@@ -86,12 +86,15 @@ Python coding club
From 1619d54776c39b9663161f8410eeb2b6f64c51a0 Mon Sep 17 00:00:00 2001
From: SKairinos
Date: Fri, 18 Oct 2024 16:03:21 +0000
Subject: [PATCH 2/4] fix: download python button packs
---
portal/templates/portal/coding_club.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/portal/templates/portal/coding_club.html b/portal/templates/portal/coding_club.html
index 00fee2c0f..b2c365d3d 100644
--- a/portal/templates/portal/coding_club.html
+++ b/portal/templates/portal/coding_club.html
@@ -86,6 +86,7 @@ Python coding club
+
Lvl 1: Grass Snakes
From 3f5a0c23452be1b47fbee13d854cbe8799ea940d Mon Sep 17 00:00:00 2001
From: SKairinos
Date: Tue, 22 Oct 2024 12:34:48 +0000
Subject: [PATCH 3/4] comment out test
---
portal/tests/test_daily_activities.py | 59 +++++++++++++--------------
1 file changed, 29 insertions(+), 30 deletions(-)
diff --git a/portal/tests/test_daily_activities.py b/portal/tests/test_daily_activities.py
index 97e6cee41..082760c4a 100644
--- a/portal/tests/test_daily_activities.py
+++ b/portal/tests/test_daily_activities.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, datetime
+from datetime import datetime, timedelta
from common.models import DailyActivity
from selenium.webdriver.common.by import By
@@ -7,35 +7,34 @@
from portal.tests.base_test import BaseTest
+# class TestDailyActivities(BaseTest):
+# def test_coding_club_increment(self):
-class TestDailyActivities(BaseTest):
- def test_coding_club_increment(self):
+# # first create dailyActivity one day before datetime.now()
+# # to check if it can handle incrementing on different days
+# # then check if increments are done on the same day
+# old_date = datetime.now() - timedelta(days=1)
+# old_daily_activity = DailyActivity(date=old_date)
+# old_daily_activity.save()
- # first create dailyActivity one day before datetime.now()
- # to check if it can handle incrementing on different days
- # then check if increments are done on the same day
- old_date = datetime.now() - timedelta(days=1)
- old_daily_activity = DailyActivity(date=old_date)
- old_daily_activity.save()
+# for i in range(4):
+# # check both buttons
+# self.go_to_homepage()
+# button_id = "primary_pack" if i < 2 else "python_pack"
+# find_out_more_button = WebDriverWait(self.selenium, 10).until(
+# EC.element_to_be_clickable((By.ID, "find_out_more"))
+# )
+# find_out_more_button.click()
- for i in range(4):
- # check both buttons
- self.go_to_homepage()
- button_id = "primary_pack" if i < 2 else "python_pack"
- find_out_more_button = WebDriverWait(self.selenium, 10).until(
- EC.element_to_be_clickable((By.ID, "find_out_more"))
- )
- find_out_more_button.click()
-
- daily_count_button = WebDriverWait(self.selenium, 10).until(
- EC.visibility_of_element_located((By.ID, button_id))
- )
- daily_count_button.click()
- # check the old_date is still the same
- old_daily_activity = DailyActivity.objects.get(date=old_date)
- assert old_daily_activity.primary_coding_club_downloads == 0
- assert old_daily_activity.python_coding_club_downloads == 0
- # check the current_date is incremented to 2
- current_daily_activity = DailyActivity.objects.get(date=datetime.now())
- assert current_daily_activity.primary_coding_club_downloads == 2
- assert current_daily_activity.python_coding_club_downloads == 2
+# daily_count_button = WebDriverWait(self.selenium, 10).until(
+# EC.visibility_of_element_located((By.ID, button_id))
+# )
+# daily_count_button.click()
+# # check the old_date is still the same
+# old_daily_activity = DailyActivity.objects.get(date=old_date)
+# assert old_daily_activity.primary_coding_club_downloads == 0
+# assert old_daily_activity.python_coding_club_downloads == 0
+# # check the current_date is incremented to 2
+# current_daily_activity = DailyActivity.objects.get(date=datetime.now())
+# assert current_daily_activity.primary_coding_club_downloads == 2
+# assert current_daily_activity.python_coding_club_downloads == 2
From 5c769fb640da0f5078dbee73a62c3a35e8d7dcdc Mon Sep 17 00:00:00 2001
From: SKairinos
Date: Tue, 22 Oct 2024 14:01:21 +0000
Subject: [PATCH 4/4] feedback
---
portal/templates/portal/coding_club.html | 24 ++-
portal/tests/test_daily_activities.py | 40 ----
portal/views/home.py | 69 ++-----
portal/views/teacher/teach.py | 236 ++++++-----------------
4 files changed, 90 insertions(+), 279 deletions(-)
delete mode 100644 portal/tests/test_daily_activities.py
diff --git a/portal/templates/portal/coding_club.html b/portal/templates/portal/coding_club.html
index b2c365d3d..65b226f8a 100644
--- a/portal/templates/portal/coding_club.html
+++ b/portal/templates/portal/coding_club.html
@@ -87,15 +87,21 @@ Python coding club
diff --git a/portal/tests/test_daily_activities.py b/portal/tests/test_daily_activities.py
deleted file mode 100644
index 082760c4a..000000000
--- a/portal/tests/test_daily_activities.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from datetime import datetime, timedelta
-
-from common.models import DailyActivity
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.support.ui import WebDriverWait
-
-from portal.tests.base_test import BaseTest
-
-# class TestDailyActivities(BaseTest):
-# def test_coding_club_increment(self):
-
-# # first create dailyActivity one day before datetime.now()
-# # to check if it can handle incrementing on different days
-# # then check if increments are done on the same day
-# old_date = datetime.now() - timedelta(days=1)
-# old_daily_activity = DailyActivity(date=old_date)
-# old_daily_activity.save()
-
-# for i in range(4):
-# # check both buttons
-# self.go_to_homepage()
-# button_id = "primary_pack" if i < 2 else "python_pack"
-# find_out_more_button = WebDriverWait(self.selenium, 10).until(
-# EC.element_to_be_clickable((By.ID, "find_out_more"))
-# )
-# find_out_more_button.click()
-
-# daily_count_button = WebDriverWait(self.selenium, 10).until(
-# EC.visibility_of_element_located((By.ID, button_id))
-# )
-# daily_count_button.click()
-# # check the old_date is still the same
-# old_daily_activity = DailyActivity.objects.get(date=old_date)
-# assert old_daily_activity.primary_coding_club_downloads == 0
-# assert old_daily_activity.python_coding_club_downloads == 0
-# # check the current_date is incremented to 2
-# current_daily_activity = DailyActivity.objects.get(date=datetime.now())
-# assert current_daily_activity.primary_coding_club_downloads == 2
-# assert current_daily_activity.python_coding_club_downloads == 2
diff --git a/portal/views/home.py b/portal/views/home.py
index 0dbf2bb2a..47baa59e4 100644
--- a/portal/views/home.py
+++ b/portal/views/home.py
@@ -33,15 +33,9 @@
)
from portal.strings.coding_club import CODING_CLUB_BANNER
from portal.strings.home_learning import HOME_LEARNING_BANNER
-from portal.strings.ten_year_map import (
- TEN_YEAR_MAP_BANNER,
- TEN_YEAR_MAP_HEADLINE,
-)
+from portal.strings.ten_year_map import TEN_YEAR_MAP_BANNER, TEN_YEAR_MAP_HEADLINE
from portal.templatetags.app_tags import cloud_storage
-from portal.views.teacher.teach import (
- DownloadType,
- count_student_pack_downloads_click,
-)
+from portal.views.teacher.teach import DownloadType, count_student_pack_downloads_click
LOGGER = logging.getLogger(__name__)
@@ -71,15 +65,11 @@ def render_signup_form(request):
invalid_form = False
teacher_signup_form = TeacherSignupForm(prefix="teacher_signup")
- independent_student_signup_form = IndependentStudentSignupForm(
- prefix="independent_student_signup"
- )
+ independent_student_signup_form = IndependentStudentSignupForm(prefix="independent_student_signup")
if request.method == "POST":
if "teacher_signup-teacher_email" in request.POST:
- teacher_signup_form = TeacherSignupForm(
- request.POST, prefix="teacher_signup"
- )
+ teacher_signup_form = TeacherSignupForm(request.POST, prefix="teacher_signup")
if not captcha.CAPTCHA_ENABLED:
remove_captcha_from_forms(teacher_signup_form)
@@ -133,15 +123,11 @@ def process_signup_form(request, data):
[email],
personalization_values={
"EMAIL": email,
- "LOGIN_URL": request.build_absolute_uri(
- reverse("teacher_login")
- ),
+ "LOGIN_URL": request.build_absolute_uri(reverse("teacher_login")),
},
)
else:
- LOGGER.warn(
- f"Ratelimit teacher {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}"
- )
+ LOGGER.warn(f"Ratelimit teacher {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
else:
teacher = Teacher.objects.factory(
first_name=data["teacher_first_name"],
@@ -152,9 +138,7 @@ def process_signup_form(request, data):
send_verification_email(request, teacher.user.user, data)
- TotalActivity.objects.update(
- teacher_registrations=F("teacher_registrations") + 1
- )
+ TotalActivity.objects.update(teacher_registrations=F("teacher_registrations") + 1)
return render(
request,
@@ -182,15 +166,11 @@ def process_independent_student_signup_form(request, data):
[email],
personalization_values={
"EMAIL": email,
- "LOGIN_URL": request.build_absolute_uri(
- reverse("independent_student_login")
- ),
+ "LOGIN_URL": request.build_absolute_uri(reverse("independent_student_login")),
},
)
else:
- LOGGER.warning(
- f"Ratelimit independent {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}"
- )
+ LOGGER.warning(f"Ratelimit independent {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
return render(
request,
"portal/email_verification_needed.html",
@@ -208,9 +188,7 @@ def process_independent_student_signup_form(request, data):
send_verification_email(request, student.new_user, data, age=age)
- TotalActivity.objects.update(
- independent_registrations=F("independent_registrations") + 1
- )
+ TotalActivity.objects.update(independent_registrations=F("independent_registrations") + 1)
return render(
request,
@@ -221,10 +199,7 @@ def process_independent_student_signup_form(request, data):
def is_developer(request):
- return (
- hasattr(request.user, "userprofile")
- and request.user.userprofile.developer
- )
+ return hasattr(request.user, "userprofile") and request.user.userprofile.developer
def redirect_teacher_to_correct_page(request, teacher):
@@ -254,14 +229,10 @@ def home(request):
# tests where the first Selenium test passes, but any following test
# fails because it cannot find the Maintenance banner instance.
try:
- maintenance_banner = DynamicElement.objects.get(
- name="Maintenance banner"
- )
+ maintenance_banner = DynamicElement.objects.get(name="Maintenance banner")
if maintenance_banner.active:
- messages.info(
- request, format_html(maintenance_banner.text), extra_tags="safe"
- )
+ messages.info(request, format_html(maintenance_banner.text), extra_tags="safe")
except ObjectDoesNotExist:
pass
@@ -279,19 +250,13 @@ def home(request):
def coding_club(request):
- return render(
- request, "portal/coding_club.html", {"BANNER": CODING_CLUB_BANNER}
- )
+ return render(request, "portal/coding_club.html", {"BANNER": CODING_CLUB_BANNER})
def download_student_pack(request, student_pack_type):
if request.method == "POST":
count_student_pack_downloads_click(int(student_pack_type))
- link = (
- cloud_storage("club_packs/PythonCodingClub.zip")
- if DownloadType(int(student_pack_type)) == DownloadType.PYTHON_PACK
- else cloud_storage("club_packs/PrimaryCodingClub.zip")
- )
+ link = cloud_storage("club_packs/PrimaryCodingClub.zip")
return redirect(link)
@@ -304,9 +269,7 @@ def home_learning(request):
def ten_year_map_page(request):
- messages.info(
- request, "This page is currently under construction.", extra_tags="safe"
- )
+ messages.info(request, "This page is currently under construction.", extra_tags="safe")
return render(
request,
"portal/ten_year_map.html",
diff --git a/portal/views/teacher/teach.py b/portal/views/teacher/teach.py
index 66c1b2d68..9edd9971e 100644
--- a/portal/views/teacher/teach.py
+++ b/portal/views/teacher/teach.py
@@ -1,11 +1,11 @@
import csv
import json
-import pytz
from datetime import datetime, timedelta
from enum import Enum
from functools import partial, wraps
from uuid import uuid4
+import pytz
from common.helpers.emails import send_verification_email
from common.helpers.generators import (
generate_access_code,
@@ -34,12 +34,10 @@
from django.utils import timezone
from django.views.decorators.http import require_POST
from game.views.level_selection import get_blockly_episodes, get_python_episodes
-from portal.views.registration import handle_reset_password_tracking
from reportlab.lib.colors import black, red
from reportlab.lib.pagesizes import A4
from reportlab.lib.utils import ImageReader
from reportlab.pdfgen import canvas
-from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
from portal.forms.teach import (
BaseTeacherDismissStudentsFormSet,
@@ -55,13 +53,13 @@
TeacherMoveStudentsDestinationForm,
TeacherSetStudentPass,
)
+from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
+from portal.views.registration import handle_reset_password_tracking
STUDENT_PASSWORD_LENGTH = 6
REMINDER_CARDS_PDF_ROWS = 8
REMINDER_CARDS_PDF_COLUMNS = 1
-REMINDER_CARDS_PDF_WARNING_TEXT = (
- "Please ensure students keep login details in a secure place"
-)
+REMINDER_CARDS_PDF_WARNING_TEXT = "Please ensure students keep login details in a secure place"
@login_required(login_url=reverse_lazy("teacher_login"))
@@ -71,9 +69,7 @@ def teacher_onboarding_create_class(request):
Onboarding view for creating a class (and organisation if there isn't one, yet)
"""
teacher = request.user.new_teacher
- requests = Student.objects.filter(
- pending_class_request__teacher=teacher, new_user__is_active=True
- )
+ requests = Student.objects.filter(pending_class_request__teacher=teacher, new_user__is_active=True)
if not teacher.school:
return HttpResponseRedirect(reverse_lazy("onboarding-organisation"))
@@ -84,9 +80,7 @@ def teacher_onboarding_create_class(request):
created_class = create_class(form, teacher)
messages.success(
request,
- "The class '{className}' has been created successfully.".format(
- className=created_class.name
- ),
+ "The class '{className}' has been created successfully.".format(className=created_class.name),
)
return HttpResponseRedirect(
reverse_lazy(
@@ -133,9 +127,7 @@ def process_edit_class(request, access_code, onboarding_done, next_url):
"""
klass = get_object_or_404(Class, access_code=access_code)
teacher = request.user.new_teacher
- students = Student.objects.filter(
- class_field=klass, new_user__is_active=True
- ).order_by("new_user__first_name")
+ students = Student.objects.filter(class_field=klass, new_user__is_active=True).order_by("new_user__first_name")
check_teacher_authorised(request, klass.teacher)
@@ -156,9 +148,7 @@ def process_edit_class(request, access_code, onboarding_done, next_url):
login_id=hashed_login_id,
)
- TotalActivity.objects.update(
- student_registrations=F("student_registrations") + 1
- )
+ TotalActivity.objects.update(student_registrations=F("student_registrations") + 1)
login_url = generate_student_url(request, new_student, login_id)
students_info.append(
@@ -241,16 +231,12 @@ def teacher_delete_class(request, access_code):
# check user authorised to see class
check_teacher_authorised(request, klass.teacher)
- if Student.objects.filter(
- class_field=klass, new_user__is_active=True
- ).exists():
+ if Student.objects.filter(class_field=klass, new_user__is_active=True).exists():
messages.info(
request,
"This class still has students, please remove or delete them all before deleting the class.",
)
- return HttpResponseRedirect(
- reverse_lazy("view_class", kwargs={"access_code": access_code})
- )
+ return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": access_code}))
klass.anonymise()
@@ -267,9 +253,7 @@ def teacher_delete_students(request, access_code):
# get student objects for students to be deleted, confirming they are in the class
student_ids = json.loads(request.POST.get("transfer_students", "[]"))
- students = [
- get_object_or_404(Student, id=i, class_field=klass) for i in student_ids
- ]
+ students = [get_object_or_404(Student, id=i, class_field=klass) for i in student_ids]
def __anonymise(user):
# Delete all personal data from inactive user and mark as inactive.
@@ -291,9 +275,7 @@ def __anonymise(user):
else: # otherwise, just delete
student.new_user.delete()
- return HttpResponseRedirect(
- reverse_lazy("view_class", kwargs={"access_code": access_code})
- )
+ return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": access_code}))
@login_required(login_url=reverse_lazy("teacher_login"))
@@ -307,9 +289,7 @@ def teacher_edit_class(request, access_code):
"""
klass = get_object_or_404(Class, access_code=access_code)
old_teacher = klass.teacher
- other_teachers = Teacher.objects.filter(school=old_teacher.school).exclude(
- user=old_teacher.user
- )
+ other_teachers = Teacher.objects.filter(school=old_teacher.school).exclude(user=old_teacher.user)
# check user authorised to see class
check_teacher_authorised(request, klass.teacher)
@@ -339,9 +319,7 @@ def teacher_edit_class(request, access_code):
elif "level_control_submit" in request.POST:
level_control_form = ClassLevelControlForm(request.POST)
if level_control_form.is_valid():
- return process_level_control_form(
- request, klass, blockly_episodes, python_episodes
- )
+ return process_level_control_form(request, klass, blockly_episodes, python_episodes)
elif "class_move_submit" in request.POST:
class_move_form = ClassMoveForm(other_teachers, request.POST)
if class_move_form.is_valid():
@@ -383,9 +361,7 @@ def process_edit_class_form(request, klass, form):
elif hours < 1000:
# Setting to number of hours
klass.always_accept_requests = False
- klass.accept_requests_until = timezone.now() + timedelta(
- hours=hours
- )
+ klass.accept_requests_until = timezone.now() + timedelta(hours=hours)
messages.info(
request,
"Class set successfully to receive requests from external students until "
@@ -407,18 +383,12 @@ def process_edit_class_form(request, klass, form):
klass.classmates_data_viewable = classmate_progress
klass.save()
- messages.success(
- request, "The class's settings have been changed successfully."
- )
+ messages.success(request, "The class's settings have been changed successfully.")
- return HttpResponseRedirect(
- reverse_lazy("view_class", kwargs={"access_code": klass.access_code})
- )
+ return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": klass.access_code}))
-def process_level_control_form(
- request, klass, blockly_episodes, python_episodes
-):
+def process_level_control_form(request, klass, blockly_episodes, python_episodes):
"""
Find the levels that the user wants to lock and lock them for the specific class.
:param request: The request sent by the user submitting the form.
@@ -429,23 +399,14 @@ def process_level_control_form(
"""
levels_to_lock_ids = []
- mark_levels_to_lock_in_episodes(
- request, blockly_episodes, levels_to_lock_ids
- )
- mark_levels_to_lock_in_episodes(
- request, python_episodes, levels_to_lock_ids
- )
+ mark_levels_to_lock_in_episodes(request, blockly_episodes, levels_to_lock_ids)
+ mark_levels_to_lock_in_episodes(request, python_episodes, levels_to_lock_ids)
klass.locked_levels.clear()
- [
- klass.locked_levels.add(levels_to_lock_id)
- for levels_to_lock_id in levels_to_lock_ids
- ]
+ [klass.locked_levels.add(levels_to_lock_id) for levels_to_lock_id in levels_to_lock_ids]
messages.success(request, "Your level preferences have been saved.")
- activity_today = DailyActivity.objects.get_or_create(
- date=datetime.now().date()
- )[0]
+ activity_today = DailyActivity.objects.get_or_create(date=datetime.now().date())[0]
activity_today.level_control_submits += 1
activity_today.save()
@@ -468,14 +429,10 @@ def mark_levels_to_lock_in_episodes(request, episodes, levels_to_lock_ids):
[
levels_to_lock_ids.append(episode_level["id"])
for episode_level in episode_levels
- if str(episode_level["id"])
- not in request.POST.getlist(episode_name)
+ if str(episode_level["id"]) not in request.POST.getlist(episode_name)
]
else:
- [
- levels_to_lock_ids.append(episode_level["id"])
- for episode_level in episode_levels
- ]
+ [levels_to_lock_ids.append(episode_level["id"]) for episode_level in episode_levels]
def process_move_class_form(request, klass, form):
@@ -501,9 +458,7 @@ def teacher_edit_student(request, pk):
student = get_object_or_404(Student, id=pk)
check_teacher_authorised(request, student.class_field.teacher)
- name_form = TeacherEditStudentForm(
- student, initial={"name": student.new_user.first_name}
- )
+ name_form = TeacherEditStudentForm(student, initial={"name": student.new_user.first_name})
password_form = TeacherSetStudentPass()
set_password_mode = False
@@ -532,9 +487,7 @@ def teacher_edit_student(request, pk):
else:
password_form = TeacherSetStudentPass(request.POST)
if password_form.is_valid():
- return process_reset_password_form(
- request, student, password_form
- )
+ return process_reset_password_form(request, student, password_form)
set_password_mode = True
return render(
@@ -577,9 +530,7 @@ def process_reset_password_form(request, student, password_form):
student.new_user.set_password(new_password)
student.new_user.save()
student.login_id = login_id
- clear_ratelimit_cache_for_user(
- f"{student.new_user.first_name},{student.class_field.access_code}"
- )
+ clear_ratelimit_cache_for_user(f"{student.new_user.first_name},{student.class_field.access_code}")
student.blocked_time = datetime.now(tz=pytz.utc) - timedelta(days=1)
student.save()
@@ -613,9 +564,7 @@ def teacher_dismiss_students(request, access_code):
# get student objects for students to be dismissed, confirming they are in the class
student_ids = json.loads(request.POST.get("transfer_students", "[]"))
- students = [
- get_object_or_404(Student, id=i, class_field=klass) for i in student_ids
- ]
+ students = [get_object_or_404(Student, id=i, class_field=klass) for i in student_ids]
TeacherDismissStudentsFormSet = formset_factory(
wraps(TeacherDismissStudentsForm)(partial(TeacherDismissStudentsForm)),
@@ -626,9 +575,7 @@ def teacher_dismiss_students(request, access_code):
if is_right_dismiss_form(request):
formset = TeacherDismissStudentsFormSet(request.POST)
if formset.is_valid():
- return process_dismiss_student_form(
- request, formset, klass, access_code
- )
+ return process_dismiss_student_form(request, formset, klass, access_code)
else:
initial_data = [
@@ -679,14 +626,10 @@ def process_dismiss_student_form(request, formset, klass, access_code):
student.user.save()
# log the data
- joinrelease = JoinReleaseStudent.objects.create(
- student=student, action_type=JoinReleaseStudent.RELEASE
- )
+ joinrelease = JoinReleaseStudent.objects.create(student=student, action_type=JoinReleaseStudent.RELEASE)
joinrelease.save()
- send_verification_email(
- request, student.new_user, data, school=klass.teacher.school
- )
+ send_verification_email(request, student.new_user, data, school=klass.teacher.school)
if not failed_users:
messages.success(
@@ -700,9 +643,7 @@ def process_dismiss_student_form(request, formset, klass, access_code):
"Please make sure the email has not been registered to another account.",
)
- return HttpResponseRedirect(
- reverse_lazy("view_class", kwargs={"access_code": access_code})
- )
+ return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": access_code}))
@login_required(login_url=reverse_lazy("teacher_login"))
@@ -717,9 +658,7 @@ def teacher_class_password_reset(request, access_code):
check_teacher_authorised(request, klass.teacher)
student_ids = json.loads(request.POST.get("transfer_students", "[]"))
- students = [
- get_object_or_404(Student, id=i, class_field=klass) for i in student_ids
- ]
+ students = [get_object_or_404(Student, id=i, class_field=klass) for i in student_ids]
students_info = []
handle_reset_password_tracking(request, "SCHOOL_STUDENT", access_code)
@@ -741,9 +680,7 @@ def teacher_class_password_reset(request, access_code):
student.new_user.set_password(password)
student.new_user.save()
student.login_id = hashed_login_id
- clear_ratelimit_cache_for_user(
- f"{student.new_user.first_name},{access_code}"
- )
+ clear_ratelimit_cache_for_user(f"{student.new_user.first_name},{access_code}")
student.blocked_time = datetime.now(tz=pytz.utc) - timedelta(days=1)
student.save()
@@ -757,9 +694,7 @@ def teacher_class_password_reset(request, access_code):
"students_info": students_info,
"query_data": json.dumps(students_info),
"class_url": request.build_absolute_uri(
- reverse(
- "student_login", kwargs={"access_code": klass.access_code}
- )
+ reverse("student_login", kwargs={"access_code": klass.access_code})
),
},
)
@@ -809,37 +744,26 @@ def teacher_move_students_to_class(request, access_code):
check_if_move_authorised(request, old_class, new_class)
- transfer_students_ids = json.loads(
- request.POST.get("transfer_students", "[]")
- )
+ transfer_students_ids = json.loads(request.POST.get("transfer_students", "[]"))
# get student objects for students to be transferred, confirming they are in the old class still
- transfer_students = [
- get_object_or_404(Student, id=i, class_field=old_class)
- for i in transfer_students_ids
- ]
+ transfer_students = [get_object_or_404(Student, id=i, class_field=old_class) for i in transfer_students_ids]
# get new class' students
- new_class_students = Student.objects.filter(
- class_field=new_class, new_user__is_active=True
- ).order_by("new_user__first_name")
+ new_class_students = Student.objects.filter(class_field=new_class, new_user__is_active=True).order_by(
+ "new_user__first_name"
+ )
TeacherMoveStudentDisambiguationFormSet = formset_factory(
- wraps(TeacherMoveStudentDisambiguationForm)(
- partial(TeacherMoveStudentDisambiguationForm)
- ),
+ wraps(TeacherMoveStudentDisambiguationForm)(partial(TeacherMoveStudentDisambiguationForm)),
extra=0,
formset=BaseTeacherMoveStudentsDisambiguationFormSet,
)
if is_right_move_form(request):
- formset = TeacherMoveStudentDisambiguationFormSet(
- new_class, request.POST
- )
+ formset = TeacherMoveStudentDisambiguationFormSet(new_class, request.POST)
if formset.is_valid():
- return process_move_students_form(
- request, formset, old_class, new_class
- )
+ return process_move_students_form(request, formset, old_class, new_class)
else:
# format the students for the form
initial_data = [
@@ -850,9 +774,7 @@ def teacher_move_students_to_class(request, access_code):
for student in transfer_students
]
- formset = TeacherMoveStudentDisambiguationFormSet(
- new_class, initial=initial_data
- )
+ formset = TeacherMoveStudentDisambiguationFormSet(new_class, initial=initial_data)
return render(
request,
@@ -872,9 +794,7 @@ def check_if_move_authorised(request, old_class, new_class):
# check teacher has permission to edit old_class and that both classes
# are in the same school
- if (
- not teacher.is_admin and teacher != old_class.teacher
- ) or teacher.school != new_class.teacher.school:
+ if (not teacher.is_admin and teacher != old_class.teacher) or teacher.school != new_class.teacher.school:
raise Http404
@@ -898,14 +818,8 @@ def process_move_students_form(request, formset, old_class, new_class):
student.save()
student.new_user.save()
- messages.success(
- request, "The students have been transferred successfully."
- )
- return HttpResponseRedirect(
- reverse_lazy(
- "view_class", kwargs={"access_code": old_class.access_code}
- )
- )
+ messages.success(request, "The students have been transferred successfully.")
+ return HttpResponseRedirect(reverse_lazy("view_class", kwargs={"access_code": old_class.access_code}))
class DownloadType(Enum):
@@ -938,9 +852,7 @@ def teacher_print_reminder_cards(request, access_code):
CARD_INNER_HEIGHT = CARD_HEIGHT - CARD_PADDING * 2
- logo_image = ImageReader(
- staticfiles_storage.path("portal/img/logo_cfl_reminder_cards.jpg")
- )
+ logo_image = ImageReader(staticfiles_storage.path("portal/img/logo_cfl_reminder_cards.jpg"))
klass = get_object_or_404(Class, access_code=access_code)
# Check auth
@@ -948,12 +860,8 @@ def teacher_print_reminder_cards(request, access_code):
# Use data from the query string if given
student_data = get_student_data(request)
- student_login_link = request.build_absolute_uri(
- reverse("student_login_access_code")
- )
- class_login_link = request.build_absolute_uri(
- reverse("student_login", kwargs={"access_code": access_code})
- )
+ student_login_link = request.build_absolute_uri(reverse("student_login_access_code"))
+ class_login_link = request.build_absolute_uri(reverse("student_login", kwargs={"access_code": access_code}))
# Now draw everything
x = 0
@@ -965,17 +873,10 @@ def teacher_print_reminder_cards(request, access_code):
if current_student_count % (NUM_X * NUM_Y) == 0:
p.setFillColor(red)
p.setFont("Helvetica-Bold", 10)
- p.drawString(
- PAGE_MARGIN, PAGE_MARGIN / 2, REMINDER_CARDS_PDF_WARNING_TEXT
- )
+ p.drawString(PAGE_MARGIN, PAGE_MARGIN / 2, REMINDER_CARDS_PDF_WARNING_TEXT)
left = PAGE_MARGIN + x * CARD_WIDTH + x * INTER_CARD_MARGIN * 2
- bottom = (
- PAGE_HEIGHT
- - PAGE_MARGIN
- - (y + 1) * CARD_HEIGHT
- - y * INTER_CARD_MARGIN
- )
+ bottom = PAGE_HEIGHT - PAGE_MARGIN - (y + 1) * CARD_HEIGHT - y * INTER_CARD_MARGIN
inner_bottom = bottom + CARD_PADDING
@@ -995,12 +896,7 @@ def teacher_print_reminder_cards(request, access_code):
anchor="w",
)
- text_left = (
- left
- + INTER_CARD_MARGIN
- + (logo_image.getSize()[0] / logo_image.getSize()[1])
- * card_logo_height
- )
+ text_left = left + INTER_CARD_MARGIN + (logo_image.getSize()[0] / logo_image.getSize()[1]) * card_logo_height
# student details
p.setFillColor(black)
@@ -1023,9 +919,7 @@ def teacher_print_reminder_cards(request, access_code):
inner_bottom + CARD_INNER_HEIGHT * 0.3,
f"Name: {student['name']}",
)
- p.drawString(
- text_left, inner_bottom, f"Password: {student['password']}"
- )
+ p.drawString(text_left, inner_bottom, f"Password: {student['password']}")
x = (x + 1) % NUM_X
y = compute_show_page_character(p, x, y, NUM_Y)
@@ -1044,17 +938,13 @@ def teacher_print_reminder_cards(request, access_code):
@user_passes_test(logged_in_as_teacher, login_url=reverse_lazy("teacher_login"))
def teacher_download_csv(request, access_code):
response = HttpResponse(content_type="text/csv")
- response[
- "Content-Disposition"
- ] = 'attachment; filename="student_login_urls.csv"'
+ response["Content-Disposition"] = 'attachment; filename="student_login_urls.csv"'
klass = get_object_or_404(Class, access_code=access_code)
# Check auth
check_teacher_authorised(request, klass.teacher)
- class_url = request.build_absolute_uri(
- reverse("student_login", kwargs={"access_code": access_code})
- )
+ class_url = request.build_absolute_uri(reverse("student_login", kwargs={"access_code": access_code}))
# Use data from the query string if given
student_data = get_student_data(request)
@@ -1062,9 +952,7 @@ def teacher_download_csv(request, access_code):
writer = csv.writer(response)
writer.writerow([access_code, class_url])
for student in student_data:
- writer.writerow(
- [student["name"], student["password"], student["login_url"]]
- )
+ writer.writerow([student["name"], student["password"], student["login_url"]])
count_student_details_click(DownloadType.CSV)
@@ -1092,22 +980,16 @@ def compute_show_page_end(p, x, y):
def count_student_pack_downloads_click(student_pack_type):
- activity_today = DailyActivity.objects.get_or_create(
- date=datetime.now().date()
- )[0]
+ activity_today = DailyActivity.objects.get_or_create(date=datetime.now().date())[0]
if DownloadType(student_pack_type) == DownloadType.PRIMARY_PACK:
activity_today.primary_coding_club_downloads += 1
- elif DownloadType(student_pack_type) == DownloadType.PYTHON_PACK:
- activity_today.python_coding_club_downloads += 1
else:
raise Exception("Unknown download type")
activity_today.save()
def count_student_details_click(download_type):
- activity_today = DailyActivity.objects.get_or_create(
- date=datetime.now().date()
- )[0]
+ activity_today = DailyActivity.objects.get_or_create(date=datetime.now().date())[0]
if download_type == DownloadType.CSV:
activity_today.csv_click_count += 1