-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Content moderator user preferences admin view (#3914)
* Add UserPreferences model * Add string name for model, and create prefs on user creation * Add user preferences to separate section in admin UI * Use a custom form for only changing blur images in Admin UI * Add tests for the admin form * Add moderator user and content moderator group creation to init * Use more idiomatic Django MVC logic * Jump directly into the single user preferences entry from list view * Always return a bound object Co-authored-by: sarayourfriend <24264157+sarayourfriend@users.noreply.github.com> * Linting * Add UserPreferences insertion data migration * Use settings.AUTH_USER_MODEL instead of model directly * Update migration * Update permissions for UserPreferences admin models Co-authored-by: Dhruv Bhanushali <hi@dhruvkb.dev> * Re-add change permissions This is required for has_view_permissions: The default implementation returns True if the user has either the “change” or “view” permission. https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.has_view_permission --------- Co-authored-by: sarayourfriend <24264157+sarayourfriend@users.noreply.github.com> Co-authored-by: Dhruv Bhanushali <hi@dhruvkb.dev>
- Loading branch information
1 parent
4524098
commit effd06c
Showing
8 changed files
with
243 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from django import forms | ||
|
||
from api.models import UserPreferences | ||
|
||
|
||
class UserPreferencesAdminForm(forms.ModelForm): | ||
blur_images = forms.BooleanField(initial=True, required=False) | ||
|
||
class Meta: | ||
model = UserPreferences | ||
fields = ["blur_images"] | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.initial["blur_images"] = self.instance.blur_images | ||
|
||
def save(self, commit=True): | ||
self.instance.blur_images = self.cleaned_data.get("blur_images") | ||
return super().save(commit=commit) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Generated by Django 4.2.11 on 2024-04-10 01:53 | ||
|
||
from django.conf import settings | ||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
def create_user_preferences(apps, schema_editor): | ||
UserPreferences = apps.get_model("api", "UserPreferences") | ||
User = apps.get_model(*settings.AUTH_USER_MODEL.split(".")) | ||
for user in User.objects.all(): | ||
if not hasattr(user, "userpreferences"): | ||
UserPreferences.objects.create(user=user) | ||
user.userpreferences.save() | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
('api', '0058_moderation_decision'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='UserPreferences', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('preferences', models.JSONField(default=dict)), | ||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), | ||
], | ||
), | ||
migrations.RunPython(create_user_preferences) | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from django.conf import settings | ||
from django.db import models | ||
from django.db.models.signals import post_save | ||
from django.dispatch import receiver | ||
|
||
|
||
class UserPreferences(models.Model): | ||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) | ||
preferences = models.JSONField(default=dict) | ||
|
||
def __str__(self): | ||
return f"{self.user.username}'s preferences" | ||
|
||
@property | ||
def moderator(self): | ||
if "moderator" not in self.preferences: | ||
self.preferences["moderator"] = {} | ||
|
||
return self.preferences["moderator"] | ||
|
||
@moderator.setter | ||
def moderator(self, value): | ||
self.preferences["moderator"] = value | ||
|
||
@property | ||
def blur_images(self): | ||
return self.moderator.get("blur_images", True) | ||
|
||
@blur_images.setter | ||
def blur_images(self, value): | ||
self.moderator |= {"blur_images": value} | ||
|
||
|
||
@receiver(post_save, sender=settings.AUTH_USER_MODEL) | ||
def create_or_update_user_profile(sender, instance, created, **kwargs): | ||
if created: | ||
UserPreferences.objects.create(user=instance) | ||
instance.userpreferences.save() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import pytest | ||
|
||
from api.admin.forms import UserPreferencesAdminForm | ||
from api.models import UserPreferences | ||
|
||
|
||
@pytest.mark.django_db | ||
@pytest.mark.parametrize( | ||
"initial_preferences, blur_images_value, expected_preferences", | ||
[ | ||
({}, True, {"moderator": {"blur_images": True}}), | ||
({}, False, {"moderator": {"blur_images": False}}), | ||
( | ||
{"moderator": {"blur_images": False}}, | ||
True, | ||
{"moderator": {"blur_images": True}}, | ||
), | ||
( | ||
{"moderator": {"blur_images": False}}, | ||
False, | ||
{"moderator": {"blur_images": False}}, | ||
), | ||
( | ||
{"moderator": {"blur_images": True}}, | ||
True, | ||
{"moderator": {"blur_images": True}}, | ||
), | ||
( | ||
{"moderator": {"blur_images": False}}, | ||
False, | ||
{"moderator": {"blur_images": False}}, | ||
), | ||
( | ||
{"some_other_setting": 123}, | ||
False, | ||
{"some_other_setting": 123, "moderator": {"blur_images": False}}, | ||
), | ||
( | ||
{"moderator": {"some_other_setting": 123}}, | ||
False, | ||
{"moderator": {"some_other_setting": 123, "blur_images": False}}, | ||
), | ||
], | ||
) | ||
def test_user_preferences_form( | ||
initial_preferences, blur_images_value, expected_preferences, django_user_model | ||
): | ||
user = django_user_model.objects.create(username="foobar", password="fake") | ||
preferences = user.userpreferences | ||
# Check that new user has no preferences | ||
assert preferences.preferences == {} | ||
# Set the initial user preferences | ||
preferences.preferences = initial_preferences | ||
preferences.save() | ||
|
||
form_data = {"blur_images": blur_images_value} | ||
form = UserPreferencesAdminForm(data=form_data, instance=preferences) | ||
assert form.is_valid(), "Form should be valid" | ||
instance = form.save() | ||
# Retrieve the instance from the database to ensure it's saved correctly | ||
saved_instance = UserPreferences.objects.get(id=instance.id) | ||
assert saved_instance.preferences == expected_preferences |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters