codeforlife-portal 6.43.0__py2.py3-none-any.whl → 6.43.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of codeforlife-portal might be problematic. Click here for more details.
- cfl_common/common/email_messages.py +0 -24
- cfl_common/common/helpers/emails.py +14 -39
- cfl_common/common/mail.py +88 -44
- {codeforlife_portal-6.43.0.dist-info → codeforlife_portal-6.43.1.dist-info}/METADATA +2 -2
- {codeforlife_portal-6.43.0.dist-info → codeforlife_portal-6.43.1.dist-info}/RECORD +11 -11
- portal/__init__.py +1 -1
- portal/tests/test_organisation.py +5 -3
- portal/views/teacher/dashboard.py +56 -32
- {codeforlife_portal-6.43.0.dist-info → codeforlife_portal-6.43.1.dist-info}/LICENSE.md +0 -0
- {codeforlife_portal-6.43.0.dist-info → codeforlife_portal-6.43.1.dist-info}/WHEEL +0 -0
- {codeforlife_portal-6.43.0.dist-info → codeforlife_portal-6.43.1.dist-info}/top_level.txt +0 -0
|
@@ -29,30 +29,6 @@ def kickedEmail(request, schoolName):
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def adminGivenEmail(request, schoolName):
|
|
33
|
-
|
|
34
|
-
url = request.build_absolute_uri(reverse("dashboard"))
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
"subject": f"You have been made a school or club administrator",
|
|
38
|
-
"message": (
|
|
39
|
-
f"Administrator control of the school or club '{schoolName}' has been "
|
|
40
|
-
f"given to you. Go to {url} to start managing your school or club."
|
|
41
|
-
),
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def adminRevokedEmail(request, schoolName):
|
|
46
|
-
return {
|
|
47
|
-
"subject": f"You are no longer a school or club administrator",
|
|
48
|
-
"message": (
|
|
49
|
-
f"Your administrator control of the school or club '{schoolName}' has been "
|
|
50
|
-
f"revoked. If you think this is an error, please contact one of the other "
|
|
51
|
-
f"administrators in your school or club."
|
|
52
|
-
),
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
32
|
def studentJoinRequestSentEmail(request, schoolName, accessCode):
|
|
57
33
|
return {
|
|
58
34
|
"subject": f"School or club join request sent",
|
|
@@ -6,14 +6,11 @@ from uuid import uuid4
|
|
|
6
6
|
|
|
7
7
|
import jwt
|
|
8
8
|
from common import app_settings
|
|
9
|
-
from common.
|
|
10
|
-
from common.mail import campaign_ids, send_dotdigital_email
|
|
9
|
+
from common.mail import campaign_ids, django_send_email, send_dotdigital_email
|
|
11
10
|
from common.models import Student, Teacher
|
|
12
11
|
from django.conf import settings
|
|
13
12
|
from django.contrib.auth.models import User
|
|
14
|
-
from django.core.mail import EmailMultiAlternatives
|
|
15
13
|
from django.http import HttpResponse
|
|
16
|
-
from django.template import loader
|
|
17
14
|
from django.urls import reverse
|
|
18
15
|
from django.utils import timezone
|
|
19
16
|
from requests import delete, get, post, put
|
|
@@ -31,41 +28,6 @@ class DotmailerUserType(Enum):
|
|
|
31
28
|
NO_ACCOUNT = auto()
|
|
32
29
|
|
|
33
30
|
|
|
34
|
-
def send_email(
|
|
35
|
-
sender,
|
|
36
|
-
recipients,
|
|
37
|
-
subject,
|
|
38
|
-
text_content,
|
|
39
|
-
title,
|
|
40
|
-
replace_url=None,
|
|
41
|
-
plaintext_template="email.txt",
|
|
42
|
-
html_template="email.html",
|
|
43
|
-
):
|
|
44
|
-
# add in template for templates to message
|
|
45
|
-
|
|
46
|
-
# setup templates
|
|
47
|
-
plaintext = loader.get_template(plaintext_template)
|
|
48
|
-
html = loader.get_template(html_template)
|
|
49
|
-
plaintext_email_context = {"content": text_content}
|
|
50
|
-
html_email_context = {"content": text_content, "title": title, "url_prefix": domain()}
|
|
51
|
-
|
|
52
|
-
# render templates
|
|
53
|
-
plaintext_body = plaintext.render(plaintext_email_context)
|
|
54
|
-
original_html_body = html.render(html_email_context)
|
|
55
|
-
html_body = original_html_body
|
|
56
|
-
|
|
57
|
-
if replace_url:
|
|
58
|
-
verify_url = replace_url["verify_url"]
|
|
59
|
-
verify_replace_url = re.sub(f"(.*/verify_email/)(.*)", f"\\1", verify_url)
|
|
60
|
-
html_body = re.sub(f"({verify_url})(.*){verify_url}", f"\\1\\2{verify_replace_url}", original_html_body)
|
|
61
|
-
|
|
62
|
-
# make message using templates
|
|
63
|
-
message = EmailMultiAlternatives(subject, plaintext_body, sender, recipients)
|
|
64
|
-
message.attach_alternative(html_body, "text/html")
|
|
65
|
-
|
|
66
|
-
message.send()
|
|
67
|
-
|
|
68
|
-
|
|
69
31
|
def generate_token(user, new_email="", preverified=False):
|
|
70
32
|
if preverified:
|
|
71
33
|
user.userprofile.is_verified = preverified
|
|
@@ -91,6 +53,19 @@ def _newsletter_ticked(data):
|
|
|
91
53
|
return "newsletter_ticked" in data and data["newsletter_ticked"]
|
|
92
54
|
|
|
93
55
|
|
|
56
|
+
def send_email(
|
|
57
|
+
sender,
|
|
58
|
+
recipients,
|
|
59
|
+
subject,
|
|
60
|
+
text_content,
|
|
61
|
+
title,
|
|
62
|
+
replace_url=None,
|
|
63
|
+
plaintext_template="email.txt",
|
|
64
|
+
html_template="email.html",
|
|
65
|
+
):
|
|
66
|
+
django_send_email(sender, recipients, subject, text_content, title, replace_url, plaintext_template, html_template)
|
|
67
|
+
|
|
68
|
+
|
|
94
69
|
def send_verification_email(request, user, data, new_email=None, age=None):
|
|
95
70
|
"""
|
|
96
71
|
Sends emails relating to email address verification.
|
cfl_common/common/mail.py
CHANGED
|
@@ -3,8 +3,13 @@ from dataclasses import dataclass
|
|
|
3
3
|
|
|
4
4
|
import requests
|
|
5
5
|
from common import app_settings
|
|
6
|
+
from common.app_settings import MODULE_NAME, domain
|
|
7
|
+
from django.core.mail import EmailMultiAlternatives
|
|
8
|
+
from django.template import loader
|
|
6
9
|
|
|
7
10
|
campaign_ids = {
|
|
11
|
+
"admin_given": 1569057,
|
|
12
|
+
"admin_revoked": 1569071,
|
|
8
13
|
"email_change_notification": 1551600,
|
|
9
14
|
"email_change_verification": 1551594,
|
|
10
15
|
"reset_password": 1557153,
|
|
@@ -34,6 +39,41 @@ class EmailAttachment:
|
|
|
34
39
|
content: str
|
|
35
40
|
|
|
36
41
|
|
|
42
|
+
def django_send_email(
|
|
43
|
+
sender,
|
|
44
|
+
recipients,
|
|
45
|
+
subject,
|
|
46
|
+
text_content,
|
|
47
|
+
title,
|
|
48
|
+
replace_url=None,
|
|
49
|
+
plaintext_template="email.txt",
|
|
50
|
+
html_template="email.html",
|
|
51
|
+
):
|
|
52
|
+
# add in template for templates to message
|
|
53
|
+
|
|
54
|
+
# setup templates
|
|
55
|
+
plaintext = loader.get_template(plaintext_template)
|
|
56
|
+
html = loader.get_template(html_template)
|
|
57
|
+
plaintext_email_context = {"content": text_content}
|
|
58
|
+
html_email_context = {"content": text_content, "title": title, "url_prefix": domain()}
|
|
59
|
+
|
|
60
|
+
# render templates
|
|
61
|
+
plaintext_body = plaintext.render(plaintext_email_context)
|
|
62
|
+
original_html_body = html.render(html_email_context)
|
|
63
|
+
html_body = original_html_body
|
|
64
|
+
|
|
65
|
+
if replace_url:
|
|
66
|
+
verify_url = replace_url["verify_url"]
|
|
67
|
+
verify_replace_url = re.sub(f"(.*/verify_email/)(.*)", f"\\1", verify_url)
|
|
68
|
+
html_body = re.sub(f"({verify_url})(.*){verify_url}", f"\\1\\2{verify_replace_url}", original_html_body)
|
|
69
|
+
|
|
70
|
+
# make message using templates
|
|
71
|
+
message = EmailMultiAlternatives(subject, plaintext_body, sender, recipients)
|
|
72
|
+
message.attach_alternative(html_body, "text/html")
|
|
73
|
+
|
|
74
|
+
message.send()
|
|
75
|
+
|
|
76
|
+
|
|
37
77
|
# pylint: disable-next=too-many-arguments
|
|
38
78
|
def send_dotdigital_email(
|
|
39
79
|
campaign_id: int,
|
|
@@ -71,47 +111,51 @@ def send_dotdigital_email(
|
|
|
71
111
|
"""
|
|
72
112
|
# pylint: enable=line-too-long
|
|
73
113
|
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
# Dotdigital emails don't work locally, so if testing emails locally use Django to send a dummy email instead
|
|
115
|
+
if MODULE_NAME == "local":
|
|
116
|
+
django_send_email(from_address, to_addresses, "dummy_subject", "dummy_text_content", "dummy_title")
|
|
117
|
+
else:
|
|
118
|
+
if auth is None:
|
|
119
|
+
auth = app_settings.DOTDIGITAL_AUTH
|
|
120
|
+
|
|
121
|
+
body = {
|
|
122
|
+
"campaignId": campaign_id,
|
|
123
|
+
"toAddresses": to_addresses,
|
|
124
|
+
}
|
|
125
|
+
if cc_addresses is not None:
|
|
126
|
+
body["ccAddresses"] = cc_addresses
|
|
127
|
+
if bcc_addresses is not None:
|
|
128
|
+
body["bccAddresses"] = bcc_addresses
|
|
129
|
+
if from_address is not None:
|
|
130
|
+
body["fromAddress"] = from_address
|
|
131
|
+
if personalization_values is not None:
|
|
132
|
+
body["personalizationValues"] = [
|
|
133
|
+
{
|
|
134
|
+
"name": key,
|
|
135
|
+
"value": value,
|
|
136
|
+
}
|
|
137
|
+
for key, value in personalization_values.items()
|
|
138
|
+
]
|
|
139
|
+
if metadata is not None:
|
|
140
|
+
body["metadata"] = metadata
|
|
141
|
+
if attachments is not None:
|
|
142
|
+
body["attachments"] = [
|
|
143
|
+
{
|
|
144
|
+
"fileName": attachment.file_name,
|
|
145
|
+
"mimeType": attachment.mime_type,
|
|
146
|
+
"content": attachment.content,
|
|
147
|
+
}
|
|
148
|
+
for attachment in attachments
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
response = requests.post(
|
|
152
|
+
url=f"https://{region}-api.dotdigital.com/v2/email/triggered-campaign",
|
|
153
|
+
json=body,
|
|
154
|
+
headers={
|
|
155
|
+
"accept": "text/plain",
|
|
156
|
+
"authorization": auth,
|
|
157
|
+
},
|
|
158
|
+
timeout=timeout,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
assert response.ok, "Failed to send email." f" Reason: {response.reason}." f" Text: {response.text}."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codeforlife-portal
|
|
3
|
-
Version: 6.43.
|
|
3
|
+
Version: 6.43.1
|
|
4
4
|
Classifier: Programming Language :: Python
|
|
5
5
|
Classifier: Programming Language :: Python :: 3.8
|
|
6
6
|
Classifier: Framework :: Django
|
|
@@ -24,7 +24,7 @@ Requires-Dist: django-classy-tags ==2.0.0
|
|
|
24
24
|
Requires-Dist: libsass ==0.23.0
|
|
25
25
|
Requires-Dist: phonenumbers ==8.12.12
|
|
26
26
|
Requires-Dist: more-itertools ==8.7.0
|
|
27
|
-
Requires-Dist: cfl-common ==6.43.
|
|
27
|
+
Requires-Dist: cfl-common ==6.43.1
|
|
28
28
|
Requires-Dist: django-ratelimit ==3.0.1
|
|
29
29
|
Requires-Dist: django-preventconcurrentlogins ==0.8.2
|
|
30
30
|
Requires-Dist: django-csp ==3.7
|
|
@@ -5,14 +5,14 @@ cfl_common/common/app_settings.py,sha256=x2ROLY5Xl5LgqjxyTiChZvQorZYUXpFzEkaLsjh
|
|
|
5
5
|
cfl_common/common/apps.py,sha256=49UXZ3bSkFKvIEOL4zM7y1sAhccQJyRtsoOg5XVd_8Y,129
|
|
6
6
|
cfl_common/common/context_processors.py,sha256=X0iuX5qu9kMWa7q8osE9CJ2LgM7pPOYQFGdjm8X3rk0,236
|
|
7
7
|
cfl_common/common/csp_config.py,sha256=sZT6s9zMT5FFIqNODsURT0ifxbDgXpDlki8UxaBq2iE,2940
|
|
8
|
-
cfl_common/common/email_messages.py,sha256=
|
|
9
|
-
cfl_common/common/mail.py,sha256=
|
|
8
|
+
cfl_common/common/email_messages.py,sha256=oK8cb5wrDbxq6xoEoILHJggs3P35aEyk9eFJHIR6y74,3644
|
|
9
|
+
cfl_common/common/mail.py,sha256=qgsgBc0drFIG8ik4ZBjaqjSvk0LVDIJV2fNYWFrbzHU,5990
|
|
10
10
|
cfl_common/common/models.py,sha256=EunFsc7sOWfWiFf4IQwuy56gu8pu3YpPoOgVtsMhbRM,14958
|
|
11
11
|
cfl_common/common/permissions.py,sha256=gC6RQGZI2QDBbglx-xr_V4Hl2C2nf1V2_uPmEuoEcJo,2416
|
|
12
12
|
cfl_common/common/utils.py,sha256=Nn2Npao9Uqad5Js_IdHwF-ow6wrPNpBLW4AO1LxoEBc,1727
|
|
13
13
|
cfl_common/common/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
cfl_common/common/helpers/data_migration_loader.py,sha256=_BhS5lPmhcuVUbryBmJytlWdHyT02KYyxPkHar32mOE,1748
|
|
15
|
-
cfl_common/common/helpers/emails.py,sha256=
|
|
15
|
+
cfl_common/common/helpers/emails.py,sha256=6xY8YxYY3ywcFWguys2G_36HTaBBah4ma1p20s4mpKU,10099
|
|
16
16
|
cfl_common/common/helpers/generators.py,sha256=kTL5e91I8wgmjJ-mu4jr9vIacjccUZ5pZSAz5cUNhdM,1505
|
|
17
17
|
cfl_common/common/helpers/organisation.py,sha256=e-JKumKoXrkMTzZPv0H4ViWL8vtCt7oXJjn_zZ1ec00,427
|
|
18
18
|
cfl_common/common/migrations/0001_initial.py,sha256=Y2kt2xmdCbrmDXCgqmhXeacicNg26Zj7L7SANSsgAAI,9664
|
|
@@ -106,7 +106,7 @@ example_project/portal_test_settings.py,sha256=frp_XMpd-z1g3VFCRxB2w7AaFW2ivRVKn
|
|
|
106
106
|
example_project/settings.py,sha256=XRZZvASoIl5a9xe3masTq_CUBleuJq9ByHx8f_e2UFc,5613
|
|
107
107
|
example_project/urls.py,sha256=OVeRQ-TCpzHISBRuzqD0yd3ewF7H5U3c-f2p2alfUD0,430
|
|
108
108
|
example_project/wsgi.py,sha256=U1W6WzZxZaIdYZ5tks7w9fqp5WS5qvn2iThsVcskrWw,829
|
|
109
|
-
portal/__init__.py,sha256=
|
|
109
|
+
portal/__init__.py,sha256=Ngar-CylGsb6FZcYQn3kMXH5BOJ1Ub5AefCQXyRW8-E,23
|
|
110
110
|
portal/admin.py,sha256=k5Hsiln43DlVPoufnrx5AXWu_RijX8xi_n7wwBuuCJo,5132
|
|
111
111
|
portal/app_settings.py,sha256=DhWLQOwM0zVOXE3O5TNKbMM9K6agfLuCsHOdr1J7xEI,651
|
|
112
112
|
portal/backends.py,sha256=2Dss6_WoQwPuDzJUF1yEaTQTNG4eUrD12ujJQ5cp5Tc,812
|
|
@@ -548,7 +548,7 @@ portal/tests/test_independent_student.py,sha256=ysWpkYiwjPdB7gO3ow-5JuxqLi0IywRS
|
|
|
548
548
|
portal/tests/test_invite_teacher.py,sha256=oeOaoJV1IqJSYPlaPFjnhVXdB2mq8otCTLp_lfjuCfk,12224
|
|
549
549
|
portal/tests/test_middleware.py,sha256=b6jfNmiRZ2snqLKsyJUG-RivoX5fmrqLlQkG9MeVnqM,8034
|
|
550
550
|
portal/tests/test_newsletter_footer.py,sha256=MdVUX53mEoDTa4Krq-jg9LFNo-QyghqvTvhHeNXBGnE,838
|
|
551
|
-
portal/tests/test_organisation.py,sha256=
|
|
551
|
+
portal/tests/test_organisation.py,sha256=kCMUNzLN6EzaMUBcFkqXwnqLGgOuQxQWIHHt63nhqBs,7574
|
|
552
552
|
portal/tests/test_partials.py,sha256=ydh1nef6BqvMfah2BSBS9QDiKY0xopY74k_W1YVobAE,3687
|
|
553
553
|
portal/tests/test_ratelimit.py,sha256=XWq1A9XgRrlcMHibGoJ0kc4gLc5U_u5UhKHjthxCfYA,19376
|
|
554
554
|
portal/tests/test_school_student.py,sha256=bFZwY4twaFHQLp0cltMq8cLNDZGgCHTZBCZHK0JcV8s,8604
|
|
@@ -636,14 +636,14 @@ portal/views/student/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
|
636
636
|
portal/views/student/edit_account_details.py,sha256=keMakqgqy5xB76QbpwsnkadxbMg_dGsAxLuP2CoWbvc,8551
|
|
637
637
|
portal/views/student/play.py,sha256=-v9lBjHF3_PAKRgWcCGGt_bEOpIkmJDJnzgR5JvqrMo,8908
|
|
638
638
|
portal/views/teacher/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
639
|
-
portal/views/teacher/dashboard.py,sha256=
|
|
639
|
+
portal/views/teacher/dashboard.py,sha256=nNA7XxylunLjyCpKmq7h_CYITi7wM3YnmjqzUL0A-bI,25236
|
|
640
640
|
portal/views/teacher/teach.py,sha256=B71jReMJ4BYFmo7NtJVK3-4DeXEwxfu_WA3Ij1RYzdI,34725
|
|
641
641
|
portal/views/two_factor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
642
642
|
portal/views/two_factor/core.py,sha256=O_wcBeFqdPYSGNGv-pT_vbs5-Dj1Z-Jfkd6f9-E5yZI,760
|
|
643
643
|
portal/views/two_factor/form.py,sha256=lnHNKI-BMlpncTuW3zUzjPaJJNuEra2I_nOam0eOKFY,257
|
|
644
644
|
portal/views/two_factor/profile.py,sha256=tkl_ludo8arMtd5LKNmohM66vpC_YQiP-0nspTSJiJ4,383
|
|
645
|
-
codeforlife_portal-6.43.
|
|
646
|
-
codeforlife_portal-6.43.
|
|
647
|
-
codeforlife_portal-6.43.
|
|
648
|
-
codeforlife_portal-6.43.
|
|
649
|
-
codeforlife_portal-6.43.
|
|
645
|
+
codeforlife_portal-6.43.1.dist-info/LICENSE.md,sha256=9AbRlCDqD2D1tPibimysFv3zg3AIc49-eyv9aEsyq9w,115
|
|
646
|
+
codeforlife_portal-6.43.1.dist-info/METADATA,sha256=tFzxDaekn6AVyuunmE_TYU1KveLBu1erHq8KPawpbzs,1137
|
|
647
|
+
codeforlife_portal-6.43.1.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
|
|
648
|
+
codeforlife_portal-6.43.1.dist-info/top_level.txt,sha256=8e5pdsuIoTqEAMqpelHBjGjLbffcBtgOoggmd2q7nMw,41
|
|
649
|
+
codeforlife_portal-6.43.1.dist-info/RECORD,,
|
portal/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "6.43.
|
|
1
|
+
__version__ = "6.43.1"
|
|
@@ -4,9 +4,11 @@ import time
|
|
|
4
4
|
|
|
5
5
|
from common.models import Teacher
|
|
6
6
|
from common.tests.utils.classes import create_class_directly
|
|
7
|
-
from common.tests.utils.organisation import (
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
from common.tests.utils.organisation import (
|
|
8
|
+
create_organisation,
|
|
9
|
+
create_organisation_directly,
|
|
10
|
+
join_teacher_to_organisation,
|
|
11
|
+
)
|
|
10
12
|
from common.tests.utils.student import create_school_student_directly
|
|
11
13
|
from common.tests.utils.teacher import signup_teacher_directly
|
|
12
14
|
from selenium.webdriver.common.by import By
|
|
@@ -2,12 +2,24 @@ from datetime import timedelta
|
|
|
2
2
|
from uuid import uuid4
|
|
3
3
|
|
|
4
4
|
from common import email_messages
|
|
5
|
-
from common.helpers.emails import (
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
from common.helpers.emails import (
|
|
6
|
+
INVITE_FROM,
|
|
7
|
+
NOTIFICATION_EMAIL,
|
|
8
|
+
DotmailerUserType,
|
|
9
|
+
add_to_dotmailer,
|
|
10
|
+
generate_token,
|
|
11
|
+
send_email,
|
|
12
|
+
update_email,
|
|
13
|
+
)
|
|
8
14
|
from common.helpers.generators import get_random_username
|
|
9
|
-
from common.
|
|
10
|
-
|
|
15
|
+
from common.mail import campaign_ids, send_dotdigital_email
|
|
16
|
+
from common.models import (
|
|
17
|
+
Class,
|
|
18
|
+
JoinReleaseStudent,
|
|
19
|
+
SchoolTeacherInvitation,
|
|
20
|
+
Student,
|
|
21
|
+
Teacher,
|
|
22
|
+
)
|
|
11
23
|
from common.permissions import check_teacher_authorised, logged_in_as_teacher
|
|
12
24
|
from common.utils import using_two_factor
|
|
13
25
|
from django.contrib import messages as messages
|
|
@@ -16,7 +28,7 @@ from django.contrib.auth.decorators import login_required, user_passes_test
|
|
|
16
28
|
from django.contrib.auth.models import User
|
|
17
29
|
from django.http import Http404, HttpResponseRedirect
|
|
18
30
|
from django.shortcuts import get_object_or_404, render
|
|
19
|
-
from django.urls import reverse_lazy
|
|
31
|
+
from django.urls import reverse, reverse_lazy
|
|
20
32
|
from django.utils import timezone
|
|
21
33
|
from django.views.decorators.http import require_POST
|
|
22
34
|
from game.level_management import levels_shared_with, unshare_level
|
|
@@ -25,14 +37,20 @@ from two_factor.utils import devices_for_user
|
|
|
25
37
|
from portal.forms.invite_teacher import InviteTeacherForm
|
|
26
38
|
from portal.forms.organisation import OrganisationForm
|
|
27
39
|
from portal.forms.registration import DeleteAccountForm
|
|
28
|
-
from portal.forms.teach import (
|
|
29
|
-
|
|
30
|
-
|
|
40
|
+
from portal.forms.teach import (
|
|
41
|
+
ClassCreationForm,
|
|
42
|
+
InvitedTeacherForm,
|
|
43
|
+
TeacherAddExternalStudentForm,
|
|
44
|
+
TeacherEditAccountForm,
|
|
45
|
+
)
|
|
31
46
|
from portal.helpers.decorators import ratelimit
|
|
32
47
|
from portal.helpers.password import check_update_password
|
|
33
|
-
from portal.helpers.ratelimit import (
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
from portal.helpers.ratelimit import (
|
|
49
|
+
RATELIMIT_LOGIN_GROUP,
|
|
50
|
+
RATELIMIT_LOGIN_RATE,
|
|
51
|
+
RATELIMIT_METHOD,
|
|
52
|
+
clear_ratelimit_cache_for_user,
|
|
53
|
+
)
|
|
36
54
|
|
|
37
55
|
from .teach import create_class
|
|
38
56
|
|
|
@@ -380,19 +398,22 @@ def invite_toggle_admin(request, invite_id):
|
|
|
380
398
|
|
|
381
399
|
if invite.invited_teacher_is_admin:
|
|
382
400
|
messages.success(request, "Administrator invite status has been given successfully")
|
|
383
|
-
|
|
401
|
+
send_dotdigital_email(
|
|
402
|
+
campaign_ids["admin_given"],
|
|
403
|
+
[invite.invited_teacher_email],
|
|
404
|
+
personalization_values={
|
|
405
|
+
"SCHOOL_CLUB_NAME": invite.school,
|
|
406
|
+
"MANAGEMENT_LINK": request.build_absolute_uri(reverse("dashboard")),
|
|
407
|
+
},
|
|
408
|
+
)
|
|
384
409
|
|
|
385
410
|
else:
|
|
386
411
|
messages.success(request, "Administrator invite status has been revoked successfully")
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
emailMessage["subject"],
|
|
393
|
-
emailMessage["message"],
|
|
394
|
-
emailMessage["subject"],
|
|
395
|
-
)
|
|
412
|
+
send_dotdigital_email(
|
|
413
|
+
campaign_ids["admin_revoked"],
|
|
414
|
+
[invite.invited_teacher_email],
|
|
415
|
+
personalization_values={"SCHOOL_CLUB_NAME": invite.school},
|
|
416
|
+
)
|
|
396
417
|
|
|
397
418
|
return HttpResponseRedirect(reverse_lazy("dashboard"))
|
|
398
419
|
|
|
@@ -411,7 +432,14 @@ def organisation_toggle_admin(request, pk):
|
|
|
411
432
|
|
|
412
433
|
if teacher.is_admin:
|
|
413
434
|
messages.success(request, "Administrator status has been given successfully.")
|
|
414
|
-
|
|
435
|
+
send_dotdigital_email(
|
|
436
|
+
campaign_ids["admin_given"],
|
|
437
|
+
[teacher.new_user.email],
|
|
438
|
+
personalization_values={
|
|
439
|
+
"SCHOOL_CLUB_NAME": teacher.school.name,
|
|
440
|
+
"MANAGEMENT_LINK": request.build_absolute_uri(reverse("dashboard")),
|
|
441
|
+
},
|
|
442
|
+
)
|
|
415
443
|
else:
|
|
416
444
|
# Remove access to all levels that are from other teachers' students
|
|
417
445
|
[
|
|
@@ -420,15 +448,11 @@ def organisation_toggle_admin(request, pk):
|
|
|
420
448
|
if hasattr(level.owner, "student") and not teacher.teaches(level.owner)
|
|
421
449
|
]
|
|
422
450
|
messages.success(request, "Administrator status has been revoked successfully.")
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
email_message["subject"],
|
|
429
|
-
email_message["message"],
|
|
430
|
-
email_message["subject"],
|
|
431
|
-
)
|
|
451
|
+
send_dotdigital_email(
|
|
452
|
+
campaign_ids["admin_revoked"],
|
|
453
|
+
[teacher.new_user.email],
|
|
454
|
+
personalization_values={"SCHOOL_CLUB_NAME": teacher.school.name},
|
|
455
|
+
)
|
|
432
456
|
|
|
433
457
|
return HttpResponseRedirect(reverse_lazy("dashboard"))
|
|
434
458
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|