fediversion/backend/models_tickets.py
fullsizemalt b4cddf41ea feat: Initialize Fediversion multi-band platform
- Fork elmeg-demo codebase for multi-band support
- Add data importer infrastructure with base class
- Create band-specific importers:
  - phish.py: Phish.net API v5
  - grateful_dead.py: Grateful Stats API
  - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm)
- Add spec-kit configuration for Gemini
- Update README with supported bands and architecture
2025-12-28 12:39:28 -08:00

140 lines
3.8 KiB
Python

"""
Bug Tracker Models - ISOLATED MODULE
No dependencies on main Elmeg models.
Can be removed by: deleting this file + routes file + removing router import from main.py
"""
from datetime import datetime
from typing import Optional, List
from sqlmodel import SQLModel, Field, Relationship
from enum import Enum
class TicketType(str, Enum):
BUG = "bug"
FEATURE = "feature"
QUESTION = "question"
OTHER = "other"
class TicketStatus(str, Enum):
OPEN = "open"
IN_PROGRESS = "in_progress"
RESOLVED = "resolved"
CLOSED = "closed"
class TicketPriority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class Ticket(SQLModel, table=True):
"""
Support ticket - fully decoupled from User model.
Stores reporter info as strings, not FKs.
"""
id: Optional[int] = Field(default=None, primary_key=True)
ticket_number: str = Field(unique=True, index=True) # ELM-001
type: TicketType = Field(default=TicketType.BUG)
status: TicketStatus = Field(default=TicketStatus.OPEN)
priority: TicketPriority = Field(default=TicketPriority.MEDIUM)
title: str = Field(max_length=200)
description: str = Field(default="")
# Reporter info - stored as strings, not FK
reporter_email: str = Field(index=True)
reporter_name: Optional[str] = None
reporter_user_id: Optional[int] = None # Reference only, not FK
# Assignment - stored as strings
assigned_to_email: Optional[str] = None
assigned_to_name: Optional[str] = None
is_public: bool = Field(default=False)
upvotes: int = Field(default=0)
# Environment info
browser: Optional[str] = None
os: Optional[str] = None
page_url: Optional[str] = None
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
resolved_at: Optional[datetime] = None
# Relationships (within ticket system only)
comments: List["TicketComment"] = Relationship(back_populates="ticket")
class TicketComment(SQLModel, table=True):
"""Comment on a ticket - no FK to User"""
id: Optional[int] = Field(default=None, primary_key=True)
ticket_id: int = Field(foreign_key="ticket.id")
# Author info - stored as strings
author_email: str
author_name: str
author_user_id: Optional[int] = None # Reference only
content: str
is_internal: bool = Field(default=False) # Admin-only visibility
created_at: datetime = Field(default_factory=datetime.utcnow)
# Relationship
ticket: Optional[Ticket] = Relationship(back_populates="comments")
# ============ Schemas ============
class TicketCreate(SQLModel):
type: TicketType = TicketType.BUG
priority: TicketPriority = TicketPriority.MEDIUM
title: str
description: str = ""
reporter_email: Optional[str] = None
reporter_name: Optional[str] = None
browser: Optional[str] = None
os: Optional[str] = None
page_url: Optional[str] = None
class TicketUpdate(SQLModel):
status: Optional[TicketStatus] = None
priority: Optional[TicketPriority] = None
assigned_to_email: Optional[str] = None
assigned_to_name: Optional[str] = None
is_public: Optional[bool] = None
class TicketCommentCreate(SQLModel):
content: str
class TicketRead(SQLModel):
id: int
ticket_number: str
type: TicketType
status: TicketStatus
priority: TicketPriority
title: str
description: str
reporter_email: str
reporter_name: Optional[str]
is_public: bool
upvotes: int
created_at: datetime
updated_at: datetime
resolved_at: Optional[datetime]
class TicketCommentRead(SQLModel):
id: int
author_name: str
content: str
is_internal: bool
created_at: datetime