lab4 / app /api /topics /services.py
brestok's picture
init
a08f988
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)