Repository: LibraryOfCongress/concordia

Issue:
Split messages into a separate AJAX call
This avoids the performance impact of not being able to make our session status code cacheable:

https://github.com/LibraryOfCongress/concordia/blob/3d66d95b9566609efe555a898af34e33d373e1af/concordia/views.py#L179-L181


Discussion:

Resolving patch:
diff --git a/concordia/urls.py b/concordia/urls.py
--- a/concordia/urls.py
+++ b/concordia/urls.py
@@ -93,6 +93,7 @@
     ),
     path("assets/<int:asset_pk>/tags/submit/", views.submit_tags, name="submit-tags"),
     path("account/ajax-status/", views.ajax_session_status, name="ajax-session-status"),
+    path("account/ajax-messages/", views.ajax_messages, name="ajax-messages"),
     path(
         "account/register/",
         views.ConcordiaRegistrationView.as_view(),
diff --git a/concordia/views.py b/concordia/views.py
--- a/concordia/views.py
+++ b/concordia/views.py
@@ -150,7 +150,7 @@ def static_page(request, base_name=None):
     return render(request, "static-page.html", ctx)
 
 
-@never_cache
+@cache_control(private=True, no_transform=True, max_age=settings.DEFAULT_PAGE_TTL)
 @csrf_exempt
 def ajax_session_status(request):
     """
@@ -176,19 +176,29 @@ def ajax_session_status(request):
                 }
             )
 
-        # TODO: we should determine whether there's enough performance impact
-        # that it would be better to make this view cacheable and move messages
-        # into a separate view:
-        messages = [
-            {"level": MESSAGE_LEVEL_NAMES[i.level], "message": i.message}
-            for i in get_messages(request)
-        ]
-
-        res = {"username": user.username, "links": links, "messages": messages}
+        res = {"username": user.username, "links": links}
 
     return JsonResponse(res)
 
 
+@never_cache
+@login_required
+@csrf_exempt
+def ajax_messages(request):
+    """
+    Returns any messages queued for the current user
+    """
+
+    return JsonResponse(
+        {
+            "messages": [
+                {"level": MESSAGE_LEVEL_NAMES[i.level], "message": i.message}
+                for i in get_messages(request)
+            ]
+        }
+    )
+
+
 @method_decorator(never_cache, name="dispatch")
 class ConcordiaRegistrationView(RegistrationView):
     form_class = UserRegistrationForm


Test patch:
diff --git a/concordia/tests/test_view.py b/concordia/tests/test_view.py
--- a/concordia/tests/test_view.py
+++ b/concordia/tests/test_view.py
@@ -290,11 +290,21 @@ def test_ajax_session_status(self):
 
         self.assertIn("links", data)
         self.assertIn("username", data)
-        self.assertIn("messages", data)
 
         self.assertEqual(data["username"], self.user.username)
 
-        # The inclusion of messages means that this view cannot currently be cached:
+        self.assertIn("private", resp["Cache-Control"])
+
+    def test_ajax_messages(self):
+        self.login_user()
+
+        resp = self.client.get(reverse("ajax-messages"))
+        data = self.assertValidJSON(resp)
+
+        self.assertIn("messages", data)
+
+        # This view cannot be cached because the messages would be displayed
+        # multiple times:
         self.assertIn("no-cache", resp["Cache-Control"])