diff --git a/bookmarks/middlewares.py b/bookmarks/middlewares.py
index 981137f..af7ff12 100644
--- a/bookmarks/middlewares.py
+++ b/bookmarks/middlewares.py
@@ -1,13 +1,17 @@
from django.conf import settings
from django.contrib.auth.middleware import RemoteUserMiddleware
-from bookmarks.models import UserProfile
+from bookmarks.models import UserProfile, GlobalSettings
class CustomRemoteUserMiddleware(RemoteUserMiddleware):
header = settings.LD_AUTH_PROXY_USERNAME_HEADER
+standard_profile = UserProfile()
+standard_profile.enable_favicons = True
+
+
class UserProfileMiddleware:
def __init__(self, get_response):
self.get_response = get_response
@@ -16,8 +20,16 @@ class UserProfileMiddleware:
if request.user.is_authenticated:
request.user_profile = request.user.profile
else:
- request.user_profile = UserProfile()
- request.user_profile.enable_favicons = True
+ # check if a custom profile for guests exists, otherwise use standard profile
+ guest_profile = None
+ try:
+ global_settings = GlobalSettings.get()
+ if global_settings.guest_profile_user:
+ guest_profile = global_settings.guest_profile_user.profile
+ except:
+ pass
+
+ request.user_profile = guest_profile or standard_profile
response = self.get_response(request)
diff --git a/bookmarks/migrations/0038_globalsettings_guest_profile_user.py b/bookmarks/migrations/0038_globalsettings_guest_profile_user.py
new file mode 100644
index 0000000..6950e9c
--- /dev/null
+++ b/bookmarks/migrations/0038_globalsettings_guest_profile_user.py
@@ -0,0 +1,26 @@
+# Generated by Django 5.0.8 on 2024-08-31 17:54
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("bookmarks", "0037_globalsettings"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="globalsettings",
+ name="guest_profile_user",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ]
diff --git a/bookmarks/models.py b/bookmarks/models.py
index 71dda82..f4db7d5 100644
--- a/bookmarks/models.py
+++ b/bookmarks/models.py
@@ -508,6 +508,9 @@ class GlobalSettings(models.Model):
blank=False,
default=LANDING_PAGE_LOGIN,
)
+ guest_profile_user = models.ForeignKey(
+ get_user_model(), on_delete=models.SET_NULL, null=True, blank=True
+ )
@classmethod
def get(cls):
@@ -526,6 +529,8 @@ class GlobalSettings(models.Model):
class GlobalSettingsForm(forms.ModelForm):
class Meta:
model = GlobalSettings
- fields = [
- "landing_page",
- ]
+ fields = ["landing_page", "guest_profile_user"]
+
+ def __init__(self, *args, **kwargs):
+ super(GlobalSettingsForm, self).__init__(*args, **kwargs)
+ self.fields["guest_profile_user"].empty_label = "Standard profile"
diff --git a/bookmarks/templates/settings/general.html b/bookmarks/templates/settings/general.html
index eae24bf..741d8c0 100644
--- a/bookmarks/templates/settings/general.html
+++ b/bookmarks/templates/settings/general.html
@@ -249,7 +249,17 @@ reddit.com/r/Music music reddit
Landing page
{{ global_settings_form.landing_page|add_class:"form-select width-25 width-sm-100" }}
- The page that unauthorized users are redirected to when accessing the root URL.
+ The page that unauthenticated users are redirected to when accessing the root URL.
+
+
+
diff --git a/bookmarks/tests/test_root_view.py b/bookmarks/tests/test_root_view.py
index a02b598..d9f978b 100644
--- a/bookmarks/tests/test_root_view.py
+++ b/bookmarks/tests/test_root_view.py
@@ -5,7 +5,7 @@ from bookmarks.models import GlobalSettings
from bookmarks.tests.helpers import BookmarkFactoryMixin
-class AnonymousViewTestCase(TestCase, BookmarkFactoryMixin):
+class RootViewTestCase(TestCase, BookmarkFactoryMixin):
def test_unauthenticated_user_redirect_to_login_by_default(self):
response = self.client.get(reverse("bookmarks:root"))
self.assertRedirects(response, reverse("login"))
diff --git a/bookmarks/tests/test_settings_general_view.py b/bookmarks/tests/test_settings_general_view.py
index 568a7c7..0f82726 100644
--- a/bookmarks/tests/test_settings_general_view.py
+++ b/bookmarks/tests/test_settings_general_view.py
@@ -469,10 +469,13 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
def test_update_global_settings(self):
superuser = self.setup_superuser()
self.client.force_login(superuser)
+ selectable_user = self.setup_user()
+ # Update global settings
form_data = {
"update_global_settings": "",
"landing_page": GlobalSettings.LANDING_PAGE_SHARED_BOOKMARKS,
+ "guest_profile_user": selectable_user.id,
}
response = self.client.post(reverse("bookmarks:settings.general"), form_data)
self.assertEqual(response.status_code, 200)
@@ -480,6 +483,22 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
global_settings = GlobalSettings.get()
self.assertEqual(global_settings.landing_page, form_data["landing_page"])
+ self.assertEqual(global_settings.guest_profile_user, selectable_user)
+
+ # Revert settings
+ form_data = {
+ "update_global_settings": "",
+ "landing_page": GlobalSettings.LANDING_PAGE_LOGIN,
+ "guest_profile_user": "",
+ }
+ response = self.client.post(reverse("bookmarks:settings.general"), form_data)
+ self.assertEqual(response.status_code, 200)
+ self.assertSuccessMessage(response.content.decode(), "Global settings updated")
+
+ global_settings = GlobalSettings.get()
+ global_settings.refresh_from_db()
+ self.assertEqual(global_settings.landing_page, form_data["landing_page"])
+ self.assertIsNone(global_settings.guest_profile_user)
def test_update_global_settings_should_not_be_called_without_respective_form_action(
self,
diff --git a/bookmarks/tests/test_user_profile_middleware.py b/bookmarks/tests/test_user_profile_middleware.py
new file mode 100644
index 0000000..1713df0
--- /dev/null
+++ b/bookmarks/tests/test_user_profile_middleware.py
@@ -0,0 +1,47 @@
+from django.test import TestCase
+from django.urls import reverse
+
+from bookmarks.models import UserProfile, GlobalSettings
+from bookmarks.tests.helpers import BookmarkFactoryMixin
+from bookmarks.middlewares import standard_profile
+
+
+class UserProfileMiddlewareTestCase(TestCase, BookmarkFactoryMixin):
+ def test_unauthenticated_user_should_use_standard_profile_by_default(self):
+ response = self.client.get(reverse("login"))
+
+ self.assertEqual(standard_profile, response.wsgi_request.user_profile)
+
+ def test_unauthenticated_user_should_use_custom_configured_profile(self):
+ guest_user = self.setup_user()
+ guest_user_profile = guest_user.profile
+ guest_user_profile.theme = UserProfile.THEME_DARK
+ guest_user_profile.save()
+
+ global_settings = GlobalSettings.get()
+ global_settings.guest_profile_user = guest_user
+ global_settings.save()
+
+ response = self.client.get(reverse("login"))
+
+ self.assertEqual(guest_user_profile, response.wsgi_request.user_profile)
+
+ def test_authenticated_user_should_use_own_profile(self):
+ guest_user = self.setup_user()
+ guest_user_profile = guest_user.profile
+ guest_user_profile.theme = UserProfile.THEME_DARK
+ guest_user_profile.save()
+
+ global_settings = GlobalSettings.get()
+ global_settings.guest_profile_user = guest_user
+ global_settings.save()
+
+ user = self.get_or_create_test_user()
+ user_profile = user.profile
+ user_profile.theme = UserProfile.THEME_LIGHT
+ user_profile.save()
+ self.client.force_login(user)
+
+ response = self.client.get(reverse("login"), follow=True)
+
+ self.assertEqual(user_profile, response.wsgi_request.user_profile)