fediversion/backend/schemas.py
fullsizemalt 59099b2b66
Some checks failed
Deploy Fediversion / deploy (push) Failing after 0s
revert: rollback schema changes to restore stability
2025-12-31 18:42:41 -08:00

487 lines
11 KiB
Python

from typing import Optional, List, Dict, Generic, TypeVar
from sqlmodel import SQLModel
from datetime import datetime
from pydantic import ConfigDict
class UserCreate(SQLModel):
email: str
password: str
username: str
class UserRead(SQLModel):
id: int
email: str
is_active: bool
is_superuser: bool
role: str = "user"
avatar_bg_color: Optional[str] = "#3B82F6"
avatar_text: Optional[str] = None
profile_public: bool = True
show_attendance_public: bool = True
appear_in_leaderboards: bool = True
bio: Optional[str] = None
username: Optional[str] = None
joined_at: Optional[datetime] = None
# Social handles
bluesky_handle: Optional[str] = None
mastodon_handle: Optional[str] = None
instagram_handle: Optional[str] = None
location: Optional[str] = None
class Token(SQLModel):
access_token: str
token_type: str
class TokenData(SQLModel):
email: Optional[str] = None
T = TypeVar("T")
class PaginationMeta(SQLModel):
total: int
limit: int
offset: int
class PaginatedResponse(SQLModel, Generic[T]):
data: List[T]
meta: PaginationMeta
# --- Venue Schemas ---
class VenueBase(SQLModel):
name: str
city: str
state: Optional[str] = None
country: str
capacity: Optional[int] = None
notes: Optional[str] = None
class VenueCreate(VenueBase):
pass
class VenueRead(VenueBase):
id: int
slug: Optional[str] = None
class VenueUpdate(SQLModel):
name: Optional[str] = None
city: Optional[str] = None
state: Optional[str] = None
country: Optional[str] = None
capacity: Optional[int] = None
notes: Optional[str] = None
# --- Song Schemas ---
class SongBase(SQLModel):
title: str
original_artist: Optional[str] = None
vertical_id: int
notes: Optional[str] = None
class SongCreate(SongBase):
pass
class SongRead(SongBase):
id: int
slug: Optional[str] = None
tags: List["TagRead"] = []
artist: Optional["ArtistRead"] = None
vertical: Optional["VerticalSimple"] = None
times_played: Optional[int] = 0
class SongUpdate(SQLModel):
title: Optional[str] = None
original_artist: Optional[str] = None
notes: Optional[str] = None
# --- Vertical Schema (simple for embedding) ---
class VerticalSimple(SQLModel):
id: int
name: str
slug: str
description: Optional[str] = None
logo_url: Optional[str] = None
accent_color: Optional[str] = None
# --- Show Schemas ---
class ShowBase(SQLModel):
date: datetime
vertical_id: int
venue_id: Optional[int] = None
tour_id: Optional[int] = None
notes: Optional[str] = None
class ShowCreate(ShowBase):
pass
# --- Performance Schemas ---
class PerformanceBase(SQLModel):
show_id: int
song_id: int
position: int
set_name: Optional[str] = None
segue: bool = False
notes: Optional[str] = None
class PerformanceRead(PerformanceBase):
id: int
slug: Optional[str] = None
song: Optional["SongRead"] = None
nicknames: List["PerformanceNicknameRead"] = []
youtube_link: Optional[str] = None
class PerformanceReadWithShow(PerformanceRead):
show_date: datetime
show_slug: Optional[str] = None
venue_name: str
venue_city: str
venue_state: Optional[str] = None
artist_name: Optional[str] = None
artist_slug: Optional[str] = None
avg_rating: Optional[float] = 0.0
total_reviews: Optional[int] = 0
class SongReadWithStats(SongRead):
times_played: int
gap: int
last_played: Optional[datetime] = None
set_breakdown: Dict[str, int] = {}
artist_distribution: Dict[str, int] = {}
performances: List[PerformanceReadWithShow] = []
class PerformanceDetailRead(PerformanceRead):
show: Optional["ShowRead"] = None
previous_performance_id: Optional[int] = None
previous_performance_slug: Optional[str] = None
next_performance_id: Optional[int] = None
next_performance_slug: Optional[str] = None
gap: Optional[int] = 0
times_played: Optional[int] = 0
other_performances: List[PerformanceReadWithShow] = []
# Ranking fields
rank: Optional[int] = None
total_versions: Optional[int] = None
avg_rating: Optional[float] = None
rating_count: Optional[int] = None
is_heady: Optional[bool] = False
# --- Groups ---
class GroupBase(SQLModel):
name: str
description: Optional[str] = None
privacy: str = "public"
class GroupCreate(GroupBase):
pass
class GroupRead(GroupBase):
id: int
created_by: int
created_at: datetime
member_count: Optional[int] = 0
class GroupPostBase(SQLModel):
content: str
class GroupPostCreate(GroupPostBase):
group_id: int
class GroupPostRead(GroupPostBase):
id: int
group_id: int
user_id: int
created_at: datetime
song: Optional["SongRead"] = None
nicknames: List["PerformanceNicknameRead"] = []
class ShowRead(ShowBase):
model_config = ConfigDict(from_attributes=True)
id: int
slug: Optional[str] = None
vertical: Optional[VerticalSimple] = None
venue: Optional[VenueRead] = None
tour: Optional[TourRead] = None
tags: List["TagRead"] = []
performances: List["PerformanceRead"] = []
notes: Optional[str] = None
youtube_link: Optional[str] = None
nugs_link: Optional[str] = None
bandcamp_link: Optional[str] = None
class ShowUpdate(SQLModel):
date: Optional[datetime] = None
venue_id: Optional[int] = None
tour_id: Optional[int] = None
notes: Optional[str] = None
# --- Tour Schemas ---
class TourBase(SQLModel):
name: str
start_date: Optional[datetime] = None
end_date: Optional[datetime] = None
notes: Optional[str] = None
class TourCreate(TourBase):
pass
class TourRead(TourBase):
id: int
slug: Optional[str] = None
class TourUpdate(SQLModel):
name: Optional[str] = None
start_date: Optional[datetime] = None
end_date: Optional[datetime] = None
notes: Optional[str] = None
# --- Artist Schemas ---
class ArtistBase(SQLModel):
name: str
instrument: Optional[str] = None
notes: Optional[str] = None
class ArtistCreate(ArtistBase):
pass
class ArtistRead(ArtistBase):
id: int
class ArtistUpdate(SQLModel):
name: Optional[str] = None
instrument: Optional[str] = None
notes: Optional[str] = None
# --- Attendance Schemas ---
class AttendanceBase(SQLModel):
show_id: int
notes: Optional[str] = None
class AttendanceCreate(AttendanceBase):
pass
class AttendanceRead(AttendanceBase):
id: int
user_id: int
created_at: datetime
# --- Social Schemas ---
class CommentBase(SQLModel):
content: str
show_id: Optional[int] = None
venue_id: Optional[int] = None
song_id: Optional[int] = None
parent_id: Optional[int] = None
class CommentCreate(CommentBase):
pass
class CommentRead(CommentBase):
id: int
user_id: int
created_at: datetime
# We might want to include the username here later
class RatingBase(SQLModel):
score: Optional[float] = None # 1-5 stars, optional
show_id: Optional[int] = None
song_id: Optional[int] = None
performance_id: Optional[int] = None
venue_id: Optional[int] = None
tour_id: Optional[int] = None
class RatingCreate(RatingBase):
pass
class RatingRead(RatingBase):
id: int
user_id: int
created_at: datetime
class ReviewBase(SQLModel):
blurb: Optional[str] = None # Short tagline/summary
content: Optional[str] = None # Full review text
score: Optional[float] = None # Optional rating with review
show_id: Optional[int] = None
venue_id: Optional[int] = None
song_id: Optional[int] = None
performance_id: Optional[int] = None
tour_id: Optional[int] = None
year: Optional[int] = None
class ReviewCreate(ReviewBase):
pass
class ReviewRead(ReviewBase):
id: int
user_id: int
created_at: datetime
# --- Badge Schemas ---
class BadgeBase(SQLModel):
name: str
description: str
icon: str
slug: str
class BadgeCreate(BadgeBase):
pass
class BadgeRead(BadgeBase):
id: int
class UserBadgeRead(SQLModel):
id: int
user_id: int
badge: BadgeRead
awarded_at: datetime
# --- Nickname Schemas ---
class PerformanceNicknameBase(SQLModel):
performance_id: int
nickname: str
description: Optional[str] = None
class PerformanceNicknameCreate(PerformanceNicknameBase):
pass
class PerformanceNicknameRead(PerformanceNicknameBase):
id: int
status: str
suggested_by: int
created_at: datetime
# --- Report Schemas ---
class ReportBase(SQLModel):
entity_type: str
entity_id: int
reason: str
class ReportCreate(ReportBase):
pass
class ReportRead(ReportBase):
id: int
user_id: int
status: str
created_at: datetime
# --- User Preferences Schemas ---
class UserPreferencesBase(SQLModel):
wiki_mode: bool = False
show_ratings: bool = True
show_comments: bool = True
theme: str = "system"
email_on_reply: bool = True
email_on_chase: bool = True
email_digest: bool = False
class UserPreferencesCreate(UserPreferencesBase):
pass
class UserPreferencesUpdate(SQLModel):
wiki_mode: Optional[bool] = None
show_ratings: Optional[bool] = None
show_comments: Optional[bool] = None
theme: Optional[str] = None
email_on_reply: Optional[bool] = None
email_on_chase: Optional[bool] = None
email_digest: Optional[bool] = None
class UserPreferencesRead(UserPreferencesBase):
user_id: int
# --- Notification Schemas ---
class NotificationBase(SQLModel):
type: str
title: str
message: str
link: Optional[str] = None
is_read: bool = False
class NotificationCreate(NotificationBase):
user_id: int
class NotificationRead(NotificationBase):
id: int
created_at: datetime
# --- Tag Schemas ---
class TagBase(SQLModel):
name: str
slug: str
class TagCreate(TagBase):
pass
class TagRead(TagBase):
id: int
slug: str
# 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
# --- Profile Schemas ---
class SocialHandles(SQLModel):
bluesky: Optional[str] = None
mastodon: Optional[str] = None
instagram: Optional[str] = None
class HeadlinerBand(SQLModel):
name: str
slug: str
tier: str # headliner, main_stage, supporting
logo_url: Optional[str] = None
class PublicProfileRead(SQLModel):
id: int
username: str
display_name: str
bio: Optional[str] = None
avatar: Optional[str] = None
avatar_bg_color: Optional[str] = None
avatar_text: Optional[str] = None
location: Optional[str] = None
# Socials
social_handles: SocialHandles
# The Lineup
headliners: List[HeadlinerBand]
supporting_acts: List[HeadlinerBand]
# Stats
stats: Dict[str, int]
joined_at: datetime
# --- Pagination ---
T = TypeVar('T')
class PaginationMeta(SQLModel):
total: int
limit: int
offset: int
class PaginatedResponse(SQLModel, Generic[T]):
data: List[T]
meta: PaginationMeta