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

Files changed (28) hide show
  1. cfl_common/common/app_settings.py +0 -1
  2. cfl_common/common/helpers/emails.py +153 -36
  3. cfl_common/common/mail.py +5 -0
  4. {codeforlife_portal-7.3.8.dist-info → codeforlife_portal-7.4.0.dist-info}/METADATA +2 -2
  5. {codeforlife_portal-7.3.8.dist-info → codeforlife_portal-7.4.0.dist-info}/RECORD +28 -27
  6. example_project/portal_test_settings.py +1 -0
  7. example_project/settings.py +1 -0
  8. portal/__init__.py +1 -1
  9. portal/context_processors.py +5 -1
  10. portal/forms/dotmailer.py +39 -4
  11. portal/static/portal/js/common.js +35 -5
  12. portal/static/portal/sass/modules/_colours.scss +3 -0
  13. portal/static/portal/sass/modules/_levels.scss +1 -1
  14. portal/static/portal/sass/modules/_mixins.scss +5 -0
  15. portal/static/portal/sass/partials/_buttons.scss +31 -3
  16. portal/static/portal/sass/partials/_header.scss +7 -6
  17. portal/static/portal/sass/partials/_popup.scss +7 -2
  18. portal/templates/portal/base.html +12 -3
  19. portal/templates/portal/partials/donate_popup.html +46 -0
  20. portal/templates/portal/partials/header.html +34 -30
  21. portal/tests/test_emails.py +17 -22
  22. portal/tests/{test_newsletter_footer.py → test_global_forms.py} +17 -1
  23. portal/urls.py +2 -0
  24. portal/views/dotmailer.py +30 -2
  25. portal/views/teacher/dashboard.py +174 -57
  26. {codeforlife_portal-7.3.8.dist-info → codeforlife_portal-7.4.0.dist-info}/LICENSE.md +0 -0
  27. {codeforlife_portal-7.3.8.dist-info → codeforlife_portal-7.4.0.dist-info}/WHEEL +0 -0
  28. {codeforlife_portal-7.3.8.dist-info → codeforlife_portal-7.4.0.dist-info}/top_level.txt +0 -0
@@ -63,6 +63,9 @@ $color-button-contained-disabled: $color-secondary-100;
63
63
  $color-button-outlined-border: $color-secondary-600;
64
64
  $color-button-outlined-border-active: $color-secondary-600;
65
65
  $color-button-subnav-border: white;
66
+ $color-button-pill: #86ae18;
67
+ $color-button-pill-hover: #82a210;
68
+ $color-button-pill-active: #82a210;
66
69
  // Old buttons
67
70
  $color-button-primary-action-navigation: $color-secondary;
68
71
  $color-button-primary-action-navigation-hover: $color-secondary;
@@ -1,4 +1,4 @@
1
1
  $hover-content-level: 100;
2
2
  $nav-bar-level: 1001;
3
- $popup-overlay-level: 300;
3
+ $popup-overlay-level: 1100;
4
4
  $behind-content-level: -100;
@@ -55,6 +55,11 @@
55
55
  calculate-rem($radius-bottom-left);
56
56
  }
57
57
 
58
+ @mixin _border-radius-all($radius) {
59
+ border-radius: calculate-rem($radius) calculate-rem($radius)
60
+ calculate-rem($radius) calculate-rem($radius);
61
+ }
62
+
58
63
  @mixin _box-shadow($h-offset, $v-offset, $blur, $spread, $color) {
59
64
  box-shadow: calculate-rem($h-offset) calculate-rem($v-offset)
60
65
  calculate-rem($blur) calculate-rem($spread) $color;
@@ -89,7 +89,6 @@ table {
89
89
  color: $color-text-primary;
90
90
  box-shadow: none;
91
91
  }
92
-
93
92
  }
94
93
 
95
94
  /* Outlined button */
@@ -139,6 +138,30 @@ table {
139
138
  }
140
139
  }
141
140
 
141
+ /* Green button */
142
+ .button--tertiary {
143
+ @include _padding(10px, 15px, 10px, 15px);
144
+ background: $color-button-pill;
145
+ color: $color-text-secondary;
146
+
147
+ &:hover:not(.disabled){
148
+ @include material-shadow();
149
+ background: $color-button-pill-hover;
150
+ color: $color-text-secondary;
151
+ text-decoration: none;
152
+ }
153
+
154
+ &:active:not(.disabled) {
155
+ background: $color-button-pill-active;
156
+ color: $color-text-secondary;
157
+ box-shadow: none;
158
+ }
159
+ }
160
+
161
+ .button--pill {
162
+ @include _border-radius-all(20px);
163
+ }
164
+
142
165
  .button-right-arrow {
143
166
  &:after {
144
167
  content: "\e5e1";
@@ -172,8 +195,6 @@ table {
172
195
  }
173
196
 
174
197
  .button--menu {
175
- background-color: transparent;
176
- border-radius: 0;
177
198
  text-decoration: none;
178
199
  }
179
200
 
@@ -416,6 +437,13 @@ td .button--primary {
416
437
  justify-content: center;
417
438
  }
418
439
 
440
+ &.button--donate {
441
+ background: $color-button-pill;
442
+ border: 0;
443
+ color: $color-text-secondary;
444
+ justify-content: center;
445
+ }
446
+
419
447
  &.button--header--login {
420
448
  border: 2px solid $color-secondary-600;
421
449
  margin: 0;
@@ -260,13 +260,14 @@
260
260
  width: 100%;
261
261
  z-index: $nav-bar-level;
262
262
 
263
- .button--menu {
264
- border-radius: 0;
263
+ .button--menu:hover,
264
+ .button--menu:focus, {
265
+ font-weight: normal;
266
+ }
265
267
 
266
- &:hover,
267
- &:focus {
268
- font-weight: normal;
269
- }
268
+ .button--pill:hover,
269
+ .button--pill:focus, {
270
+ font-weight: 600;
270
271
  }
271
272
 
272
273
  .button--menu--secondary {
@@ -20,9 +20,9 @@
20
20
  .popup-box {
21
21
  background-color: $color-background-secondary;
22
22
  box-shadow: 0 0 4 * $spacing $color-background-box-shadow;
23
- margin: 20% auto 0;
23
+ margin: 10% auto;
24
24
  overflow: hidden;
25
- width: 460px;
25
+ width: 520px;
26
26
 
27
27
  .popup-box__msg {
28
28
  @include _padding(0px, 5 * $spacing, 5 * $spacing, 5 * $spacing);
@@ -47,6 +47,7 @@
47
47
  .popup-box__title {
48
48
  @include _padding(5 * $spacing, 5 * $spacing, 0px, 5 * $spacing);
49
49
  background-color: $color-background-secondary;
50
+ color: $color-text-primary;
50
51
  display: flex;
51
52
  justify-content: flex-start;
52
53
  font-family: "Space Grotesk", sans-serif;
@@ -57,6 +58,10 @@
57
58
  min-width:0;
58
59
  @include _margin(8px, 8px, 8px, 8px);
59
60
  }
61
+
62
+ label {
63
+ text-align: left;
64
+ }
60
65
  }
61
66
 
62
67
  &#screentime-popup,
@@ -32,7 +32,6 @@
32
32
  type="image/x-icon">
33
33
  {% endblock css %}
34
34
  {% include "portal/tag_manager/tag_manager_head.html" %}
35
-
36
35
  <script type="text/javascript" src="{% static 'portal/js/lib/modernizr-build.js' %}"></script>
37
36
  <script type="text/javascript" src="{% static 'portal/js/common.js' %}"></script>
38
37
  <script type="text/javascript" src="{% static 'portal/js/jquery.placeholder.js' %}"></script>
@@ -82,6 +81,7 @@
82
81
  {% include "portal/tag_manager/tag_manager_body.html" %}
83
82
  {% render_block "js" %}
84
83
  {% include 'portal/mouseflow.html' %}
84
+ {% include "portal/partials/donate_popup.html" %}
85
85
  <div class="content-footer-wrapper">
86
86
  {% block contentWrapper %}
87
87
  <div {% block pageID %}id="contentWrapper"{% endblock %}>
@@ -240,16 +240,25 @@
240
240
  });
241
241
  </script>
242
242
  <script>
243
- // disable newsletter signup button by default
243
+ // disable newsletter signup and donate buttons by default
244
244
  const newsletterSubmitButton = $('#submit_newsletter');
245
245
  newsletterSubmitButton.addClass("disabled");
246
246
  newsletterSubmitButton.prop("disabled", true);
247
247
 
248
- // enable it or disable it depending on age verification checkbox
248
+ const donateSubmitButton = $('#confirm_donate_button');
249
+ donateSubmitButton.addClass("disabled");
250
+ donateSubmitButton.prop("disabled", true);
251
+
252
+ // enable them or disable them depending on age verification checkbox
249
253
  $('#id_age_verification').on("click", function() {
250
254
  newsletterSubmitButton.prop("disabled", !this.checked);
251
255
  newsletterSubmitButton.toggleClass("disabled", !this.checked);
252
256
  });
257
+
258
+ $('#donate_age_verification').on("click", function() {
259
+ donateSubmitButton.prop("disabled", !this.checked);
260
+ donateSubmitButton.toggleClass("disabled", !this.checked);
261
+ })
253
262
  </script>
254
263
  {% endblock scripts %}
255
264
  </body>
@@ -0,0 +1,46 @@
1
+ {% load static %}
2
+ {% load app_tags %}
3
+ {# A popup with a form input for email addresses. #}
4
+ <section id="donate-popup" class="popup-wrapper">
5
+ <div class="popup-box">
6
+ <div>
7
+ <button type="button" onclick="hideDonatePopup()" class="close popup-box__close" aria-label="Close">
8
+ <span class="iconify" data-icon="mdi:close"></span>
9
+ </button>
10
+ </div>
11
+ <div class="popup-box__title"></div>
12
+ <div class="popup-box__msg"></div>
13
+ <form id="donate_form" action="{% url 'process_donate_form' %}"
14
+ method="post">
15
+ <div class="col-sm-12">
16
+ {{ donate_form.non_field_errors }}
17
+ <div class="form--row">
18
+ <div class="form--row__input">
19
+ <label><small>{{ donate_form.email.label }}</small></label>
20
+ <div class="input--icon">
21
+ {{ donate_form.email }}
22
+ <span class="iconify" data-icon="mdi:email-outline"></span>
23
+ </div>
24
+ {{ donate_form.email.errors }}
25
+ <small>{{ donate_form.email.help_text }}</small>
26
+ </div>
27
+ </div>
28
+ <div class="form--row justify-content-between">
29
+ <div class="form__checkbox">
30
+ <div class="form__checkbox-input">
31
+ {{ donate_form.age_verification }}
32
+ </div>
33
+ <p class="p-0">Please confirm that you are over 18.</p>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ <div class="popup-box__buttons">
38
+ <a class="button button--small button--secondary button--secondary--dark"
39
+ onclick="hideDonatePopup()" aria-labelledby="cancel_button">Cancel</a>
40
+ <button type="submit" id="confirm_donate_button"
41
+ class='button button--small button--primary'
42
+ aria-labelledby="confirm_button">Confirm</button>
43
+ </div>
44
+ </form>
45
+ </div>
46
+ </section>
@@ -57,6 +57,7 @@
57
57
  <a class="button--menu button--menu--secondary button--menu--disabled">Games</a>
58
58
  <a class="button--menu button--menu--secondary button--menu--disabled">Teaching Resources</a>
59
59
  {% endif %}
60
+ <button onclick="showDonateConfirmation()" class="button--menu button--pill button--tertiary">Donate</button>
60
61
  {% else %}
61
62
  {% if user|is_independent_student %}
62
63
  <div class="menu--title">Independent</div>
@@ -103,6 +104,7 @@
103
104
  <div class="menu__left-side col-md-5">
104
105
  <a href="{% url 'teach' %}" class="button--menu button--menu--primary button--menu--enabled">Teachers</a>
105
106
  <a href="{% url 'play' %}" class="button--menu button--menu--primary button--menu--enabled">Students</a>
107
+ <button id="donate" onclick="showDonateConfirmation()" class="button--menu button--pill button--tertiary">Donate</button>
106
108
  {% endif %}
107
109
  </div>
108
110
  {% if user|is_logged_in %}
@@ -145,36 +147,36 @@
145
147
  {% endif %}
146
148
  </ul>
147
149
  </div>
148
- {% else %}
149
- <div class="menu__right-side col-md-5">
150
- <a href="{% url 'register' %}" id="signup_button" class="button button--primary button--register register">Register</a>
151
- <div class="dropdown">
152
- <button id="login_dropdown" class="button--regular button--secondary button--header--login button--dropdown"
153
- data-toggle="dropdown">
154
- <div class="dropdown__text">Log in</div>
155
- </button>
156
- <ul class="dropdown-menu header__login-options-dropdown-menu">
157
- <li class="dropdown-menu__option">
158
- <a id="teacher_login_button" class="button--regular" aria-labelledby="Teacher" href="{% url 'teacher_login' %}">
159
- <div class="dropdown-menu__option__text">Teacher</div>
160
- <span data-nosnippet class="material-icons-outlined">chevron_right</span>
161
- </a>
162
- </li>
163
- <li class="dropdown-menu__option">
164
- <a id="student_login_button" class="button--regular" aria-labelledby="Student" href="{% url 'student_login_access_code' %}">
165
- <div class="dropdown-menu__option__text">Student</div>
166
- <span data-nosnippet class="material-icons-outlined">chevron_right</span>
167
- </a>
168
- </li>
169
- <li class="dropdown-menu__option">
170
- <a id="independent_login_button" class="button--regular" aria-labelledby="Independent" href="{% url 'independent_student_login' %}">
171
- <div class="dropdown-menu__option__text">Independent</div>
172
- <span data-nosnippet class="material-icons-outlined">chevron_right</span>
173
- </a>
174
- </li>
175
- </ul>
176
- </div>
177
- {% endif %}
150
+ {% else %}
151
+ <div class="menu__right-side col-md-5">
152
+ <a href="{% url 'register' %}" id="signup_button" class="button button--primary button--register register">Register</a>
153
+ <div class="dropdown">
154
+ <button id="login_dropdown" class="button--regular button--secondary button--header--login button--dropdown"
155
+ data-toggle="dropdown">
156
+ <div class="dropdown__text">Log in</div>
157
+ </button>
158
+ <ul class="dropdown-menu header__login-options-dropdown-menu">
159
+ <li class="dropdown-menu__option">
160
+ <a id="teacher_login_button" class="button--regular" aria-labelledby="Teacher" href="{% url 'teacher_login' %}">
161
+ <div class="dropdown-menu__option__text">Teacher</div>
162
+ <span data-nosnippet class="material-icons-outlined">chevron_right</span>
163
+ </a>
164
+ </li>
165
+ <li class="dropdown-menu__option">
166
+ <a id="student_login_button" class="button--regular" aria-labelledby="Student" href="{% url 'student_login_access_code' %}">
167
+ <div class="dropdown-menu__option__text">Student</div>
168
+ <span data-nosnippet class="material-icons-outlined">chevron_right</span>
169
+ </a>
170
+ </li>
171
+ <li class="dropdown-menu__option">
172
+ <a id="independent_login_button" class="button--regular" aria-labelledby="Independent" href="{% url 'independent_student_login' %}">
173
+ <div class="dropdown-menu__option__text">Independent</div>
174
+ <span data-nosnippet class="material-icons-outlined">chevron_right</span>
175
+ </a>
176
+ </li>
177
+ </ul>
178
+ </div>
179
+ {% endif %}
178
180
  </div>
179
181
  </div>
180
182
  <div id="menu-items" class="collapse">
@@ -239,6 +241,8 @@
239
241
  {% else %}
240
242
  <a class="button button--menu__item button--register"
241
243
  href="{% url 'register' %}">Register now</a>
244
+ <button onclick="showDonateConfirmation()"
245
+ class="button--menu__item button--donate">Donate</button>
242
246
  <button class="button--menu__item button--menu__item--sub-header login"
243
247
  data-toggle="collapse" data-target="#login-tabs">Log in</button>
244
248
  <div id="login-tabs" class="collapse">
@@ -10,6 +10,7 @@ from common.helpers.emails import (
10
10
  send_dotmailer_consent_confirmation_email_to_user,
11
11
  DotmailerUserType,
12
12
  )
13
+ from common.mail import address_book_ids
13
14
  from django.test import Client
14
15
  from django.urls import reverse
15
16
 
@@ -21,7 +22,6 @@ from example_project.portal_test_settings import (
21
22
  DOTMAILER_THANKS_FOR_STAYING_CAMPAIGN_ID,
22
23
  DOTMAILER_CREATE_CONTACT_URL,
23
24
  DOTMAILER_DELETE_USER_BY_ID_URL,
24
- DOTMAILER_MAIN_ADDRESS_BOOK_URL,
25
25
  DOTMAILER_TEACHER_ADDRESS_BOOK_URL,
26
26
  DOTMAILER_STUDENT_ADDRESS_BOOK_URL,
27
27
  DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL,
@@ -47,7 +47,11 @@ def test_newsletter_calls_correct_requests(mocker, monkeypatch):
47
47
  )
48
48
 
49
49
  add_to_dotmailer(
50
- "Ray", "Charles", "ray.charles@example.com", DotmailerUserType.TEACHER
50
+ "Ray",
51
+ "Charles",
52
+ "ray.charles@example.com",
53
+ address_book_ids["newsletter"],
54
+ DotmailerUserType.TEACHER,
51
55
  )
52
56
 
53
57
  mocked_create_contact.assert_called_once()
@@ -121,17 +125,15 @@ def test_newsletter_sends_correct_request_data(
121
125
  )
122
126
 
123
127
  add_contact_to_address_book(
124
- "Ray", "Charles", "ray.charles@example.com", DotmailerUserType.TEACHER
128
+ "Ray",
129
+ "Charles",
130
+ "ray.charles@example.com",
131
+ address_book_ids["newsletter"],
132
+ DotmailerUserType.TEACHER,
125
133
  )
126
134
 
127
135
  assert mocked_post.call_count == 3
128
136
 
129
- mocked_post.assert_any_call(
130
- DOTMAILER_MAIN_ADDRESS_BOOK_URL,
131
- auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
132
- json=expected_body2,
133
- )
134
-
135
137
  mocked_post.assert_any_call(
136
138
  DOTMAILER_TEACHER_ADDRESS_BOOK_URL,
137
139
  auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
@@ -141,17 +143,15 @@ def test_newsletter_sends_correct_request_data(
141
143
  mocked_post.reset_mock()
142
144
 
143
145
  add_contact_to_address_book(
144
- "Ray", "Charles", "ray.charles@example.com", DotmailerUserType.STUDENT
146
+ "Ray",
147
+ "Charles",
148
+ "ray.charles@example.com",
149
+ address_book_ids["newsletter"],
150
+ DotmailerUserType.STUDENT,
145
151
  )
146
152
 
147
153
  assert mocked_post.call_count == 2
148
154
 
149
- mocked_post.assert_any_call(
150
- DOTMAILER_MAIN_ADDRESS_BOOK_URL,
151
- auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
152
- json=expected_body2,
153
- )
154
-
155
155
  mocked_post.assert_any_call(
156
156
  DOTMAILER_STUDENT_ADDRESS_BOOK_URL,
157
157
  auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
@@ -164,17 +164,12 @@ def test_newsletter_sends_correct_request_data(
164
164
  "Ray",
165
165
  "Charles",
166
166
  "ray.charles@example.com",
167
+ address_book_ids["newsletter"],
167
168
  DotmailerUserType.NO_ACCOUNT,
168
169
  )
169
170
 
170
171
  assert mocked_post.call_count == 2
171
172
 
172
- mocked_post.assert_any_call(
173
- DOTMAILER_MAIN_ADDRESS_BOOK_URL,
174
- auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
175
- json=expected_body2,
176
- )
177
-
178
173
  mocked_post.assert_any_call(
179
174
  DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL,
180
175
  auth=(DOTMAILER_USER, DOTMAILER_PASSWORD),
@@ -2,7 +2,7 @@ from django.urls import reverse
2
2
  from django.test import TestCase, Client
3
3
 
4
4
 
5
- class TestNewsletterFooter(TestCase):
5
+ class TestGlobalForms(TestCase):
6
6
  def test_newsletter_signup_successful(self):
7
7
  url = reverse("process_newsletter_form")
8
8
  client = Client()
@@ -18,3 +18,19 @@ class TestNewsletterFooter(TestCase):
18
18
  response = client.post(url, data)
19
19
  messages = list(response.wsgi_request._messages)
20
20
  assert len([m for m in messages if "error" in m.tags]) == 1
21
+
22
+ def test_donate_signup_successful(self):
23
+ url = reverse("process_donate_form")
24
+ client = Client()
25
+ data = {"email": "valid_email@example.com", "age_verification": "on"}
26
+ response = client.post(url, data)
27
+ messages = list(response.wsgi_request._messages)
28
+ assert len([m for m in messages if m.tags == "success"]) == 1
29
+
30
+ def test_donate_signup_fail(self):
31
+ url = reverse("process_donate_form")
32
+ client = Client()
33
+ data = {"email": "invalid_email", "age_verification": "on"}
34
+ response = client.post(url, data)
35
+ messages = list(response.wsgi_request._messages)
36
+ assert len([m for m in messages if "error" in m.tags]) == 1
portal/urls.py CHANGED
@@ -38,6 +38,7 @@ from portal.views.api import (
38
38
  )
39
39
  from portal.views.dotmailer import (
40
40
  dotmailer_consent_form,
41
+ process_donate_form,
41
42
  process_newsletter_form,
42
43
  )
43
44
  from portal.views.email import verify_email
@@ -278,6 +279,7 @@ urlpatterns = [
278
279
  process_newsletter_form,
279
280
  name="process_newsletter_form",
280
281
  ),
282
+ url(r"^donate_signup/$", process_donate_form, name="process_donate_form"),
281
283
  url(r"^consent_form/$", dotmailer_consent_form, name="consent_form"),
282
284
  url(
283
285
  r"^verify_email/$",
portal/views/dotmailer.py CHANGED
@@ -5,13 +5,14 @@ from common.helpers.emails import (
5
5
  add_consent_record_to_dotmailer_user,
6
6
  DotmailerUserType,
7
7
  )
8
+ from common.mail import address_book_ids
8
9
  from django.contrib import messages as messages
9
10
  from django.http import HttpResponseRedirect, HttpResponse
10
11
  from django.shortcuts import render
11
12
  from django.urls import reverse_lazy
12
13
  from django.views.decorators.csrf import csrf_exempt
13
14
 
14
- from portal.forms.dotmailer import NewsletterForm, ConsentForm
15
+ from portal.forms.dotmailer import NewsletterForm, DonateForm, ConsentForm
15
16
 
16
17
 
17
18
  @csrf_exempt
@@ -20,7 +21,13 @@ def process_newsletter_form(request):
20
21
  newsletter_form = NewsletterForm(data=request.POST)
21
22
  if newsletter_form.is_valid():
22
23
  user_email = newsletter_form.cleaned_data["email"]
23
- add_to_dotmailer("", "", user_email, DotmailerUserType.NO_ACCOUNT)
24
+ add_to_dotmailer(
25
+ "",
26
+ "",
27
+ user_email,
28
+ address_book_ids["newsletter"],
29
+ DotmailerUserType.NO_ACCOUNT,
30
+ )
24
31
  messages.success(request, "Thank you for signing up! 🎉")
25
32
  return HttpResponseRedirect(reverse_lazy("home"))
26
33
  messages.error(
@@ -33,6 +40,27 @@ def process_newsletter_form(request):
33
40
  return HttpResponse(status=405)
34
41
 
35
42
 
43
+ @csrf_exempt
44
+ def process_donate_form(request):
45
+ if request.method == "POST":
46
+ donate_form = DonateForm(data=request.POST)
47
+ if donate_form.is_valid():
48
+ user_email = request.POST.get("email", "")
49
+ add_to_dotmailer("", "", user_email, address_book_ids["donors"])
50
+ messages.success(
51
+ request, "Thank you for registering your interest! 🎉"
52
+ )
53
+ return HttpResponseRedirect(reverse_lazy("home"))
54
+ messages.error(
55
+ request,
56
+ "Invalid email address. Please try again.",
57
+ extra_tags="sub-nav--warning",
58
+ )
59
+ return HttpResponseRedirect(reverse_lazy("home"))
60
+
61
+ return HttpResponse(status=405)
62
+
63
+
36
64
  def dotmailer_consent_form(request):
37
65
  if request.method == "POST":
38
66
  consent_form = ConsentForm(data=request.POST)