- 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
140 lines
3.8 KiB
Python
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
|