Initial commit: Aurora Moments self-hosted photo/video sharing platform
Django/DRF + PostgreSQL/Redis/Celery backend with accounts, library, moments, and notifications apps; React/TypeScript/Vite frontend with Instagram-style sidebar nav, feed, profiles, nested comment replies, notifications, and photo/video upload with ffmpeg-generated posters. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from django.contrib.auth import password_validation
|
||||
from rest_framework import serializers
|
||||
|
||||
from .models import Follow, User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["id", "username", "display_name", "bio", "avatar", "is_private", "date_joined"]
|
||||
read_only_fields = ["id", "date_joined"]
|
||||
|
||||
|
||||
class ProfileSerializer(UserSerializer):
|
||||
"""UserSerializer plus the counts/relationship state a profile page
|
||||
needs. Kept separate from UserSerializer (used for owner/author fields
|
||||
all over the feed) so those hot paths don't pay for two extra COUNT
|
||||
queries per embedded user."""
|
||||
|
||||
follower_count = serializers.SerializerMethodField()
|
||||
following_count = serializers.SerializerMethodField()
|
||||
viewer_follow_id = serializers.SerializerMethodField()
|
||||
viewer_follow_status = serializers.SerializerMethodField()
|
||||
|
||||
class Meta(UserSerializer.Meta):
|
||||
fields = UserSerializer.Meta.fields + [
|
||||
"follower_count", "following_count", "viewer_follow_id", "viewer_follow_status",
|
||||
]
|
||||
|
||||
def _viewer_follow(self, obj):
|
||||
request = self.context.get("request")
|
||||
if not request or not request.user.is_authenticated or request.user.id == obj.id:
|
||||
return None
|
||||
if not hasattr(obj, "_viewer_follow_cache"):
|
||||
obj._viewer_follow_cache = Follow.objects.filter(follower=request.user, following=obj).first()
|
||||
return obj._viewer_follow_cache
|
||||
|
||||
def get_follower_count(self, obj):
|
||||
return obj.follower_edges.filter(status=Follow.Status.ACCEPTED).count()
|
||||
|
||||
def get_following_count(self, obj):
|
||||
return obj.following_edges.filter(status=Follow.Status.ACCEPTED).count()
|
||||
|
||||
def get_viewer_follow_id(self, obj):
|
||||
follow = self._viewer_follow(obj)
|
||||
return follow.id if follow else None
|
||||
|
||||
def get_viewer_follow_status(self, obj):
|
||||
follow = self._viewer_follow(obj)
|
||||
return follow.status if follow else None
|
||||
|
||||
|
||||
class RegisterSerializer(serializers.ModelSerializer):
|
||||
password = serializers.CharField(write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["id", "email", "username", "password", "display_name"]
|
||||
|
||||
def validate_password(self, value):
|
||||
password_validation.validate_password(value)
|
||||
return value
|
||||
|
||||
def create(self, validated_data):
|
||||
password = validated_data.pop("password")
|
||||
user = User(**validated_data)
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
return user
|
||||
|
||||
|
||||
class FollowSerializer(serializers.ModelSerializer):
|
||||
follower = UserSerializer(read_only=True)
|
||||
following = UserSerializer(read_only=True)
|
||||
following_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=User.objects.all(), source="following", write_only=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Follow
|
||||
fields = ["id", "follower", "following", "following_id", "status", "created_at"]
|
||||
read_only_fields = ["id", "follower", "status", "created_at"]
|
||||
|
||||
def create(self, validated_data):
|
||||
follower = self.context["request"].user
|
||||
following = validated_data["following"]
|
||||
status = Follow.Status.PENDING if following.is_private else Follow.Status.ACCEPTED
|
||||
follow, _ = Follow.objects.get_or_create(
|
||||
follower=follower, following=following, defaults={"status": status}
|
||||
)
|
||||
return follow
|
||||
Reference in New Issue
Block a user