Skip to content

Commit

Permalink
Allow configuring guest user profile (#809)
Browse files Browse the repository at this point in the history
  • Loading branch information
sissbruecker authored Aug 31, 2024
1 parent 79bf4b3 commit aad62f6
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 8 deletions.
18 changes: 15 additions & 3 deletions bookmarks/middlewares.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,8 +20,16 @@ def __call__(self, request):
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)

Expand Down
26 changes: 26 additions & 0 deletions bookmarks/migrations/0038_globalsettings_guest_profile_user.py
Original file line number Diff line number Diff line change
@@ -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,
),
),
]
11 changes: 8 additions & 3 deletions bookmarks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -526,6 +529,8 @@ def save(self, *args, **kwargs):
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"
12 changes: 11 additions & 1 deletion bookmarks/templates/settings/general.html
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,17 @@ <h2>Global settings</h2>
<label for="{{ global_settings_form.landing_page.id_for_label }}" class="form-label">Landing page</label>
{{ global_settings_form.landing_page|add_class:"form-select width-25 width-sm-100" }}
<div class="form-input-hint">
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.
</div>
</div>
<div class="form-group">
<label for="{{ global_settings_form.guest_profile_user.id_for_label }}" class="form-label">Guest user
profile</label>
{{ global_settings_form.guest_profile_user|add_class:"form-select width-25 width-sm-100" }}
<div class="form-input-hint">
The user profile to use for users that are not logged in. This will affect how publicly shared bookmarks
are displayed regarding theme, bookmark list settings, etc. You can either use your own profile or create
a dedicated user for this purpose. By default, a standard profile with fixed settings is used.
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion bookmarks/tests/test_root_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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"))
Expand Down
19 changes: 19 additions & 0 deletions bookmarks/tests/test_settings_general_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,17 +469,36 @@ def test_create_missing_html_snapshots_should_not_be_called_without_respective_f
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)
self.assertSuccessMessage(response.content.decode(), "Global settings updated")

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,
Expand Down
47 changes: 47 additions & 0 deletions bookmarks/tests/test_user_profile_middleware.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit aad62f6

Please sign in to comment.