Repository: alan-turing-institute/autspaces
Issue: [BUG]: Viewing public experience crashes for Anon. users

### Describe the bug

Currently it is not possible to view the publicly shared experiences unless one is logged in. As a logged-out user one encounters the following error:

`Field 'id' expected a number but got <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x400f471df0>>.`

The problem is that in line 335 of the `views.py` we load the user profile as `profile = UserProfile.objects.get(user=request.user)`, but non-logged in users have no expanded profile, so we need to catch that case :-) 

### Steps to reproduce

1. Log out of AutSPACEs, 
2. browse to `/main/public_experiences`
3. et voilà 😉 

### In which environment are you using AutSPACEs?

_No response_

### Other comments

_No response_

Changed files:
server/apps/main/tests/test_views.py, server/apps/main/views.py, server/apps/users/views.py

diff --git a/server/apps/main/tests/test_views.py b/server/apps/main/tests/test_views.py
index 8f536b3..4a1a182 100644
--- a/server/apps/main/tests/test_views.py
+++ b/server/apps/main/tests/test_views.py
@@ -532,6 +532,8 @@ class Views(TestCase):
         c = Client()
         c.force_login(self.user_a)
         response = c.post("/main/public_experiences/")
+        assert response.status_code == 200
+        self.assertTemplateUsed(response, "main/experiences_page.html")
 
         # Check that there is only one story visible - the one with no triggering labels
         for item in response.context[0]:
@@ -583,6 +585,8 @@ class Views(TestCase):
         c = Client()
         c.force_login(self.user_c)
         response = c.post("/main/public_experiences/")
+        assert response.status_code == 200
+        self.assertTemplateUsed(response, "main/experiences_page.html")
 
         # We're not going to set the abuse flag, but it should be pulled in from the user profile
         # There should be 2 stories one with no tags one with the abuse tag
@@ -619,6 +623,58 @@ class Views(TestCase):
             if item.keys().__contains__("experiences"):
                assert len(item['experiences']) == 0
 
+    def test_list_public_exp_anonymous_user(self):
+        """
+        Checks the public experience search given no user is logged in
+        """
+        c = Client()
+        response = c.post("/main/public_experiences/")
+        assert response.status_code == 200
+        self.assertTemplateUsed(response, "main/experiences_page.html")
+
+        # Check that there is only one story visible - the one with no triggering labels
+        for item in response.context[0]:
+            if item.keys().__contains__("experiences"):
+                assert len(item['experiences']) == 1
+
+        # If you allow the abuse tag there should be 2 stories one with no tags one with the abuse tag
+        search_response_abuse = c.get("/main/public_experiences/", {"searched": "", "abuse": True})
+        for item in search_response_abuse.context[0]:
+            if item.keys().__contains__("experiences"):
+                assert len(item['experiences']) == 2
+
+        # Results for story containing caramel is none as there is no triggering warning tag used
+        search_response_c = c.get("/main/public_experiences/", {"searched": "caramel"})
+        for item in search_response_c.context[0]:
+            if item.keys().__contains__("experiences"):
+               assert len(item['experiences'])==  0
+
+        # Results for story containing caramel when the wrong trigger label is used is 0
+        search_response_c_nb = c.get("/main/public_experiences/", {"searched": "caramel", "negbody": True})
+        for item in search_response_c_nb.context[0]:
+            if item.keys().__contains__("experiences"):
+               assert len(item['experiences']) ==  0
+
+        # Results for story containing caramel is 1 when there is no triggering warning tag used
+        search_response_c = c.get("/main/public_experiences/", {"searched": "caramel", "all_triggers": True})
+        for item in search_response_c.context[0]:
+            if item.keys().__contains__("experiences"):
+               assert len(item['experiences']) ==  1
+
+        # Results for story containing sausages is no stories
+        search_response = c.get("/main/public_experiences/", {"searched": "sausages"})
+        for item in search_response.context[0]:
+            if item.keys().__contains__("experiences"):
+                assert len(item['experiences']) ==  0
+
+        # One triggering story visible
+        search_response_t = c.get(
+            "/main/public_experiences/", {"searched": "", "triggering_stories": "True"}
+        )
+        for item in search_response_t.context[0]:
+            if item.keys().__contains__("experiences"):
+                assert len(item['experiences']) == 1
+
     def test_single_story(self):
         c = Client()
         c.force_login(self.user_a)
diff --git a/server/apps/main/views.py b/server/apps/main/views.py
index 101a991..380a7c6 100644
--- a/server/apps/main/views.py
+++ b/server/apps/main/views.py
@@ -334,13 +334,11 @@ def list_public_experiences(request):
         # Check the allowed triggers
         allowed_triggers = set(request.GET.keys())
 
-    if "searched" not in request.GET:
-        try:
-            profile = UserProfile.objects.get(user=request.user)
+    if request.user.is_authenticated and "searched" not in request.GET:
+        profile = get_user_profile(request.user)
+        if profile:
             user_data = model_to_dict(profile)
             allowed_triggers = set([key for key in user_data if user_data[key]])
-        except UserProfile.DoesNotExist:
-            pass
 
     # Get a list of allowed triggers
     triggers_to_show = extract_triggers_to_show(allowed_triggers)
diff --git a/server/apps/users/views.py b/server/apps/users/views.py
index 9c07feb..7d4148b 100644
--- a/server/apps/users/views.py
+++ b/server/apps/users/views.py
@@ -10,6 +10,7 @@ from .models import UserProfile
 from .forms import UserProfileForm
 from .helpers import (
     user_profile_exists,
+    get_user_profile,
 )
 
 logger = logging.getLogger(__name__)
@@ -30,13 +31,13 @@ def user_profile(request, first_visit=False):
 
             return redirect("users:profile")
         else:
-            try:
-                profile = UserProfile.objects.get(user=request.user)
+            profile = get_user_profile(request.user)
+            if profile:
                 data = model_to_dict(profile)
                 # If the profile has been submitted this can't be the user's first visit
                 first_visit &= not profile.profile_submitted
                 form = UserProfileForm(data)
-            except UserProfile.DoesNotExist:
+            else:
                 form = UserProfileForm()
             oh_member = request.user.openhumansmember
             return render(