mirror of
https://github.com/sissbruecker/linkding
synced 2024-11-25 12:50:23 +00:00
Allow configuring guest user profile (#809)
This commit is contained in:
parent
79bf4b38c6
commit
aad62f61c9
7 changed files with 127 additions and 8 deletions
|
@ -1,13 +1,17 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.middleware import RemoteUserMiddleware
|
from django.contrib.auth.middleware import RemoteUserMiddleware
|
||||||
|
|
||||||
from bookmarks.models import UserProfile
|
from bookmarks.models import UserProfile, GlobalSettings
|
||||||
|
|
||||||
|
|
||||||
class CustomRemoteUserMiddleware(RemoteUserMiddleware):
|
class CustomRemoteUserMiddleware(RemoteUserMiddleware):
|
||||||
header = settings.LD_AUTH_PROXY_USERNAME_HEADER
|
header = settings.LD_AUTH_PROXY_USERNAME_HEADER
|
||||||
|
|
||||||
|
|
||||||
|
standard_profile = UserProfile()
|
||||||
|
standard_profile.enable_favicons = True
|
||||||
|
|
||||||
|
|
||||||
class UserProfileMiddleware:
|
class UserProfileMiddleware:
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
@ -16,8 +20,16 @@ class UserProfileMiddleware:
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
request.user_profile = request.user.profile
|
request.user_profile = request.user.profile
|
||||||
else:
|
else:
|
||||||
request.user_profile = UserProfile()
|
# check if a custom profile for guests exists, otherwise use standard profile
|
||||||
request.user_profile.enable_favicons = True
|
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)
|
response = self.get_response(request)
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -508,6 +508,9 @@ class GlobalSettings(models.Model):
|
||||||
blank=False,
|
blank=False,
|
||||||
default=LANDING_PAGE_LOGIN,
|
default=LANDING_PAGE_LOGIN,
|
||||||
)
|
)
|
||||||
|
guest_profile_user = models.ForeignKey(
|
||||||
|
get_user_model(), on_delete=models.SET_NULL, null=True, blank=True
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls):
|
def get(cls):
|
||||||
|
@ -526,6 +529,8 @@ class GlobalSettings(models.Model):
|
||||||
class GlobalSettingsForm(forms.ModelForm):
|
class GlobalSettingsForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = GlobalSettings
|
model = GlobalSettings
|
||||||
fields = [
|
fields = ["landing_page", "guest_profile_user"]
|
||||||
"landing_page",
|
|
||||||
]
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(GlobalSettingsForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields["guest_profile_user"].empty_label = "Standard profile"
|
||||||
|
|
|
@ -249,7 +249,17 @@ reddit.com/r/Music music reddit</pre>
|
||||||
<label for="{{ global_settings_form.landing_page.id_for_label }}" class="form-label">Landing page</label>
|
<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" }}
|
{{ global_settings_form.landing_page|add_class:"form-select width-25 width-sm-100" }}
|
||||||
<div class="form-input-hint">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from bookmarks.models import GlobalSettings
|
||||||
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
from bookmarks.tests.helpers import BookmarkFactoryMixin
|
||||||
|
|
||||||
|
|
||||||
class AnonymousViewTestCase(TestCase, BookmarkFactoryMixin):
|
class RootViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
def test_unauthenticated_user_redirect_to_login_by_default(self):
|
def test_unauthenticated_user_redirect_to_login_by_default(self):
|
||||||
response = self.client.get(reverse("bookmarks:root"))
|
response = self.client.get(reverse("bookmarks:root"))
|
||||||
self.assertRedirects(response, reverse("login"))
|
self.assertRedirects(response, reverse("login"))
|
||||||
|
|
|
@ -469,10 +469,13 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
def test_update_global_settings(self):
|
def test_update_global_settings(self):
|
||||||
superuser = self.setup_superuser()
|
superuser = self.setup_superuser()
|
||||||
self.client.force_login(superuser)
|
self.client.force_login(superuser)
|
||||||
|
selectable_user = self.setup_user()
|
||||||
|
|
||||||
|
# Update global settings
|
||||||
form_data = {
|
form_data = {
|
||||||
"update_global_settings": "",
|
"update_global_settings": "",
|
||||||
"landing_page": GlobalSettings.LANDING_PAGE_SHARED_BOOKMARKS,
|
"landing_page": GlobalSettings.LANDING_PAGE_SHARED_BOOKMARKS,
|
||||||
|
"guest_profile_user": selectable_user.id,
|
||||||
}
|
}
|
||||||
response = self.client.post(reverse("bookmarks:settings.general"), form_data)
|
response = self.client.post(reverse("bookmarks:settings.general"), form_data)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -480,6 +483,22 @@ class SettingsGeneralViewTestCase(TestCase, BookmarkFactoryMixin):
|
||||||
|
|
||||||
global_settings = GlobalSettings.get()
|
global_settings = GlobalSettings.get()
|
||||||
self.assertEqual(global_settings.landing_page, form_data["landing_page"])
|
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(
|
def test_update_global_settings_should_not_be_called_without_respective_form_action(
|
||||||
self,
|
self,
|
||||||
|
|
47
bookmarks/tests/test_user_profile_middleware.py
Normal file
47
bookmarks/tests/test_user_profile_middleware.py
Normal file
|
@ -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)
|
Loading…
Reference in a new issue