VisionApp/tickets/data.py
Mathis e46c04fe98
All checks were successful
ci / ci (push) Successful in 44s
feat(ticket): add transfer, priority, lock/unlock, stats, message recording
- TransferButton: transfer ticket to another staff member
- PriorityButton: set ticket priority (low/normal/high/urgent)
- LockButton: lock/unlock ticket (toggle channel permissions)
- StatsButton: show ticket info (category, user, claimed, priority, messages)
- on_message listener: records all messages for transcript
- TicketData: added locked, priority fields
2026-09-25 19:38:24 +02:00

133 lines
4 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
class TicketStatus(str, Enum):
OPEN = "open"
CLOSED = "closed"
class TicketPriority(str, Enum):
LOW = "low"
NORMAL = "normal"
HIGH = "high"
URGENT = "urgent"
@dataclass
class TicketCategory:
id: str
name: str
emoji: str = ""
description: str = ""
staff_role_id: int | None = None
discord_category_id: int | None = None
def to_dict(self) -> dict:
return {
"id": self.id,
"name": self.name,
"emoji": self.emoji,
"description": self.description,
"staff_role_id": self.staff_role_id,
"discord_category_id": self.discord_category_id,
}
@classmethod
def from_dict(cls, data: dict) -> TicketCategory:
return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
@dataclass
class TicketMessage:
author_id: int
author_name: str
content: str
timestamp: str
attachments: list[str] = field(default_factory=list)
is_staff: bool = False
@dataclass
class TicketData:
channel_id: int
guild_id: int
user_id: int
category_id: str
status: TicketStatus = TicketStatus.OPEN
created_at: str = ""
closed_at: str | None = None
closed_by: int | None = None
claimed_by: int | None = None
locked: bool = False
priority: TicketPriority = TicketPriority.NORMAL
messages: list[TicketMessage] = field(default_factory=list)
reason: str = ""
def to_dict(self) -> dict:
return {
"channel_id": self.channel_id,
"guild_id": self.guild_id,
"user_id": self.user_id,
"category_id": self.category_id,
"status": self.status.value,
"created_at": self.created_at,
"closed_at": self.closed_at,
"closed_by": self.closed_by,
"claimed_by": self.claimed_by,
"locked": self.locked,
"priority": self.priority.value,
"messages": [
{
"author_id": m.author_id,
"author_name": m.author_name,
"content": m.content,
"timestamp": m.timestamp,
"attachments": m.attachments,
"is_staff": m.is_staff,
}
for m in self.messages
],
"reason": self.reason,
}
@classmethod
def from_dict(cls, data: dict) -> TicketData:
messages = [TicketMessage(**m) for m in data.pop("messages", [])]
data["status"] = TicketStatus(data.get("status", "open"))
data["priority"] = TicketPriority(data.get("priority", "normal"))
data.pop("transcript_path", None)
data.pop("rating", None)
data.pop("feedback", None)
return cls(messages=messages, **{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
@dataclass
class GuildTicketConfig:
guild_id: int
enabled: bool = False
categories: list[TicketCategory] = field(default_factory=list)
staff_role_id: int | None = None
log_channel_id: int | None = None
panel_channel_id: int | None = None
panel_message_id: int | None = None
transcript_enabled: bool = True
def to_dict(self) -> dict:
return {
"guild_id": self.guild_id,
"enabled": self.enabled,
"categories": [c.to_dict() for c in self.categories],
"staff_role_id": self.staff_role_id,
"log_channel_id": self.log_channel_id,
"panel_channel_id": self.panel_channel_id,
"panel_message_id": self.panel_message_id,
"transcript_enabled": self.transcript_enabled,
}
@classmethod
def from_dict(cls, data: dict) -> GuildTicketConfig:
categories = [TicketCategory.from_dict(c) for c in data.pop("categories", [])]
return cls(categories=categories, **{k: v for k, v in data.items() if k in cls.__dataclass_fields__})