codeforlife-portal 6.46.1__py2.py3-none-any.whl → 7.1.0__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/common/csp_config.py +0 -2
- cfl_common/common/mail.py +31 -6
- cfl_common/common/migrations/0005_add_worksheets.py +1 -5
- cfl_common/common/migrations/0007_add_pdf_names_to_first_two_worksheets.py +1 -5
- cfl_common/common/migrations/0054_delete_aimmo_models.py +20 -0
- cfl_common/common/models.py +0 -25
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/METADATA +3 -4
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/RECORD +44 -68
- example_project/portal_test_settings.py +0 -1
- example_project/settings.py +0 -1
- example_project/urls.py +0 -2
- portal/__init__.py +1 -1
- portal/static/portal/sass/partials/_banners.scss +0 -177
- portal/static/portal/sass/partials/_buttons.scss +0 -12
- portal/static/portal/sass/partials/_grids.scss +0 -53
- portal/static/portal/sass/partials/_text.scss +1 -10
- portal/static/portal/sass/styles.scss +0 -1
- portal/strings/play.py +1 -2
- portal/strings/teacher_resources.py +0 -10
- portal/templates/portal/about.html +91 -60
- portal/templates/portal/contribute.html +45 -49
- portal/templates/portal/partials/header.html +0 -12
- portal/templates/portal/play/independent_student_dashboard.html +12 -25
- portal/templates/portal/play/student_dashboard.html +16 -34
- portal/templates/portal/play.html +36 -49
- portal/templates/portal/register.html +1 -1
- portal/templates/portal/teach.html +37 -55
- portal/templates/portal/ten_year_map.html +9 -9
- portal/templatetags/app_tags.py +13 -28
- portal/tests/conftest.py +4 -16
- portal/tests/pageObjects/portal/base_page.py +20 -20
- portal/tests/snapshots/snap_test_partials.py +0 -452
- portal/tests/test_class.py +213 -45
- portal/tests/test_independent_student.py +0 -9
- portal/tests/test_partials.py +6 -56
- portal/tests/test_teacher.py +221 -285
- portal/tests/test_views.py +257 -73
- portal/urls.py +38 -20
- portal/views/cron/user.py +158 -15
- portal/views/student/play.py +36 -25
- portal/views/teacher/teach.py +0 -5
- cfl_common/common/tests/test_migration_aimmo_characters.py +0 -29
- portal/forms/add_game.py +0 -29
- portal/static/portal/img/kurono_hero.jpg +0 -0
- portal/static/portal/img/kurono_landing_hero.png +0 -0
- portal/static/portal/img/kurono_logo.svg +0 -1
- portal/static/portal/img/kurono_logo_grey_background.svg +0 -1
- portal/static/portal/img/kurono_logo_mark.svg +0 -1
- portal/static/portal/img/kurono_resources_hero.jpg +0 -0
- portal/static/portal/img/kurono_story.png +0 -0
- portal/static/portal/img/thumbnail_educate_kurono.png +0 -0
- portal/static/portal/img/thumbnail_kurono_resources.png +0 -0
- portal/static/portal/img/thumbnail_play_kurono.png +0 -0
- portal/static/portal/js/aimmoGame.js +0 -106
- portal/static/portal/sass/partials/_videos.scss +0 -10
- portal/static/portal/video/aimmo_play_now_background_video.mp4 +0 -0
- portal/strings/student_aimmo_dashboard.py +0 -6
- portal/templates/portal/partials/aimmo_games_table.html +0 -89
- portal/templates/portal/play/student_aimmo_dashboard.html +0 -46
- portal/templates/portal/teach/teacher_aimmo_dashboard.html +0 -95
- portal/templatetags/character_list_tags.py +0 -16
- portal/tests/pageObjects/portal/kurono_teacher_dashboard_page.py +0 -49
- portal/tests/test_aimmo_dashboards.py +0 -206
- portal/tests/utils/aimmo_games.py +0 -30
- portal/views/aimmo/__init__.py +0 -0
- portal/views/aimmo/dashboard.py +0 -105
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/WHEEL +0 -0
- {codeforlife_portal-6.46.1.dist-info → codeforlife_portal-7.1.0.dist-info}/top_level.txt +0 -0
portal/tests/test_views.py
CHANGED
|
@@ -6,7 +6,6 @@ from unittest.mock import ANY, Mock, patch
|
|
|
6
6
|
|
|
7
7
|
import PyPDF2
|
|
8
8
|
import pytest
|
|
9
|
-
from aimmo.models import Game
|
|
10
9
|
from common.models import (
|
|
11
10
|
Class,
|
|
12
11
|
DailyActivity,
|
|
@@ -17,6 +16,7 @@ from common.models import (
|
|
|
17
16
|
UserProfile,
|
|
18
17
|
UserSession,
|
|
19
18
|
)
|
|
19
|
+
from common.mail import campaign_ids
|
|
20
20
|
from common.tests.utils.classes import create_class_directly
|
|
21
21
|
from common.tests.utils.organisation import (
|
|
22
22
|
create_organisation_directly,
|
|
@@ -55,7 +55,9 @@ class TestTeacherViews(TestCase):
|
|
|
55
55
|
cls.email, cls.password = signup_teacher_directly()
|
|
56
56
|
cls.school = create_organisation_directly(cls.email)
|
|
57
57
|
_, _, cls.class_access_code = create_class_directly(cls.email)
|
|
58
|
-
_, cls.password_student, cls.student = create_school_student_directly(
|
|
58
|
+
_, cls.password_student, cls.student = create_school_student_directly(
|
|
59
|
+
cls.class_access_code
|
|
60
|
+
)
|
|
59
61
|
|
|
60
62
|
def login(self):
|
|
61
63
|
c = Client()
|
|
@@ -64,7 +66,9 @@ class TestTeacherViews(TestCase):
|
|
|
64
66
|
|
|
65
67
|
def test_reminder_cards(self):
|
|
66
68
|
c = self.login()
|
|
67
|
-
url = reverse(
|
|
69
|
+
url = reverse(
|
|
70
|
+
"teacher_print_reminder_cards", args=[self.class_access_code]
|
|
71
|
+
)
|
|
68
72
|
|
|
69
73
|
# First test with 2 dummy students
|
|
70
74
|
NAME1 = "Test name"
|
|
@@ -98,7 +102,9 @@ class TestTeacherViews(TestCase):
|
|
|
98
102
|
# page number
|
|
99
103
|
students_per_page = REMINDER_CARDS_PDF_ROWS * REMINDER_CARDS_PDF_COLUMNS
|
|
100
104
|
for _ in range(len(studentlist), students_per_page + 1):
|
|
101
|
-
studentlist.append(
|
|
105
|
+
studentlist.append(
|
|
106
|
+
{"name": NAME1, "password": PASSWORD1, "login_url": URL}
|
|
107
|
+
)
|
|
102
108
|
|
|
103
109
|
assert len(studentlist) == students_per_page + 1
|
|
104
110
|
|
|
@@ -137,7 +143,9 @@ class TestTeacherViews(TestCase):
|
|
|
137
143
|
reader = csv.reader(io.StringIO(content))
|
|
138
144
|
|
|
139
145
|
access_code = self.class_access_code
|
|
140
|
-
class_url = reverse(
|
|
146
|
+
class_url = reverse(
|
|
147
|
+
"student_login", kwargs={"access_code": access_code}
|
|
148
|
+
)
|
|
141
149
|
row0 = next(reader)
|
|
142
150
|
assert row0[0].strip() == access_code
|
|
143
151
|
assert class_url in row0[1].strip()
|
|
@@ -176,7 +184,9 @@ class TestTeacherViews(TestCase):
|
|
|
176
184
|
|
|
177
185
|
def test_daily_activity_student_details(self):
|
|
178
186
|
c = self.login()
|
|
179
|
-
url = reverse(
|
|
187
|
+
url = reverse(
|
|
188
|
+
"teacher_print_reminder_cards", args=[self.class_access_code]
|
|
189
|
+
)
|
|
180
190
|
|
|
181
191
|
data = {
|
|
182
192
|
"data": json.dumps(
|
|
@@ -224,7 +234,9 @@ class TestTeacherViews(TestCase):
|
|
|
224
234
|
|
|
225
235
|
def test_release_verified_student(self):
|
|
226
236
|
c = Client()
|
|
227
|
-
student_login_url = reverse(
|
|
237
|
+
student_login_url = reverse(
|
|
238
|
+
"student_login", args=[self.class_access_code]
|
|
239
|
+
)
|
|
228
240
|
response = c.post(
|
|
229
241
|
student_login_url,
|
|
230
242
|
{
|
|
@@ -240,7 +252,9 @@ class TestTeacherViews(TestCase):
|
|
|
240
252
|
c.logout()
|
|
241
253
|
c.login(username=self.email, password=self.password)
|
|
242
254
|
|
|
243
|
-
release_url = reverse(
|
|
255
|
+
release_url = reverse(
|
|
256
|
+
"teacher_dismiss_students", args=[self.class_access_code]
|
|
257
|
+
)
|
|
244
258
|
response = c.post(
|
|
245
259
|
release_url,
|
|
246
260
|
{
|
|
@@ -277,7 +291,9 @@ class TestLoginViews(TestCase):
|
|
|
277
291
|
teacher_email, teacher_password = signup_teacher_directly()
|
|
278
292
|
create_organisation_directly(teacher_email)
|
|
279
293
|
_, _, class_access_code = create_class_directly(teacher_email)
|
|
280
|
-
student_name, student_password, _ = create_school_student_directly(
|
|
294
|
+
student_name, student_password, _ = create_school_student_directly(
|
|
295
|
+
class_access_code
|
|
296
|
+
)
|
|
281
297
|
|
|
282
298
|
return (
|
|
283
299
|
teacher_email,
|
|
@@ -310,9 +326,16 @@ class TestLoginViews(TestCase):
|
|
|
310
326
|
_, _, name, password, class_access_code = self._set_up_test_data()
|
|
311
327
|
|
|
312
328
|
if next_url:
|
|
313
|
-
url =
|
|
329
|
+
url = (
|
|
330
|
+
reverse(
|
|
331
|
+
"student_login", kwargs={"access_code": class_access_code}
|
|
332
|
+
)
|
|
333
|
+
+ "?next=/"
|
|
334
|
+
)
|
|
314
335
|
else:
|
|
315
|
-
url = reverse(
|
|
336
|
+
url = reverse(
|
|
337
|
+
"student_login", kwargs={"access_code": class_access_code}
|
|
338
|
+
)
|
|
316
339
|
|
|
317
340
|
c = Client()
|
|
318
341
|
response = c.post(url, {"username": name, "password": password})
|
|
@@ -351,7 +374,9 @@ class TestLoginViews(TestCase):
|
|
|
351
374
|
|
|
352
375
|
def _get_user_class(self, name, class_access_code):
|
|
353
376
|
klass = Class.objects.get(access_code=class_access_code)
|
|
354
|
-
students = Student.objects.filter(
|
|
377
|
+
students = Student.objects.filter(
|
|
378
|
+
new_user__first_name__iexact=name, class_field=klass
|
|
379
|
+
)
|
|
355
380
|
assert len(students) == 1
|
|
356
381
|
user = students[0].new_user
|
|
357
382
|
return user, klass
|
|
@@ -393,7 +418,9 @@ class TestLoginViews(TestCase):
|
|
|
393
418
|
_, _, name, password, class_access_code = self._set_up_test_data()
|
|
394
419
|
|
|
395
420
|
c = Client()
|
|
396
|
-
url = reverse(
|
|
421
|
+
url = reverse(
|
|
422
|
+
"student_login", kwargs={"access_code": class_access_code}
|
|
423
|
+
)
|
|
397
424
|
c.post(url, {"username": name, "password": password})
|
|
398
425
|
|
|
399
426
|
# check if there's a UserSession data within the last 10 secs
|
|
@@ -414,7 +441,9 @@ class TestLoginViews(TestCase):
|
|
|
414
441
|
randomname = "randomname"
|
|
415
442
|
|
|
416
443
|
c = Client()
|
|
417
|
-
url = reverse(
|
|
444
|
+
url = reverse(
|
|
445
|
+
"student_login", kwargs={"access_code": class_access_code}
|
|
446
|
+
)
|
|
418
447
|
c.post(url, {"username": randomname, "password": "xx"})
|
|
419
448
|
|
|
420
449
|
# check if there's a UserSession data within the last 10 secs
|
|
@@ -440,7 +469,9 @@ class TestLoginViews(TestCase):
|
|
|
440
469
|
|
|
441
470
|
def test_student_direct_login(self):
|
|
442
471
|
_, _, _, _, class_access_code = self._set_up_test_data()
|
|
443
|
-
student, login_id, _, _ = create_student_with_direct_login(
|
|
472
|
+
student, login_id, _, _ = create_student_with_direct_login(
|
|
473
|
+
class_access_code
|
|
474
|
+
)
|
|
444
475
|
|
|
445
476
|
c = Client()
|
|
446
477
|
assert c.login(user_id=student.new_user.id, login_id=login_id) == True
|
|
@@ -543,7 +574,8 @@ class TestViews(TestCase):
|
|
|
543
574
|
"total_available_score": 2040,
|
|
544
575
|
}
|
|
545
576
|
|
|
546
|
-
# Expected context data when a student has also attempted some custom RR
|
|
577
|
+
# Expected context data when a student has also attempted some custom RR
|
|
578
|
+
# levels
|
|
547
579
|
EXPECTED_DATA_WITH_CUSTOM_ATTEMPTS = {
|
|
548
580
|
"num_completed": 2,
|
|
549
581
|
"num_top_scores": 1,
|
|
@@ -553,22 +585,12 @@ class TestViews(TestCase):
|
|
|
553
585
|
"total_custom_available_score": 20,
|
|
554
586
|
}
|
|
555
587
|
|
|
556
|
-
# Expected context data when a student also has access to a Kurono game
|
|
557
|
-
EXPECTED_DATA_WITH_KURONO_GAME = {
|
|
558
|
-
"num_completed": 2,
|
|
559
|
-
"num_top_scores": 1,
|
|
560
|
-
"total_score": 39,
|
|
561
|
-
"total_available_score": 2040,
|
|
562
|
-
"total_custom_score": 10,
|
|
563
|
-
"total_custom_available_score": 20,
|
|
564
|
-
"worksheet_id": 3,
|
|
565
|
-
"worksheet_image": "images/worksheets/ancient.jpg",
|
|
566
|
-
}
|
|
567
|
-
|
|
568
588
|
c = Client()
|
|
569
589
|
|
|
570
590
|
# Login and check initial data
|
|
571
|
-
url = reverse(
|
|
591
|
+
url = reverse(
|
|
592
|
+
"student_login", kwargs={"access_code": class_access_code}
|
|
593
|
+
)
|
|
572
594
|
c.post(url, {"username": student_name, "password": student_password})
|
|
573
595
|
|
|
574
596
|
student_dashboard_url = reverse("student_details")
|
|
@@ -589,9 +611,9 @@ class TestViews(TestCase):
|
|
|
589
611
|
assert response.status_code == 200
|
|
590
612
|
assert response.context_data == EXPECTED_DATA_WITH_ATTEMPTS
|
|
591
613
|
|
|
592
|
-
# Teacher creates 3 custom levels, only shares the first 2 with the
|
|
593
|
-
# Check that the total available score only includes the
|
|
594
|
-
# student. Student attempts one level only.
|
|
614
|
+
# Teacher creates 3 custom levels, only shares the first 2 with the
|
|
615
|
+
# student. Check that the total available score only includes the
|
|
616
|
+
# levels shared with the student. Student attempts one level only.
|
|
595
617
|
custom_level1_id = create_save_level(student.class_field.teacher)
|
|
596
618
|
custom_level2_id = create_save_level(student.class_field.teacher)
|
|
597
619
|
create_save_level(student.class_field.teacher)
|
|
@@ -608,15 +630,6 @@ class TestViews(TestCase):
|
|
|
608
630
|
assert response.status_code == 200
|
|
609
631
|
assert response.context_data == EXPECTED_DATA_WITH_CUSTOM_ATTEMPTS
|
|
610
632
|
|
|
611
|
-
# Link Kurono game to student's class
|
|
612
|
-
game = Game(game_class=klass, worksheet_id=3)
|
|
613
|
-
game.save()
|
|
614
|
-
|
|
615
|
-
response = c.get(student_dashboard_url)
|
|
616
|
-
|
|
617
|
-
assert response.status_code == 200
|
|
618
|
-
assert response.context_data == EXPECTED_DATA_WITH_KURONO_GAME
|
|
619
|
-
|
|
620
633
|
@patch("portal.views.registration.send_dotdigital_email")
|
|
621
634
|
def test_delete_account(self, mock_send_dotdigital_email: Mock):
|
|
622
635
|
email, password = signup_teacher_directly()
|
|
@@ -647,7 +660,9 @@ class TestViews(TestCase):
|
|
|
647
660
|
|
|
648
661
|
# try again with the correct password
|
|
649
662
|
url = reverse("delete_account")
|
|
650
|
-
response = c.post(
|
|
663
|
+
response = c.post(
|
|
664
|
+
url, {"password": password, "unsubscribe_newsletter": "on"}
|
|
665
|
+
)
|
|
651
666
|
|
|
652
667
|
assert response.status_code == 302
|
|
653
668
|
mock_send_dotdigital_email.assert_called_once()
|
|
@@ -729,7 +744,9 @@ class TestViews(TestCase):
|
|
|
729
744
|
|
|
730
745
|
school_id = school.id
|
|
731
746
|
school_name = school.name
|
|
732
|
-
teachers = Teacher.objects.filter(school=school).order_by(
|
|
747
|
+
teachers = Teacher.objects.filter(school=school).order_by(
|
|
748
|
+
"new_user__last_name", "new_user__first_name"
|
|
749
|
+
)
|
|
733
750
|
assert len(teachers) == 3
|
|
734
751
|
|
|
735
752
|
# one of the remaining teachers should be admin (the second in our case, as it's alphabetical)
|
|
@@ -760,7 +777,9 @@ class TestViews(TestCase):
|
|
|
760
777
|
self.assertEqual(mock_send_dotdigital_email.call_count, 2)
|
|
761
778
|
|
|
762
779
|
# 2 teachers left
|
|
763
|
-
teachers = Teacher.objects.filter(school=school).order_by(
|
|
780
|
+
teachers = Teacher.objects.filter(school=school).order_by(
|
|
781
|
+
"new_user__last_name", "new_user__first_name"
|
|
782
|
+
)
|
|
764
783
|
assert len(teachers) == 2
|
|
765
784
|
|
|
766
785
|
# teacher2 should still be admin, teacher4 is not passed admin role because there is teacher2
|
|
@@ -772,7 +791,9 @@ class TestViews(TestCase):
|
|
|
772
791
|
# delete teacher4
|
|
773
792
|
anonymise(user4)
|
|
774
793
|
|
|
775
|
-
teachers = Teacher.objects.filter(school=school).order_by(
|
|
794
|
+
teachers = Teacher.objects.filter(school=school).order_by(
|
|
795
|
+
"new_user__last_name", "new_user__first_name"
|
|
796
|
+
)
|
|
776
797
|
assert len(teachers) == 1
|
|
777
798
|
u = User.objects.get(id=usrid2)
|
|
778
799
|
assert u.new_teacher.is_admin
|
|
@@ -830,13 +851,17 @@ class TestViews(TestCase):
|
|
|
830
851
|
c.logout()
|
|
831
852
|
|
|
832
853
|
@patch("common.helpers.emails.send_dotdigital_email")
|
|
833
|
-
def test_registrations_increment_data(
|
|
854
|
+
def test_registrations_increment_data(
|
|
855
|
+
self, mock_send_dotdigital_email: Mock
|
|
856
|
+
):
|
|
834
857
|
c = Client()
|
|
835
858
|
|
|
836
859
|
total_activity = TotalActivity.objects.get(id=1)
|
|
837
860
|
teacher_registration_count = total_activity.teacher_registrations
|
|
838
861
|
student_registration_count = total_activity.student_registrations
|
|
839
|
-
independent_registration_count =
|
|
862
|
+
independent_registration_count = (
|
|
863
|
+
total_activity.independent_registrations
|
|
864
|
+
)
|
|
840
865
|
|
|
841
866
|
response = c.post(
|
|
842
867
|
reverse("register"),
|
|
@@ -856,7 +881,10 @@ class TestViews(TestCase):
|
|
|
856
881
|
|
|
857
882
|
total_activity = TotalActivity.objects.get(id=1)
|
|
858
883
|
|
|
859
|
-
assert
|
|
884
|
+
assert (
|
|
885
|
+
total_activity.teacher_registrations
|
|
886
|
+
== teacher_registration_count + 1
|
|
887
|
+
)
|
|
860
888
|
|
|
861
889
|
response = c.post(
|
|
862
890
|
reverse("register"),
|
|
@@ -878,7 +906,10 @@ class TestViews(TestCase):
|
|
|
878
906
|
|
|
879
907
|
total_activity = TotalActivity.objects.get(id=1)
|
|
880
908
|
|
|
881
|
-
assert
|
|
909
|
+
assert (
|
|
910
|
+
total_activity.independent_registrations
|
|
911
|
+
== independent_registration_count + 1
|
|
912
|
+
)
|
|
882
913
|
|
|
883
914
|
teacher_email, teacher_password = signup_teacher_directly()
|
|
884
915
|
create_organisation_directly(teacher_email)
|
|
@@ -894,7 +925,10 @@ class TestViews(TestCase):
|
|
|
894
925
|
|
|
895
926
|
total_activity = TotalActivity.objects.get(id=1)
|
|
896
927
|
|
|
897
|
-
assert
|
|
928
|
+
assert (
|
|
929
|
+
total_activity.student_registrations
|
|
930
|
+
== student_registration_count + 3
|
|
931
|
+
)
|
|
898
932
|
|
|
899
933
|
|
|
900
934
|
# CRON view tests
|
|
@@ -913,8 +947,12 @@ class CronTestClient(APIClient):
|
|
|
913
947
|
secure=False,
|
|
914
948
|
**extra,
|
|
915
949
|
):
|
|
916
|
-
wsgi_response = super().generic(
|
|
917
|
-
|
|
950
|
+
wsgi_response = super().generic(
|
|
951
|
+
method, path, data, content_type, secure, **extra
|
|
952
|
+
)
|
|
953
|
+
assert (
|
|
954
|
+
200 <= wsgi_response.status_code < 300
|
|
955
|
+
), f"Response has error status code: {wsgi_response.status_code}"
|
|
918
956
|
|
|
919
957
|
return wsgi_response
|
|
920
958
|
|
|
@@ -933,7 +971,9 @@ class TestUser(CronTestCase):
|
|
|
933
971
|
indy_email, _, _ = create_independent_student_directly()
|
|
934
972
|
|
|
935
973
|
self.teacher_user = User.objects.get(email=teacher_email)
|
|
936
|
-
self.teacher_user_profile = UserProfile.objects.get(
|
|
974
|
+
self.teacher_user_profile = UserProfile.objects.get(
|
|
975
|
+
user=self.teacher_user
|
|
976
|
+
)
|
|
937
977
|
|
|
938
978
|
self.indy_user = User.objects.get(email=indy_email)
|
|
939
979
|
self.indy_user_profile = UserProfile.objects.get(user=self.indy_user)
|
|
@@ -949,11 +989,17 @@ class TestUser(CronTestCase):
|
|
|
949
989
|
assert_called: bool,
|
|
950
990
|
mock_send_dotdigital_email: Mock,
|
|
951
991
|
):
|
|
952
|
-
self.teacher_user.date_joined = timezone.now() - timedelta(
|
|
992
|
+
self.teacher_user.date_joined = timezone.now() - timedelta(
|
|
993
|
+
days=days, hours=12
|
|
994
|
+
)
|
|
953
995
|
self.teacher_user.save()
|
|
954
|
-
self.student_user.date_joined = timezone.now() - timedelta(
|
|
996
|
+
self.student_user.date_joined = timezone.now() - timedelta(
|
|
997
|
+
days=days, hours=12
|
|
998
|
+
)
|
|
955
999
|
self.student_user.save()
|
|
956
|
-
self.indy_user.date_joined = timezone.now() - timedelta(
|
|
1000
|
+
self.indy_user.date_joined = timezone.now() - timedelta(
|
|
1001
|
+
days=days, hours=12
|
|
1002
|
+
)
|
|
957
1003
|
self.indy_user.save()
|
|
958
1004
|
|
|
959
1005
|
self.teacher_user_profile.is_verified = is_verified
|
|
@@ -964,9 +1010,13 @@ class TestUser(CronTestCase):
|
|
|
964
1010
|
self.client.get(reverse(view_name))
|
|
965
1011
|
|
|
966
1012
|
if assert_called:
|
|
967
|
-
mock_send_dotdigital_email.assert_any_call(
|
|
1013
|
+
mock_send_dotdigital_email.assert_any_call(
|
|
1014
|
+
ANY, [self.teacher_user.email], personalization_values=ANY
|
|
1015
|
+
)
|
|
968
1016
|
|
|
969
|
-
mock_send_dotdigital_email.assert_any_call(
|
|
1017
|
+
mock_send_dotdigital_email.assert_any_call(
|
|
1018
|
+
ANY, [self.indy_user.email], personalization_values=ANY
|
|
1019
|
+
)
|
|
970
1020
|
|
|
971
1021
|
# Check only two emails are sent - the student should never be included.
|
|
972
1022
|
assert mock_send_dotdigital_email.call_count == 2
|
|
@@ -976,22 +1026,40 @@ class TestUser(CronTestCase):
|
|
|
976
1026
|
mock_send_dotdigital_email.reset_mock()
|
|
977
1027
|
|
|
978
1028
|
def test_first_verify_email_reminder_view(self):
|
|
979
|
-
self.send_verify_email_reminder(
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
self.send_verify_email_reminder(
|
|
1029
|
+
self.send_verify_email_reminder(
|
|
1030
|
+
6, False, "first-verify-email-reminder", False
|
|
1031
|
+
)
|
|
1032
|
+
self.send_verify_email_reminder(
|
|
1033
|
+
7, False, "first-verify-email-reminder", True
|
|
1034
|
+
)
|
|
1035
|
+
self.send_verify_email_reminder(
|
|
1036
|
+
7, True, "first-verify-email-reminder", False
|
|
1037
|
+
)
|
|
1038
|
+
self.send_verify_email_reminder(
|
|
1039
|
+
8, False, "first-verify-email-reminder", False
|
|
1040
|
+
)
|
|
983
1041
|
|
|
984
1042
|
def test_second_verify_email_reminder_view(self):
|
|
985
|
-
self.send_verify_email_reminder(
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
self.send_verify_email_reminder(
|
|
1043
|
+
self.send_verify_email_reminder(
|
|
1044
|
+
13, False, "second-verify-email-reminder", False
|
|
1045
|
+
)
|
|
1046
|
+
self.send_verify_email_reminder(
|
|
1047
|
+
14, False, "second-verify-email-reminder", True
|
|
1048
|
+
)
|
|
1049
|
+
self.send_verify_email_reminder(
|
|
1050
|
+
14, True, "second-verify-email-reminder", False
|
|
1051
|
+
)
|
|
1052
|
+
self.send_verify_email_reminder(
|
|
1053
|
+
15, False, "second-verify-email-reminder", False
|
|
1054
|
+
)
|
|
989
1055
|
|
|
990
1056
|
def test_anonymise_unverified_accounts_view(self):
|
|
991
1057
|
now = timezone.now()
|
|
992
1058
|
|
|
993
1059
|
for user in [self.teacher_user, self.indy_user, self.student_user]:
|
|
994
|
-
user.date_joined = now - timedelta(
|
|
1060
|
+
user.date_joined = now - timedelta(
|
|
1061
|
+
days=USER_DELETE_UNVERIFIED_ACCOUNT_DAYS + 1
|
|
1062
|
+
)
|
|
995
1063
|
user.save()
|
|
996
1064
|
|
|
997
1065
|
for user_profile in [self.teacher_user_profile, self.indy_user_profile]:
|
|
@@ -1056,7 +1124,9 @@ class TestUser(CronTestCase):
|
|
|
1056
1124
|
new_user=indy_user,
|
|
1057
1125
|
)
|
|
1058
1126
|
|
|
1059
|
-
activity_today = DailyActivity.objects.get_or_create(
|
|
1127
|
+
activity_today = DailyActivity.objects.get_or_create(
|
|
1128
|
+
date=datetime.now().date()
|
|
1129
|
+
)[0]
|
|
1060
1130
|
daily_teacher_count = activity_today.anonymised_unverified_teachers
|
|
1061
1131
|
daily_indy_count = activity_today.anonymised_unverified_independents
|
|
1062
1132
|
|
|
@@ -1079,16 +1149,30 @@ class TestUser(CronTestCase):
|
|
|
1079
1149
|
assert indy_user_active == assert_active
|
|
1080
1150
|
assert student_user_active
|
|
1081
1151
|
|
|
1082
|
-
activity_today = DailyActivity.objects.get_or_create(
|
|
1152
|
+
activity_today = DailyActivity.objects.get_or_create(
|
|
1153
|
+
date=datetime.now().date()
|
|
1154
|
+
)[0]
|
|
1083
1155
|
total_activity = TotalActivity.objects.get(id=1)
|
|
1084
1156
|
|
|
1085
1157
|
if not teacher_user_active:
|
|
1086
|
-
assert
|
|
1087
|
-
|
|
1158
|
+
assert (
|
|
1159
|
+
activity_today.anonymised_unverified_teachers
|
|
1160
|
+
== daily_teacher_count + 1
|
|
1161
|
+
)
|
|
1162
|
+
assert (
|
|
1163
|
+
total_activity.anonymised_unverified_teachers
|
|
1164
|
+
== total_teacher_count + 1
|
|
1165
|
+
)
|
|
1088
1166
|
|
|
1089
1167
|
if not indy_user_active:
|
|
1090
|
-
assert
|
|
1091
|
-
|
|
1168
|
+
assert (
|
|
1169
|
+
activity_today.anonymised_unverified_independents
|
|
1170
|
+
== daily_indy_count + 1
|
|
1171
|
+
)
|
|
1172
|
+
assert (
|
|
1173
|
+
total_activity.anonymised_unverified_independents
|
|
1174
|
+
== total_indy_count + 1
|
|
1175
|
+
)
|
|
1092
1176
|
|
|
1093
1177
|
teacher_user.delete()
|
|
1094
1178
|
indy_user.delete()
|
|
@@ -1114,3 +1198,103 @@ class TestUser(CronTestCase):
|
|
|
1114
1198
|
is_verified=False,
|
|
1115
1199
|
assert_active=False,
|
|
1116
1200
|
)
|
|
1201
|
+
|
|
1202
|
+
@patch("portal.views.cron.user.send_dotdigital_email")
|
|
1203
|
+
def send_inactivity_reminder(
|
|
1204
|
+
self,
|
|
1205
|
+
days: int,
|
|
1206
|
+
view_name: str,
|
|
1207
|
+
assert_called: bool,
|
|
1208
|
+
campaign_name: str,
|
|
1209
|
+
mock_send_dotdigital_email: Mock,
|
|
1210
|
+
):
|
|
1211
|
+
self.teacher_user.date_joined = timezone.now() - timedelta(
|
|
1212
|
+
days=days, hours=12
|
|
1213
|
+
)
|
|
1214
|
+
self.teacher_user.save()
|
|
1215
|
+
self.student_user.date_joined = timezone.now() - timedelta(
|
|
1216
|
+
days=days, hours=12
|
|
1217
|
+
)
|
|
1218
|
+
self.student_user.save()
|
|
1219
|
+
self.indy_user.last_login = timezone.now() - timedelta(
|
|
1220
|
+
days=days, hours=12
|
|
1221
|
+
)
|
|
1222
|
+
self.indy_user.save()
|
|
1223
|
+
|
|
1224
|
+
self.client.get(reverse(view_name))
|
|
1225
|
+
|
|
1226
|
+
if assert_called:
|
|
1227
|
+
mock_send_dotdigital_email.assert_any_call(
|
|
1228
|
+
campaign_ids[campaign_name], [self.teacher_user.email]
|
|
1229
|
+
)
|
|
1230
|
+
|
|
1231
|
+
mock_send_dotdigital_email.assert_any_call(
|
|
1232
|
+
campaign_ids[campaign_name], [self.indy_user.email]
|
|
1233
|
+
)
|
|
1234
|
+
|
|
1235
|
+
# Check only two emails are sent - the student should never be included.
|
|
1236
|
+
assert mock_send_dotdigital_email.call_count == 2
|
|
1237
|
+
else:
|
|
1238
|
+
mock_send_dotdigital_email.assert_not_called()
|
|
1239
|
+
|
|
1240
|
+
mock_send_dotdigital_email.reset_mock()
|
|
1241
|
+
|
|
1242
|
+
def test_first_inactivity_reminder_view(self):
|
|
1243
|
+
self.send_inactivity_reminder(
|
|
1244
|
+
729,
|
|
1245
|
+
"first-inactivity-reminder",
|
|
1246
|
+
False,
|
|
1247
|
+
"inactive_users_on_website_first_reminder",
|
|
1248
|
+
)
|
|
1249
|
+
self.send_inactivity_reminder(
|
|
1250
|
+
730,
|
|
1251
|
+
"first-inactivity-reminder",
|
|
1252
|
+
True,
|
|
1253
|
+
"inactive_users_on_website_first_reminder",
|
|
1254
|
+
)
|
|
1255
|
+
self.send_inactivity_reminder(
|
|
1256
|
+
731,
|
|
1257
|
+
"first-inactivity-reminder",
|
|
1258
|
+
False,
|
|
1259
|
+
"inactive_users_on_website_first_reminder",
|
|
1260
|
+
)
|
|
1261
|
+
|
|
1262
|
+
def test_second_inactivity_reminder_view(self):
|
|
1263
|
+
self.send_inactivity_reminder(
|
|
1264
|
+
972,
|
|
1265
|
+
"second-inactivity-reminder",
|
|
1266
|
+
False,
|
|
1267
|
+
"inactive_users_on_website_second_reminder",
|
|
1268
|
+
)
|
|
1269
|
+
self.send_inactivity_reminder(
|
|
1270
|
+
973,
|
|
1271
|
+
"second-inactivity-reminder",
|
|
1272
|
+
True,
|
|
1273
|
+
"inactive_users_on_website_second_reminder",
|
|
1274
|
+
)
|
|
1275
|
+
self.send_inactivity_reminder(
|
|
1276
|
+
974,
|
|
1277
|
+
"second-inactivity-reminder",
|
|
1278
|
+
False,
|
|
1279
|
+
"inactive_users_on_website_second_reminder",
|
|
1280
|
+
)
|
|
1281
|
+
|
|
1282
|
+
def test_final_inactivity_reminder_view(self):
|
|
1283
|
+
self.send_inactivity_reminder(
|
|
1284
|
+
1064,
|
|
1285
|
+
"final-inactivity-reminder",
|
|
1286
|
+
False,
|
|
1287
|
+
"inactive_users_on_website_final_reminder",
|
|
1288
|
+
)
|
|
1289
|
+
self.send_inactivity_reminder(
|
|
1290
|
+
1065,
|
|
1291
|
+
"final-inactivity-reminder",
|
|
1292
|
+
True,
|
|
1293
|
+
"inactive_users_on_website_final_reminder",
|
|
1294
|
+
)
|
|
1295
|
+
self.send_inactivity_reminder(
|
|
1296
|
+
1066,
|
|
1297
|
+
"final-inactivity-reminder",
|
|
1298
|
+
False,
|
|
1299
|
+
"inactive_users_on_website_final_reminder",
|
|
1300
|
+
)
|