|
|
from datetime import datetime |
|
|
from typing import List, Optional |
|
|
from uuid import UUID, uuid4 |
|
|
|
|
|
from fastapi import HTTPException, status |
|
|
|
|
|
from app.api.messages.schemas import MessageCreate |
|
|
from app.api.messages.services import MessageService |
|
|
from app.api.topics.parser import TopicLineParser |
|
|
from app.api.topics.schemas import AddMessageRequest, Topic, TopicCreate, TopicMessage |
|
|
from app.core.config import ( |
|
|
FORBIDDEN_WORDS, |
|
|
FORBIDDEN_WORDS_MESSAGE, |
|
|
TABLE_TOPICS, |
|
|
TOPIC_NOT_FOUND_MESSAGE, |
|
|
) |
|
|
from app.core.file_manager import FileManager |
|
|
from app.core.link import Link, TopicLink, ParticipantLink |
|
|
|
|
|
|
|
|
class TopicService: |
|
|
def __init__(self, file_manager: FileManager, message_service: MessageService | None = None) -> None: |
|
|
self.file_manager = file_manager |
|
|
self.message_service = message_service |
|
|
|
|
|
@staticmethod |
|
|
def _resolve_topic_id(value: UUID | Link) -> UUID: |
|
|
if isinstance(value, UUID): |
|
|
return value |
|
|
return value.resolve({TABLE_TOPICS: lambda link_value: link_value}) |
|
|
|
|
|
def list_topics(self) -> List[Topic]: |
|
|
topics: List[Topic] = [] |
|
|
for line in self.file_manager.read_lines(): |
|
|
try: |
|
|
topics.append(TopicLineParser.parse(line)) |
|
|
except ValueError: |
|
|
continue |
|
|
return topics |
|
|
|
|
|
def get_topic(self, topic_id: UUID | Link) -> Topic: |
|
|
resolved_id = self._resolve_topic_id(topic_id) |
|
|
for topic in self.list_topics(): |
|
|
if topic.id == resolved_id: |
|
|
return topic |
|
|
raise HTTPException( |
|
|
status_code=status.HTTP_404_NOT_FOUND, |
|
|
detail=TOPIC_NOT_FOUND_MESSAGE, |
|
|
) |
|
|
|
|
|
def create_topic(self, payload: TopicCreate) -> Topic: |
|
|
topic_messages = ( |
|
|
[] |
|
|
if self.message_service |
|
|
else [ |
|
|
TopicMessage( |
|
|
participant_id=message.participant_id, |
|
|
content=message.content, |
|
|
) |
|
|
for message in payload.messages |
|
|
] |
|
|
) |
|
|
topic = Topic( |
|
|
id=uuid4(), |
|
|
title=payload.title, |
|
|
description=payload.description, |
|
|
created_at=datetime.utcnow(), |
|
|
participants=payload.participants, |
|
|
messages=topic_messages, |
|
|
) |
|
|
serialized = TopicLineParser.serialize(topic) |
|
|
self.file_manager.append_line(serialized) |
|
|
if self.message_service: |
|
|
for message in payload.messages: |
|
|
self.message_service.create_message( |
|
|
MessageCreate( |
|
|
topic_id=TopicLink(value=topic.id), |
|
|
participant_id=message.participant_id, |
|
|
content=message.content, |
|
|
) |
|
|
) |
|
|
return topic |
|
|
|
|
|
@staticmethod |
|
|
def check_forbidden_words(content: str) -> Optional[str]: |
|
|
content_lower = content.lower() |
|
|
for word in FORBIDDEN_WORDS: |
|
|
if word in content_lower: |
|
|
return word |
|
|
return None |
|
|
|
|
|
def add_message(self, topic_id: UUID | Link, payload: AddMessageRequest) -> Topic: |
|
|
forbidden_word = self.check_forbidden_words(payload.content) |
|
|
if forbidden_word: |
|
|
raise HTTPException( |
|
|
status_code=status.HTTP_400_BAD_REQUEST, |
|
|
detail=f"{FORBIDDEN_WORDS_MESSAGE}: '{forbidden_word}'", |
|
|
) |
|
|
|
|
|
resolved_id = self._resolve_topic_id(topic_id) |
|
|
|
|
|
if self.message_service: |
|
|
self.message_service.create_message( |
|
|
MessageCreate( |
|
|
topic_id=TopicLink(value=resolved_id), |
|
|
participant_id=ParticipantLink(value=payload.participant_id.value), |
|
|
content=payload.content, |
|
|
) |
|
|
) |
|
|
return self.get_topic(resolved_id) |
|
|
|
|
|
topics = self.list_topics() |
|
|
topic_index = None |
|
|
for i, topic in enumerate(topics): |
|
|
if topic.id == resolved_id: |
|
|
topic_index = i |
|
|
break |
|
|
|
|
|
if topic_index is None: |
|
|
raise HTTPException( |
|
|
status_code=status.HTTP_404_NOT_FOUND, |
|
|
detail=TOPIC_NOT_FOUND_MESSAGE, |
|
|
) |
|
|
|
|
|
new_message = TopicMessage( |
|
|
participant_id=payload.participant_id, |
|
|
content=payload.content, |
|
|
) |
|
|
topics[topic_index].messages.append(new_message) |
|
|
|
|
|
lines = [TopicLineParser.serialize(t) for t in topics] |
|
|
self.file_manager.write_lines(lines) |
|
|
|
|
|
return topics[topic_index] |
|
|
|
|
|
def export_topic(self, topic_id: UUID | Link) -> str: |
|
|
topic = self.get_topic(topic_id) |
|
|
return TopicLineParser.serialize(topic) |
|
|
|