From 352ded6c40b97d5217bb1c585fe358a918942d6f Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Tue, 12 Nov 2024 13:36:13 +0000
Subject: [PATCH 1/9] retrieve csrf token in the same way as inline feedback
---
domestic/static/javascript/hcsat-feedback-form.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/domestic/static/javascript/hcsat-feedback-form.js b/domestic/static/javascript/hcsat-feedback-form.js
index f23e3480af..aedbab4b8f 100644
--- a/domestic/static/javascript/hcsat-feedback-form.js
+++ b/domestic/static/javascript/hcsat-feedback-form.js
@@ -31,10 +31,12 @@ class CsatFormHandler {
this.resetForm();
}
try {
+ const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value
+ console.log('csrfToken:',csrfToken)
const response = await fetch(`${url}?js_enabled=True`, {
method: 'POST',
headers: {
- 'X-CSRFToken': formData.get('csrfmiddlewaretoken'),
+ 'X-CSRFToken': csrfToken,
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
From 50aec6220050c40a11efd70443d77cbe230fd71c Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Tue, 12 Nov 2024 14:37:29 +0000
Subject: [PATCH 2/9] cache_control no cache added to post
---
domestic/static/javascript/hcsat-feedback-form.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/domestic/static/javascript/hcsat-feedback-form.js b/domestic/static/javascript/hcsat-feedback-form.js
index aedbab4b8f..2395c2629d 100644
--- a/domestic/static/javascript/hcsat-feedback-form.js
+++ b/domestic/static/javascript/hcsat-feedback-form.js
@@ -36,6 +36,7 @@ class CsatFormHandler {
const response = await fetch(`${url}?js_enabled=True`, {
method: 'POST',
headers: {
+ 'cache_control': 'no-cache',
'X-CSRFToken': csrfToken,
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
From 27ae90ec42f97de181571b2834de96b807d278ba Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Tue, 12 Nov 2024 14:42:19 +0000
Subject: [PATCH 3/9] revert last change to confirm if wagtail cache is causing
error
---
domestic/static/javascript/hcsat-feedback-form.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/domestic/static/javascript/hcsat-feedback-form.js b/domestic/static/javascript/hcsat-feedback-form.js
index 2395c2629d..aedbab4b8f 100644
--- a/domestic/static/javascript/hcsat-feedback-form.js
+++ b/domestic/static/javascript/hcsat-feedback-form.js
@@ -36,7 +36,6 @@ class CsatFormHandler {
const response = await fetch(`${url}?js_enabled=True`, {
method: 'POST',
headers: {
- 'cache_control': 'no-cache',
'X-CSRFToken': csrfToken,
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
From fe74957b96260c9491aa0cbb347bd745fbf4c9fd Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Tue, 12 Nov 2024 15:06:09 +0000
Subject: [PATCH 4/9] wagtail cache is the issue, re-adding cache-control to
post
---
domestic/static/javascript/hcsat-feedback-form.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/domestic/static/javascript/hcsat-feedback-form.js b/domestic/static/javascript/hcsat-feedback-form.js
index aedbab4b8f..2395c2629d 100644
--- a/domestic/static/javascript/hcsat-feedback-form.js
+++ b/domestic/static/javascript/hcsat-feedback-form.js
@@ -36,6 +36,7 @@ class CsatFormHandler {
const response = await fetch(`${url}?js_enabled=True`, {
method: 'POST',
headers: {
+ 'cache_control': 'no-cache',
'X-CSRFToken': csrfToken,
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
From 43f19dadc64b832f53c13e7f37e9faa4019c5b13 Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Tue, 12 Nov 2024 15:43:48 +0000
Subject: [PATCH 5/9] no_cache added to learn article page view
---
core/models.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/core/models.py b/core/models.py
index 5ea88182cd..a43b93f9e4 100644
--- a/core/models.py
+++ b/core/models.py
@@ -764,7 +764,12 @@ def serve(self, request):
return self._redirect_to_parent_module()
-class DetailPage(settings.FEATURE_DEA_V2 and CMSGenericPageAnonymous or CMSGenericPage, mixins.HCSATMixin):
+from wagtailcache.cache import WagtailCacheMixin
+
+
+class DetailPage(
+ settings.FEATURE_DEA_V2 and CMSGenericPageAnonymous or CMSGenericPage, mixins.HCSATMixin, WagtailCacheMixin
+):
estimated_read_duration = models.DurationField(null=True, blank=True)
parent_page_types = [
'core.CuratedListPage', # TEMPORARY: remove after topics refactor migration has run
@@ -778,6 +783,9 @@ class Meta:
verbose_name = 'Detail page'
verbose_name_plural = 'Detail pages'
+ def cache_control(self):
+ return 'no-cache'
+
################
# Content fields
################
From 22f1fb02ea6c3c4a0add4f9bf195fcf0f9ec9c9e Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Wed, 13 Nov 2024 12:09:05 +0000
Subject: [PATCH 6/9] added clear_cache wagtail tag for hcsat template fragment
in learn article page
---
core/templatetags/clear_cache.py | 50 ++++++++++++++++++++++++++
learn/templates/learn/detail_page.html | 5 +++
2 files changed, 55 insertions(+)
create mode 100644 core/templatetags/clear_cache.py
diff --git a/core/templatetags/clear_cache.py b/core/templatetags/clear_cache.py
new file mode 100644
index 0000000000..705ad57e1d
--- /dev/null
+++ b/core/templatetags/clear_cache.py
@@ -0,0 +1,50 @@
+from django import template
+from django.core.cache import cache
+from urllib.parse import quote
+from hashlib import md5
+
+register = template.Library()
+
+
+class ClearCacheNode(template.Node):
+ def __init__(self, fragment_name, vary_on):
+ self.fragment_name = fragment_name
+ self.vary_on = vary_on
+
+ def render(self, context):
+ # Build a unicode key for this fragment and all vary-on's.
+ args = md5(
+ u':'.join([quote(template.Variable('request').resolve(var, context)) for var in self.vary_on]).encode(
+ 'utf-8'
+ )
+ )
+ cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
+ cache.delete(cache_key)
+ return ''
+
+
+@register.simple_tag
+def clear_cache(parser, token):
+ """
+ This will clear the cache for a template fragment
+
+ Usage::
+
+ {% load clearcache %}
+ {% clearcache [fragment_name] %}
+
+ This tag also supports varying by a list of arguments::
+
+ {% load clearcache %}
+ {% clearcache [fragment_name] [var1] [var2] .. %}
+
+ The set of arguments must be the same as the original cache tag (except for expire_time).
+ """
+ try:
+ tokens = token.split_contents()
+ except ValueError:
+ raise template.TemplateSyntaxError('%r tag requires at least one argument' % token.contents.split()[0])
+ return ClearCacheNode(tokens[1], tokens[2:])
+
+
+register.tag('clear_cache', clear_cache)
diff --git a/learn/templates/learn/detail_page.html b/learn/templates/learn/detail_page.html
index 6393bc9977..7b12dacd8f 100644
--- a/learn/templates/learn/detail_page.html
+++ b/learn/templates/learn/detail_page.html
@@ -94,6 +94,9 @@
Explore the topic
{% endif %}
{% include 'learn/promo.html' with bg_class='great-bg-light-blue' %}
{% block body_inline_feedback %}{% endblock %}
+{% load clear_cache %}
+{% clear_cache hcsat %}
+{% block hcsat %}
{% if not csat_complete %}
@@ -103,6 +106,8 @@ Explore the topic
{% endif %}
{% endblock %}
+{% clear_cache hcsat %}
+{% endblock %}
{% block body_js %}
{{ block.super }}
From 62e838e24c405103f144357b1da415c0764c8b4c Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Wed, 13 Nov 2024 16:50:54 +0000
Subject: [PATCH 7/9] csrf token generator created but not used, csrf protect
decorator added to serve which I think will fix
---
core/models.py | 9 +++------
core/urls.py | 1 +
core/views.py | 15 +++++++++++++++
domestic/static/javascript/hcsat-feedback-form.js | 12 ++++++++++--
4 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/core/models.py b/core/models.py
index a43b93f9e4..bbf0abbcd5 100644
--- a/core/models.py
+++ b/core/models.py
@@ -73,6 +73,8 @@
SECTION_SLUGS as EXPORTPLAN_SLUGS,
SECTIONS as EXPORTPLAN_URL_MAP,
)
+from django.utils.decorators import method_decorator
+from django.views.decorators.csrf import csrf_protect
# If we make a Redirect appear as a Snippet, we can sync it via Wagtail-Transfer
register_snippet(Redirect)
@@ -764,9 +766,6 @@ def serve(self, request):
return self._redirect_to_parent_module()
-from wagtailcache.cache import WagtailCacheMixin
-
-
class DetailPage(
settings.FEATURE_DEA_V2 and CMSGenericPageAnonymous or CMSGenericPage, mixins.HCSATMixin, WagtailCacheMixin
):
@@ -783,9 +782,6 @@ class Meta:
verbose_name = 'Detail page'
verbose_name_plural = 'Detail pages'
- def cache_control(self):
- return 'no-cache'
-
################
# Content fields
################
@@ -1102,6 +1098,7 @@ def form_valid(self, form, request):
return JsonResponse({'pk': hcsat.pk})
return HttpResponseRedirect(self.get_success_url(request))
+ @method_decorator(csrf_protect, name='post')
def serve(self, request, *args, **kwargs):
self.handle_page_view(request)
diff --git a/core/urls.py b/core/urls.py
index d63872c83a..1281bc0db7 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -175,6 +175,7 @@ def anonymous_user_required(function):
name='campaign-site',
),
path('api/signed-url/', views.SignedURLView.as_view(), name='signed-url'),
+ path('api/getcsrftoken/', views.CSRFView.as_view(), name='csrftoken'),
# WHEN ADDING TO THIS LIST CONSIDER WHETHER YOU SHOULD ALSO ADD THE URL NAME
# TO core.views.StaticViewSitemap
]
diff --git a/core/views.py b/core/views.py
index efb0f57665..81fa51ed29 100644
--- a/core/views.py
+++ b/core/views.py
@@ -55,6 +55,8 @@
from domestic.models import DomesticDashboard, TopicLandingPage
from export_academy.models import Event
from sso.views import SSOBusinessUserLogoutView
+from django.middleware.csrf import get_token
+from rest_framework.views import APIView
logger = logging.getLogger(__name__)
@@ -966,3 +968,16 @@ def get_context_data(self, **kwargs):
ukea_events=ukea_events,
market_guide=market_guide,
)
+
+
+@method_decorator(never_cache, name='dispatch')
+class CSRFView(APIView):
+ permission_classes = []
+ authentication_classes = []
+
+ def _get_token(self, request):
+ token = get_token(request)
+ return JsonResponse(status=200, data={'csrftoken': token})
+
+ def dispatch(self, request, *args, **kwargs):
+ return self._get_token(request)
diff --git a/domestic/static/javascript/hcsat-feedback-form.js b/domestic/static/javascript/hcsat-feedback-form.js
index 2395c2629d..76135df3be 100644
--- a/domestic/static/javascript/hcsat-feedback-form.js
+++ b/domestic/static/javascript/hcsat-feedback-form.js
@@ -31,13 +31,21 @@ class CsatFormHandler {
this.resetForm();
}
try {
- const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value
+ const oldCsrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value
+ const csrfTokenFetch = await fetch('/api/getcsrftoken/', {
+ method: 'GET',
+ headers: {
+ 'cache_control': 'no-cache',
+ }
+ })
+ const csrfTokenJson = await csrfTokenFetch.json()
+ const csrfToken = csrfTokenJson.csrftoken
console.log('csrfToken:',csrfToken)
const response = await fetch(`${url}?js_enabled=True`, {
method: 'POST',
headers: {
'cache_control': 'no-cache',
- 'X-CSRFToken': csrfToken,
+ 'X-CSRFToken': oldCsrfToken,
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
From 90c6077977d4a07cb9b5d151196f8da5464ef7fb Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Wed, 13 Nov 2024 16:58:23 +0000
Subject: [PATCH 8/9] syntax fix on csrf token generator
---
core/views.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/core/views.py b/core/views.py
index 81fa51ed29..b234975114 100644
--- a/core/views.py
+++ b/core/views.py
@@ -55,6 +55,7 @@
from domestic.models import DomesticDashboard, TopicLandingPage
from export_academy.models import Event
from sso.views import SSOBusinessUserLogoutView
+from django.views.decorators.cache import never_cache
from django.middleware.csrf import get_token
from rest_framework.views import APIView
From 83f55d65ede0764c3c4d8e57750bdd906203ad20 Mon Sep 17 00:00:00 2001
From: Jamie Fox <134952460+FoxJamie16@users.noreply.github.com>
Date: Fri, 22 Nov 2024 09:14:04 +0000
Subject: [PATCH 9/9] more snippet caching attempts but none working so far
---
core/templatetags/clear_cache.py | 15 ++++++++++++++-
learn/templates/learn/detail_page.html | 3 +++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/core/templatetags/clear_cache.py b/core/templatetags/clear_cache.py
index 705ad57e1d..95ec0abf95 100644
--- a/core/templatetags/clear_cache.py
+++ b/core/templatetags/clear_cache.py
@@ -18,8 +18,20 @@ def render(self, context):
'utf-8'
)
)
+ from django.core.cache.utils import make_template_fragment_key
+
cache_key = 'template.cache.%s.%s' % (self.fragment_name, args.hexdigest())
- cache.delete(cache_key)
+ print('clear-cache key', cache_key)
+ from django.core.cache import cache
+
+ key = make_template_fragment_key('hcsat')
+
+ result2 = cache.delete(key)
+ result1 = cache.delete_many(keys=cache.keys('*hcsat*'))
+ result = cache.delete(cache_key)
+ print('result', result)
+ print('result1', result1)
+ print('result2', result2)
return ''
@@ -42,6 +54,7 @@ def clear_cache(parser, token):
"""
try:
tokens = token.split_contents()
+ print('tokens', tokens)
except ValueError:
raise template.TemplateSyntaxError('%r tag requires at least one argument' % token.contents.split()[0])
return ClearCacheNode(tokens[1], tokens[2:])
diff --git a/learn/templates/learn/detail_page.html b/learn/templates/learn/detail_page.html
index 7b12dacd8f..d9f02ce571 100644
--- a/learn/templates/learn/detail_page.html
+++ b/learn/templates/learn/detail_page.html
@@ -96,6 +96,8 @@ Explore the topic
{% block body_inline_feedback %}{% endblock %}
{% load clear_cache %}
{% clear_cache hcsat %}
+{% load cache %}
+{% cache 500 hcsat %}
{% block hcsat %}
{% if not csat_complete %}
{% endif %}
{% endblock %}
+{% endcache %}
{% clear_cache hcsat %}
{% endblock %}
{% block body_js %}