/
gr.ev.vl
/
TestGen
Обзор
Документация
Войти
/
gr.ev.vl
/
TestGen
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
backend/src/testgen/services/export.py
119 строк
4 KB
gr.ev.vl
Initial commit
06 июн 2026, 02:41
06 июн 2026, 02:41
02fb1fb
Код
Авторство
О чём код?
""" Сервис экспорта вопросов. """ import logging from uuid import UUID from sqlalchemy.ext.asyncio import AsyncSession # Late import from ..config import settings from ..core.enums import ExportFormat from ..core.exceptions import EntityNotFoundError, ValidationError from ..domain.models.export_job import ExportJob from ..domain.repositories.export_job import ExportJobRepository from ..domain.repositories.question import QuestionRepository from ..infrastructure.export.aiken import AikenExporter from ..infrastructure.export.csv_exporter import CSVExporter from ..infrastructure.export.gift import GIFTExporter from ..infrastructure.export.moodle_xml import MoodleXMLExporter from ..infrastructure.storage.file_storage import FileStorage logger = logging.getLogger(__name__) class ExportService: """Сервис экспорта.""" EXPORTERS = { ExportFormat.MOODLE_XML: MoodleXMLExporter, ExportFormat.GIFT: GIFTExporter, ExportFormat.AIKEN: AikenExporter, ExportFormat.CSV: CSVExporter, } def __init__(self, db: AsyncSession, file_storage: FileStorage): self.db = db self.file_storage = file_storage self.question_repo = QuestionRepository(db) self.export_repo = ExportJobRepository(db) async def export( self, question_ids: list[UUID], format: ExportFormat, include_explanations: bool = False, include_taxonomy: bool = False, user_id: UUID | None = None, ) -> ExportJob: """Экспортировать выбранные вопросы.""" if not question_ids: raise ValidationError("Не выбрано ни одного вопроса для экспорта") # Загрузка вопросов questions = [] for qid in question_ids: question = await self.question_repo.get_with_distractors(qid) if question is None: raise EntityNotFoundError("Вопрос", str(qid)) questions.append(question) # Выбор экспортёра exporter_class = self.EXPORTERS.get(format) if exporter_class is None: raise ValidationError(f"Неподдерживаемый формат экспорта: {format}") exporter = exporter_class( include_explanations=include_explanations, include_taxonomy=include_taxonomy, ) # Генерация контента content = exporter.export(questions) # Сохранение файла file_name = self._generate_file_name(format) file_path = await self.file_storage.save( content=content, directory=settings.storage.EXPORT_DIR, file_name=file_name, ) # Запись в БД job = await self.export_repo.create( created_by=user_id, format=format, include_explanations=include_explanations, include_taxonomy=include_taxonomy, question_ids=question_ids, question_count=len(questions), file_name=file_name, file_size_bytes=len(content.encode("utf-8")), file_path=file_path, ) logger.info( f"Export completed: {job.id} ({format}, {len(questions)} questions)" ) return job async def get_export_history( self, user_id: UUID, offset: int = 0, limit: int = 50 ) -> list[ExportJob]: """Получить историю экспортов.""" return await self.export_repo.get_by_user(user_id, offset, limit) async def get_export_job(self, job_id: UUID) -> ExportJob: """Получить задачу экспорта.""" return await self.export_repo.get_or_raise(job_id) def _generate_file_name(self, format: ExportFormat) -> str: """Сгенерировать имя файла.""" from datetime import datetime exporter_class = self.EXPORTERS[format] exporter = exporter_class() timestamp = datetime.utcnow().strftime("%Y%m%d_%H%M%S") return f"export_{timestamp}.{exporter.get_file_extension()}"