feat(social): Add Reaction model, schema, and API endpoints
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run

This commit is contained in:
fullsizemalt 2025-12-21 02:38:40 -08:00
parent a4edbb676d
commit d5b5ee8192
3 changed files with 94 additions and 2 deletions

View file

@ -279,3 +279,13 @@ class Notification(SQLModel, table=True):
created_at: datetime = Field(default_factory=datetime.utcnow)
user: User = Relationship(back_populates="notifications")
class Reaction(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
user_id: int = Field(foreign_key="user.id")
entity_type: str = Field(index=True) # "review", "comment"
entity_id: int = Field(index=True)
emoji: str # "❤️", "🔥", etc.
created_at: datetime = Field(default_factory=datetime.utcnow)
user: User = Relationship()

View file

@ -3,8 +3,8 @@ from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select, func
from database import get_session
from models import Comment, Rating, User, Profile
from schemas import CommentCreate, CommentRead, RatingCreate, RatingRead
from models import Comment, Rating, User, Profile, Reaction
from schemas import CommentCreate, CommentRead, RatingCreate, RatingRead, ReactionCreate, ReactionRead
from auth import get_current_user
from helpers import create_notification
@ -121,3 +121,71 @@ def get_average_rating(
avg = session.exec(query).first()
return float(avg) if avg else 0.0
# --- Reactions ---
@router.post("/reactions", response_model=ReactionRead)
def toggle_reaction(
reaction: ReactionCreate,
session: Session = Depends(get_session),
current_user: User = Depends(get_current_user)
):
query = select(Reaction).where(
Reaction.user_id == current_user.id,
Reaction.entity_type == reaction.entity_type,
Reaction.entity_id == reaction.entity_id
)
existing = session.exec(query).first()
if existing:
if existing.emoji == reaction.emoji:
# Toggle off
session.delete(existing)
session.commit()
return existing
else:
# Change emoji
existing.emoji = reaction.emoji
session.add(existing)
session.commit()
session.refresh(existing)
return existing
# Create new
db_reaction = Reaction.model_validate(reaction)
db_reaction.user_id = current_user.id
session.add(db_reaction)
session.commit()
session.refresh(db_reaction)
return db_reaction
@router.get("/reactions/counts")
def get_reaction_counts(
entity_type: str,
entity_id: int,
session: Session = Depends(get_session)
):
# Group by emoji and count
query = select(Reaction.emoji, func.count(Reaction.id)).where(
Reaction.entity_type == entity_type,
Reaction.entity_id == entity_id
).group_by(Reaction.emoji)
results = session.exec(query).all()
# returns list of (emoji, count)
return {emoji: count for emoji, count in results}
@router.get("/reactions/me")
def get_my_reaction(
entity_type: str,
entity_id: int,
current_user: User = Depends(get_current_user),
session: Session = Depends(get_session)
):
query = select(Reaction).where(
Reaction.user_id == current_user.id,
Reaction.entity_type == entity_type,
Reaction.entity_id == entity_id
)
return session.exec(query).first()

View file

@ -346,3 +346,17 @@ class TagRead(TagBase):
# Circular refs
ShowRead.model_rebuild()
PerformanceDetailRead.model_rebuild()
# --- Reaction Schemas ---
class ReactionBase(SQLModel):
entity_type: str
entity_id: int
emoji: str
class ReactionCreate(ReactionBase):
pass
class ReactionRead(ReactionBase):
id: int
user_id: int
created_at: datetime