first commit

This commit is contained in:
Anurag Jangid 2026-10-08 02:52:58 +05:30
commit 34ea15a54d
246 changed files with 18660 additions and 0 deletions

View file

@ -0,0 +1,3 @@
from app.schemas.auth import LoginRequest, RegisterRequest, Token, UserPublic
from app.schemas.domain import * # noqa: F403
from app.schemas.health import HealthResponse

View file

@ -0,0 +1,181 @@
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field
from app.models.enums import AdminRole, EventStatus, EventType, OrderStatus, TicketTypeStatus
class AdminLoginRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=8, max_length=128)
class AdminToken(BaseModel):
access_token: str
token_type: str = "bearer"
class AdminUserPublic(BaseModel):
id: int
email: EmailStr
role: AdminRole
model_config = {"from_attributes": True}
class DashboardMetrics(BaseModel):
total_revenue_paise: int
tickets_sold: int
tickets_remaining: int
orders_total: int
orders_paid: int
orders_pending: int
attendance: int
upcoming_events: int
class EventStatsRow(BaseModel):
event_id: int
event_title: str
starts_at: datetime
tickets_sold: int
tickets_remaining: int
revenue_paise: int
attendance: int
class VenueAdmin(BaseModel):
id: int
slug: str
name: str
area: str
city: str
address: str
map_url: str | None = None
description: str | None = None
model_config = {"from_attributes": True}
class VenueCreate(BaseModel):
slug: str = Field(min_length=2, max_length=120)
name: str = Field(min_length=2, max_length=200)
area: str = Field(min_length=2, max_length=120)
city: str = Field(default="Bengaluru", max_length=80)
address: str = Field(min_length=5, max_length=512)
map_url: str | None = Field(default=None, max_length=512)
description: str | None = None
class VenueUpdate(BaseModel):
slug: str | None = Field(default=None, max_length=120)
name: str | None = Field(default=None, max_length=200)
area: str | None = Field(default=None, max_length=120)
city: str | None = Field(default=None, max_length=80)
address: str | None = Field(default=None, max_length=512)
map_url: str | None = Field(default=None, max_length=512)
description: str | None = None
class EventAdmin(BaseModel):
id: int
slug: str
title: str
category: EventType
status: EventStatus
venue_id: int
description: str | None
starts_at: datetime
ends_at: datetime | None
is_featured: bool
cover_image_url: str | None
cover_image_alt: str | None
model_config = {"from_attributes": True}
class EventCreate(BaseModel):
slug: str = Field(min_length=2, max_length=200)
title: str = Field(min_length=2, max_length=240)
category: EventType
status: EventStatus = EventStatus.draft
venue_id: int
description: str | None = None
starts_at: datetime
ends_at: datetime | None = None
is_featured: bool = False
cover_image_url: str | None = None
cover_image_alt: str | None = None
class EventUpdate(BaseModel):
slug: str | None = Field(default=None, max_length=200)
title: str | None = Field(default=None, max_length=240)
category: EventType | None = None
status: EventStatus | None = None
venue_id: int | None = None
description: str | None = None
starts_at: datetime | None = None
ends_at: datetime | None = None
is_featured: bool | None = None
cover_image_url: str | None = None
cover_image_alt: str | None = None
class TicketTypeAdmin(BaseModel):
id: int
event_id: int
name: str
description: str | None
price_paise: int
quantity_total: int
quantity_sold: int
remaining: int
status: TicketTypeStatus
sort_order: int
model_config = {"from_attributes": True}
class TicketTypeCreate(BaseModel):
event_id: int
name: str = Field(min_length=1, max_length=120)
description: str | None = Field(default=None, max_length=512)
price_paise: int = Field(ge=0)
quantity_total: int = Field(ge=0)
status: TicketTypeStatus = TicketTypeStatus.active
sort_order: int = 0
class TicketTypeUpdate(BaseModel):
name: str | None = Field(default=None, max_length=120)
description: str | None = Field(default=None, max_length=512)
price_paise: int | None = Field(default=None, ge=0)
quantity_total: int | None = Field(default=None, ge=0)
status: TicketTypeStatus | None = None
sort_order: int | None = None
class OrderAdmin(BaseModel):
id: int
user_id: int
event_id: int
status: OrderStatus
total_paise: int
currency: str
provider_order_id: str | None
provider_payment_id: str | None
paid_at: datetime | None
created_at: datetime
model_config = {"from_attributes": True}
class PaymentAdmin(BaseModel):
order_id: int
event_id: int
status: OrderStatus
total_paise: int
provider_payment_id: str | None
payment_reference: str | None
paid_at: datetime | None

View file

@ -0,0 +1,47 @@
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field, field_validator
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
class LoginRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=8, max_length=128)
@field_validator("email")
@classmethod
def normalize_email(cls, value: str) -> str:
return value.strip().lower()
class RegisterRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=8, max_length=128)
full_name: str | None = Field(default=None, max_length=120)
@field_validator("email")
@classmethod
def normalize_email(cls, value: str) -> str:
return value.strip().lower()
@field_validator("full_name")
@classmethod
def strip_name(cls, value: str | None) -> str | None:
if value is None:
return None
stripped = value.strip()
return stripped or None
class UserPublic(BaseModel):
id: int
email: EmailStr
full_name: str | None
is_active: bool
created_at: datetime
model_config = {"from_attributes": True}

View file

@ -0,0 +1,62 @@
from datetime import datetime
from pydantic import BaseModel, Field
from app.models.enums import EventStatus, EventType, TicketTypeStatus
class VenuePublic(BaseModel):
id: int
slug: str
name: str
area: str
city: str
address: str
map_url: str | None = None
description: str | None = None
model_config = {"from_attributes": True}
class EventMediaPublic(BaseModel):
id: int
image_url: str
alt_text: str | None
sort_order: int
model_config = {"from_attributes": True}
class TicketTypePublic(BaseModel):
id: int
name: str
description: str | None
price_paise: int = Field(ge=0)
status: TicketTypeStatus
sort_order: int
remaining_quantity: int = Field(ge=0)
model_config = {"from_attributes": True}
class EventSummary(BaseModel):
id: int
slug: str
title: str
category: EventType
status: EventStatus
starts_at: datetime
ends_at: datetime | None
is_featured: bool
cover_image_url: str | None
cover_image_alt: str | None
venue: VenuePublic
model_config = {"from_attributes": True}
class EventDetail(EventSummary):
description: str | None
meta_description: str | None
media: list[EventMediaPublic]
ticket_types: list[TicketTypePublic]

View file

@ -0,0 +1,170 @@
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field
from app.models.enums import AdminRole, EventType, PlatformKind
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
class LoginRequest(BaseModel):
email: EmailStr
password: str
class SubscribeRequest(BaseModel):
email: EmailStr
neighborhood: str | None = Field(default=None, max_length=120)
class SubscriberPublic(BaseModel):
id: int
email: str
neighborhood: str | None
created_at: datetime
model_config = {"from_attributes": True}
class AdminUserPublic(BaseModel):
id: int
email: str
role: AdminRole
created_at: datetime
model_config = {"from_attributes": True}
class AdminUserCreate(BaseModel):
email: EmailStr
password: str = Field(min_length=8, max_length=128)
role: AdminRole = AdminRole.editor
class PlatformLinkPublic(BaseModel):
id: int
kind: PlatformKind
label: str
url: str
sort_order: int
model_config = {"from_attributes": True}
class PlatformLinkCreate(BaseModel):
kind: PlatformKind
label: str = Field(max_length=120)
url: str = Field(max_length=512)
sort_order: int = 0
is_active: bool = True
class PlatformLinkUpdate(BaseModel):
kind: PlatformKind | None = None
label: str | None = Field(default=None, max_length=120)
url: str | None = Field(default=None, max_length=512)
sort_order: int | None = None
is_active: bool | None = None
class EditionTicketsPublic(BaseModel):
bookmyshow: str | None = None
district: str | None = None
instagram: str | None = None
class MediaAssetPublic(BaseModel):
id: int
url: str
thumb_url: str | None = None
caption: str | None
sort_order: int
model_config = {"from_attributes": True}
class ClickSummaryItem(BaseModel):
link_kind: str
count: int
class OutboundClickPublic(BaseModel):
id: int
link_kind: str
destination_url: str
edition_id: int | None
created_at: datetime
model_config = {"from_attributes": True}
class EventEditionPublic(BaseModel):
id: int
title: str
slug: str
event_type: EventType
city: str
venue_name: str | None
event_date: datetime | None
description: str | None
is_featured: bool
cover_image_url: str | None
cover_thumb_url: str | None = None
tickets: EditionTicketsPublic
meta_description: str | None
media: list[MediaAssetPublic]
model_config = {"from_attributes": True}
class EventEditionAdmin(EventEditionPublic):
is_published: bool
sort_order: int
class EventEditionCreate(BaseModel):
title: str = Field(max_length=200)
slug: str = Field(max_length=200)
event_type: EventType
venue_name: str | None = Field(default=None, max_length=200)
event_date: datetime | None = None
description: str | None = None
is_published: bool = False
is_featured: bool = False
sort_order: int = 0
bookmyshow_url: str | None = Field(default=None, max_length=512)
district_url: str | None = Field(default=None, max_length=512)
instagram_url: str | None = Field(default=None, max_length=512)
meta_description: str | None = Field(default=None, max_length=320)
class EventEditionUpdate(BaseModel):
title: str | None = Field(default=None, max_length=200)
slug: str | None = Field(default=None, max_length=200)
event_type: EventType | None = None
venue_name: str | None = None
event_date: datetime | None = None
description: str | None = None
is_published: bool | None = None
is_featured: bool | None = None
sort_order: int | None = None
bookmyshow_url: str | None = Field(default=None, max_length=512)
district_url: str | None = Field(default=None, max_length=512)
instagram_url: str | None = Field(default=None, max_length=512)
meta_description: str | None = Field(default=None, max_length=320)
class SiteConfigPublic(BaseModel):
city: str = "Bengaluru"
tagline: str
platform_links: list[PlatformLinkPublic]
featured_edition: EventEditionPublic | None
recent_editions: list[EventEditionPublic]
class MediaReorderItem(BaseModel):
id: int
sort_order: int

View file

@ -0,0 +1,7 @@
from pydantic import BaseModel, Field
class HealthResponse(BaseModel):
status: str = Field(examples=["ok"])
service: str = Field(examples=["desi-clans-api"])
database: str = Field(examples=["connected"])

View file

@ -0,0 +1,90 @@
from datetime import datetime
from pydantic import BaseModel, Field
from app.models.enums import OrderStatus, TicketStatus, TicketTypeStatus
class PaymentCheckoutPublic(BaseModel):
provider: str
key_id: str
provider_order_id: str
amount_paise: int
currency: str
order_id: int
expires_at: datetime | None = None
timeout_minutes: int
class EventTicketTypePublic(BaseModel):
id: int
event_id: int
name: str
description: str | None
price_paise: int = Field(ge=0)
status: TicketTypeStatus
sort_order: int
remaining_quantity: int = Field(ge=0)
model_config = {"from_attributes": True}
class OrderLineCreate(BaseModel):
ticket_type_id: int = Field(gt=0)
quantity: int = Field(ge=1, le=20)
class OrderCreate(BaseModel):
event_id: int = Field(gt=0)
items: list[OrderLineCreate] = Field(min_length=1, max_length=20)
class OrderItemPublic(BaseModel):
id: int
ticket_type_id: int
quantity: int
unit_price_paise: int
line_total_paise: int
model_config = {"from_attributes": True}
class OrderPublic(BaseModel):
id: int
event_id: int
status: OrderStatus
total_paise: int
currency: str
payment_reference: str | None
provider_order_id: str | None = None
provider_payment_id: str | None = None
expires_at: datetime | None = None
paid_at: datetime | None = None
created_at: datetime
items: list[OrderItemPublic]
model_config = {"from_attributes": True}
class OrderCheckoutResponse(OrderPublic):
payment: PaymentCheckoutPublic
class PaymentVerifyRequest(BaseModel):
provider_order_id: str = Field(min_length=1, max_length=64)
provider_payment_id: str = Field(min_length=1, max_length=64)
signature: str = Field(min_length=1, max_length=256)
class TicketPublic(BaseModel):
id: int
code: str
order_id: int
ticket_type_id: int
event_id: int
status: TicketStatus
created_at: datetime
ticket_type_name: str | None = None
event_title: str | None = None
model_config = {"from_attributes": True}

View file

@ -0,0 +1,41 @@
from datetime import datetime
from pydantic import BaseModel, Field
from app.models.enums import TicketStatus
class TicketVerifyRequest(BaseModel):
qr_token: str = Field(min_length=16, max_length=128)
class TicketVerifyResponse(BaseModel):
valid: bool
status: TicketStatus
ticket_id: int
ticket_code: str
event_title: str
message: str
class TicketDetailPublic(BaseModel):
id: int
code: str
status: TicketStatus
order_id: int
event_id: int
event_title: str
event_starts_at: datetime
event_ends_at: datetime | None
venue_name: str
venue_area: str
venue_city: str
attendee_name: str
attendee_email: str
ticket_type_name: str
ticket_type_id: int
qr_token: str
qr_payload: str
qr_image_base64: str
used_at: datetime | None
created_at: datetime