Skip to content

Commit 3649ab0

Browse files
committed
Fix stuff
1 parent 0aec3f1 commit 3649ab0

5 files changed

Lines changed: 117 additions & 2 deletions

File tree

ticket-backend/app/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
DiscordContent,
1717
GitHubContent,
1818
FormContent,
19+
SMSContent,
1920
content_from_dict,
2021
)
2122
from .ticket import Ticket, InvalidStateTransitionError
@@ -39,6 +40,7 @@
3940
"DiscordContent",
4041
"GitHubContent",
4142
"FormContent",
43+
"SMSContent",
4244
"content_from_dict",
4345
# Ticket
4446
"Ticket",

ticket-backend/app/models/content.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,87 @@ def from_dict(cls, data: dict[str, Any]) -> "FormContent":
395395
)
396396

397397

398+
class SMSContent(TicketContent):
399+
"""Content from SMS messages."""
400+
401+
def __init__(
402+
self,
403+
sender_phone_number: str,
404+
message_body: str,
405+
timestamp: datetime,
406+
message_sid: Optional[str] = None,
407+
):
408+
self._sender_phone_number = sender_phone_number
409+
self._recipient_phone_number = recipient_phone_number
410+
self._message_body = message_body
411+
self._timestamp = timestamp
412+
self._message_sid = message_sid
413+
414+
@property
415+
def raw_content(self) -> str:
416+
return self._message_body
417+
418+
@property
419+
def sender(self) -> str:
420+
return self._sender_phone_number
421+
422+
@property
423+
def timestamp(self) -> datetime:
424+
return self._timestamp
425+
426+
@property
427+
def metadata(self) -> dict[str, Any]:
428+
return {
429+
"recipient_phone_number": self._recipient_phone_number,
430+
"message_sid": self._message_sid,
431+
}
432+
433+
@property
434+
def sender_phone_number(self) -> str:
435+
return self._sender_phone_number
436+
437+
@property
438+
def recipient_phone_number(self) -> str:
439+
return self._recipient_phone_number
440+
441+
@property
442+
def message_body(self) -> str:
443+
return self._message_body
444+
445+
@property
446+
def message_sid(self) -> Optional[str]:
447+
return self._message_sid
448+
449+
def extract_body(self) -> str:
450+
return self._message_body
451+
452+
def extract_attachments(self) -> list[dict[str, Any]]:
453+
return []
454+
455+
def to_dict(self) -> dict[str, Any]:
456+
return {
457+
"type": "sms",
458+
"sender_phone_number": self._sender_phone_number,
459+
"recipient_phone_number": self._recipient_phone_number,
460+
"message_body": self._message_body,
461+
"timestamp": self._timestamp.isoformat(),
462+
"message_sid": self._message_sid,
463+
}
464+
465+
@classmethod
466+
def from_dict(cls, data: dict[str, Any]) -> "SMSContent":
467+
timestamp = data.get("timestamp")
468+
if isinstance(timestamp, str):
469+
timestamp = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
470+
return cls(
471+
sender_phone_number=data["sender_phone_number"],
472+
recipient_phone_number=data["recipient_phone_number"],
473+
message_body=data["message_body"],
474+
timestamp=timestamp,
475+
message_sid=data.get("message_sid"),
476+
)
477+
478+
398479
def content_from_dict(data: dict[str, Any]) -> TicketContent:
399480
"""Factory function to create the appropriate content type from a dictionary."""
400481
content_type = data.get("type", "").lower()
@@ -407,5 +488,7 @@ def content_from_dict(data: dict[str, Any]) -> TicketContent:
407488
return GitHubContent.from_dict(data)
408489
elif content_type == "form":
409490
return FormContent.from_dict(data)
491+
elif content_type == "sms":
492+
return SMSContent.from_dict(data)
410493
else:
411494
raise ValueError(f"Unknown content type: {content_type}")

ticket-backend/app/models/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class TicketSource(str, Enum):
5353
GITHUB = "GITHUB"
5454
FORM = "FORM"
5555
WEBHOOK = "WEBHOOK"
56+
SMS = "SMS"
5657

5758

5859
class AutoResolveAction(str, Enum):

ticket-backend/app/routes/tickets.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
EmailContent,
2020
DiscordContent,
2121
GitHubContent,
22+
GitHubContent,
2223
FormContent,
24+
SMSContent,
2325
)
2426
from app.storage import ticket_repository
2527
from app.queues import queue_manager
@@ -83,6 +85,19 @@ class Config:
8385
populate_by_name = True
8486

8587

88+
class SMSPayload(BaseModel):
89+
"""SMS content payload (e.g. from Twilio)."""
90+
91+
sender: str = Field(..., alias="From")
92+
recipient: str = Field(..., alias="To")
93+
body: str = Field(..., alias="Body")
94+
message_sid: Optional[str] = Field(None, alias="MessageSid")
95+
timestamp: Optional[str] = None
96+
97+
class Config:
98+
populate_by_name = True
99+
100+
86101
class IngestRequest(BaseModel):
87102
"""Request body for ticket ingestion."""
88103

@@ -220,6 +235,20 @@ def create_content_from_payload(content_type: str, payload: dict[str, Any]):
220235
submitter_email=payload.get("submitter_email"),
221236
submitter_name=payload.get("submitter_name", payload.get("user")),
222237
)
238+
elif content_type == "sms":
239+
return SMSContent(
240+
sender_phone_number=payload.get(
241+
"From", payload.get("sender", payload.get("subject", ""))
242+
),
243+
recipient_phone_number=payload.get(
244+
"To", payload.get("recipient", payload.get("user", ""))
245+
),
246+
message_body=payload.get("Body", payload.get("body", "")),
247+
timestamp=parse_timestamp(payload.get("timestamp")),
248+
message_sid=payload.get(
249+
"MessageSid", payload.get("message_id", payload.get("id"))
250+
),
251+
)
223252
else:
224253
raise ValueError(f"Unknown content type: {content_type}")
225254

ticket-frontend/src/lib/api/client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export interface BackendTicket {
99
id: string;
1010
created_at: string;
1111
updated_at: string;
12-
source: 'EMAIL' | 'DISCORD' | 'GITHUB' | 'FORM' | 'WEBHOOK';
12+
source: 'EMAIL' | 'DISCORD' | 'GITHUB' | 'FORM' | 'WEBHOOK' | 'SMS';
1313
priority: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
1414
category: 'BILLING' | 'TECHNICAL_SUPPORT' | 'FEATURE_REQUEST' | 'BUG_REPORT' | 'ADMIN' | 'OTHER' | null;
1515
status: 'INBOX' | 'TRIAGE_PENDING' | 'ASSIGNED' | 'IN_PROGRESS' | 'RESOLVED' | 'CLOSED';
@@ -321,7 +321,7 @@ export async function getAgentStats(agentId: string): Promise<{
321321
}
322322

323323
export async function createTicket(ticketData: {
324-
source: 'EMAIL' | 'DISCORD' | 'GITHUB' | 'FORM' | 'WEBHOOK';
324+
source: 'EMAIL' | 'DISCORD' | 'GITHUB' | 'FORM' | 'WEBHOOK' | 'SMS';
325325
content_type: string;
326326
payload: Record<string, any>;
327327
metadata?: Record<string, any>;

0 commit comments

Comments
 (0)