Fix SSO theme selection (#7556)

* Adjust caching key to be numeric for user

* Add strong usermodel to colortheme

* switch to using user model everywhere for colortheme

* add some types

* use pk instead of id

* fix migration clash

* fix request
This commit is contained in:
Matthias Mair 2024-07-04 23:24:55 +02:00 committed by GitHub
parent 7f43040049
commit 5844747e32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 57 additions and 14 deletions

View File

@ -438,9 +438,9 @@ def progress_bar(val, max_val, *args, **kwargs):
@register.simple_tag()
def get_color_theme_css(username):
def get_color_theme_css(user):
"""Return the custom theme .css file for the selected user."""
user_theme_name = get_user_color_theme(username)
user_theme_name = get_user_color_theme(user)
# Build path to CSS sheet
inventree_css_sheet = os.path.join('css', 'color-themes', user_theme_name + '.css')
@ -451,12 +451,15 @@ def get_color_theme_css(username):
@register.simple_tag()
def get_user_color_theme(username):
def get_user_color_theme(user):
"""Get current user color theme."""
from common.models import ColorTheme
if not user.is_authenticated:
return 'default'
try:
user_theme = ColorTheme.objects.filter(user=username).get()
user_theme = ColorTheme.objects.filter(user_obj=user).get()
user_theme_name = user_theme.name
if not user_theme_name or not ColorTheme.is_valid_choice(user_theme):
user_theme_name = 'default'

View File

@ -614,7 +614,7 @@ class AppearanceSelectView(RedirectView):
"""Get current user color theme."""
try:
user_theme = common_models.ColorTheme.objects.filter(
user=self.request.user
user_obj=self.request.user
).get()
except common_models.ColorTheme.DoesNotExist:
user_theme = None
@ -631,7 +631,7 @@ class AppearanceSelectView(RedirectView):
# Create theme entry if user did not select one yet
if not user_theme:
user_theme = common_models.ColorTheme()
user_theme.user = request.user
user_theme.user_obj = request.user
if theme:
try:

View File

@ -0,0 +1,39 @@
# Generated by Django 4.2.12 on 2024-07-04 10:23
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
def migrate_userthemes(apps, schema_editor):
"""Mgrate text-based user references to ForeignKey references."""
ColorTheme = apps.get_model("common", "ColorTheme")
User = apps.get_model(settings.AUTH_USER_MODEL)
for theme in ColorTheme.objects.all():
try:
theme.user_obj = User.objects.get(username=theme.user)
theme.save()
except User.DoesNotExist:
pass
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("common", "0027_alter_customunit_symbol"),
]
operations = [
migrations.AddField(
model_name="colortheme",
name="user_obj",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
migrations.RunPython(migrate_userthemes, migrations.RunPython.noop),
]

View File

@ -2583,6 +2583,7 @@ class ColorTheme(models.Model):
name = models.CharField(max_length=20, default='', blank=True)
user = models.CharField(max_length=150, unique=True)
user_obj = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
@classmethod
def get_color_themes_choices(cls):

View File

@ -41,7 +41,7 @@
<div class='form-group input-group mb-3'>
<select id='theme' name='theme' class='select form-control'>
{% get_available_themes as themes %}
{% get_user_color_theme request.user.username as user_theme %}
{% get_user_color_theme request.user as user_theme %}
{% for theme in themes %}
<option value='{{ theme.key }}'{% if theme.key == user_theme %} selected{% endif %}>{{ theme.name }}</option>
{% endfor %}

View File

@ -38,7 +38,7 @@
<link rel="stylesheet" href="{% static 'select2/css/select2-bootstrap-5-theme.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% get_color_theme_css user.get_username %}">
<link rel="stylesheet" href="{% get_color_theme_css request.user %}">
<title>
{% inventree_title %} | {% block head_title %}{% endblock head_title %}

View File

@ -55,7 +55,7 @@
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% get_color_theme_css user.get_username %}">
<link rel="stylesheet" href="{% get_color_theme_css request.user %}">
<style>
{% block css %}

View File

@ -405,7 +405,7 @@ class RuleSet(models.Model):
)
@classmethod
def check_table_permission(cls, user, table, permission):
def check_table_permission(cls, user: User, table, permission):
"""Check if the provided user has the specified permission against the table."""
# Superuser knows no bounds
if user.is_superuser:
@ -664,7 +664,7 @@ def update_group_roles(group, debug=False):
)
def clear_user_role_cache(user):
def clear_user_role_cache(user: User):
"""Remove user role permission information from the cache.
- This function is called whenever the user / group is updated
@ -674,11 +674,11 @@ def clear_user_role_cache(user):
"""
for role in RuleSet.get_ruleset_models().keys():
for perm in ['add', 'change', 'view', 'delete']:
key = f'role_{user}_{role}_{perm}'
key = f'role_{user.pk}_{role}_{perm}'
cache.delete(key)
def check_user_role(user, role, permission):
def check_user_role(user: User, role, permission):
"""Check if a user has a particular role:permission combination.
If the user is a superuser, this will return True
@ -687,7 +687,7 @@ def check_user_role(user, role, permission):
return True
# First, check the cache
key = f'role_{user}_{role}_{permission}'
key = f'role_{user.pk}_{role}_{permission}'
try:
result = cache.get(key)