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).
132 lines
4.1 KiB
Python
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)
|