Files
J621/backend/apps/accounts/serializers.py
T
JakeBreath dc79349d9e Online defaults to order:hot, with an Account toggle
New online_hot_default preference (on by default, so guests and accounts
that never saved preferences get it): opening /online without a search
replaces the URL with ?tags=order:hot — e621's metatag for the order the
Hot page uses — so it is visible in the search field and shareable.
Existing searches are never touched: they live in the URL, so a refresh
or back/forward keeps them, while a fresh visit (nav pill, first time,
after a long time away) gets the hot default again. Turning the toggle
off opens Online on the site-wide newest posts as before.

The toggle sits in Account -> Browsing preferences and saves with the
rest of the settings; the backend validates the new boolean
(400 for non-boolean input).
2026-09-17 23:46:14 -05:00

132 lines
4.1 KiB
Python

from pathlib import Path
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers
from apps.library.services import VIDEO_EXTENSIONS
from apps.library.services import signed_media_url as signed_library_url
from .models import User
def signed_media_url(request, item):
"""A signed media URL an <img> tag can load for an authenticated user."""
if item is None:
return None
user = getattr(request, "user", None)
if user is None or not getattr(user, "is_authenticated", False):
return None
location = item.locations.first()
is_video = (
location is not None
and Path(location.rel_path).suffix.lower() in VIDEO_EXTENSIONS
)
action = "thumbnail" if is_video else "raw"
return signed_library_url(item, user, action, request=request)
class UserSerializer(serializers.ModelSerializer):
e621_configured = serializers.BooleanField(read_only=True)
can_upload = serializers.BooleanField(read_only=True)
avatar_j_id = serializers.SerializerMethodField()
avatar_url = serializers.SerializerMethodField()
class Meta:
model = User
fields = [
"id",
"username",
"email",
"is_staff",
"is_superuser",
"date_joined",
"role",
"can_upload",
"avatar_j_id",
"avatar_url",
"e621_username",
"e621_configured",
"preferences",
]
read_only_fields = fields
def get_avatar_j_id(self, obj):
return f"J-{obj.avatar_id}" if obj.avatar_id else None
def get_avatar_url(self, obj):
return signed_media_url(self.context.get("request"), obj.avatar)
class UserListSerializer(serializers.ModelSerializer):
avatar_j_id = serializers.SerializerMethodField()
avatar_url = serializers.SerializerMethodField()
uploads_count = serializers.IntegerField(read_only=True)
class Meta:
model = User
fields = [
"id",
"username",
"email",
"role",
"is_staff",
"is_superuser",
"date_joined",
"avatar_j_id",
"avatar_url",
"uploads_count",
]
read_only_fields = fields
def get_avatar_j_id(self, obj):
return f"J-{obj.avatar_id}" if obj.avatar_id else None
def get_avatar_url(self, obj):
return signed_media_url(self.context.get("request"), obj.avatar)
class UserUpdateSerializer(serializers.Serializer):
avatar_j_id = serializers.CharField(
required=False, allow_blank=True, allow_null=True
)
role = serializers.ChoiceField(choices=User.ROLE_CHOICES, required=False)
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, validators=[validate_password])
class Meta:
model = User
fields = ["username", "email", "password"]
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class E621CredentialsSerializer(serializers.Serializer):
username = serializers.CharField(max_length=100, allow_blank=True)
api_key = serializers.CharField(
max_length=100, allow_blank=True, trim_whitespace=True
)
base_url = serializers.URLField(
max_length=200, required=False, allow_blank=True
)
class PreferencesSerializer(serializers.Serializer):
"""Per-user browse preferences; unknown keys are ignored."""
LANDING_PAGES = ["library", "online", "pools", "followed"]
landing_page = serializers.ChoiceField(choices=LANDING_PAGES, required=False)
ratings = serializers.ListField(
child=serializers.ChoiceField(choices=["s", "q", "e"]),
required=False,
max_length=3,
)
ordering = serializers.CharField(max_length=30, required=False)
per_page = serializers.IntegerField(min_value=12, max_value=200, required=False)
zoom = serializers.IntegerField(min_value=120, max_value=400, required=False)
# Open Online with the order:hot metatag when no search is given.
online_hot_default = serializers.BooleanField(required=False)