Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run
- Backend: Ticket and TicketComment models (no FK to User) - API: /tickets/* endpoints for submit, view, comment, upvote - Admin: /tickets/admin/* for triage queue - Frontend: /bugs pages (submit, my-tickets, known-issues, detail) - Feature flag: ENABLE_BUG_TRACKER env var (default: true) To disable: Set ENABLE_BUG_TRACKER=false To remove: Delete models_tickets.py, routers/tickets.py, frontend/app/bugs/
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
|