mnemo_cards/mnemo_cards_backend/lib/tests/test_manager.dart
Dmitry 77b4ce91b5
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
postgress
2025-12-13 16:27:05 +03:00

244 lines
No EOL
7.2 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:injectable/injectable.dart';
import 'package:mnemo_cards_backend/database/database.dart';
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart';
import 'package:mnemo_cards_backend/packs/pack_manager.dart';
import 'package:mnemo_cards_backend/tests/generators/models/creation_test_data.dart';
import 'package:mnemo_cards_backend/tests/test_extension.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:drift/drift.dart' as drift;
import '../packs/pack_dto_converter.dart';
import 'generators/question_generators/input_buttons_question_generator.dart';
import 'generators/pack_test_generator.dart';
import 'generators/question_generators/simple_question_generator.dart';
@lazySingleton
class TestManager {
final AppDatabase _db;
final PackDtoConverter _packDtoConverter;
List<CreationTestData> _customCreationTestData = [];
TestManager(this._db, this._packDtoConverter);
Future<TestStatisticsDto?> _testStatisticsDto(
int userId, int testId) async {
final statistics = await _db.testDao.getTestStatistics(userId, testId);
if (statistics == null) return null;
// Convert TestStatistic to TestStatisticsDto
return TestStatisticsDto(
testId: statistics.testId.toString(),
results: statistics.results,
completedAt: statistics.completedAt.toIso8601String(),
);
}
Future<TestDto?> fetchTest(String id, UserModel user) async {
final testId = int.tryParse(id);
if (testId == null) return null;
final test = await _db.testDao.getTestById(testId);
if (test == null) return null;
final questions = await _db.testDao.getTestQuestions(testId);
final statistics = await _testStatisticsDto(user.id!, testId);
// Convert Test to TestDto
final questionsList = questions.map((q) {
// Parse question body based on type
final body = json.decode(q.body) as Map<String, dynamic>;
return AbstractTestQuestion.fromJson({
'questionType': q.questionType,
...body,
});
}).toList();
return TestDto(
id: testId.toString(),
name: test.name,
color: test.color,
cover: test.cover,
version: test.version ?? '1.0',
time: test.time,
timeSubtitle: test.timeSubtitle,
questions: questionsList,
statistics: statistics,
);
}
Future<List<TestDto>> availableTests(UserModel userModel) async {
final tests = await _db.testDao.getAllTests();
final testDtos = <TestDto>[];
for (final test in tests) {
final questions = await _db.testDao.getTestQuestions(test.id);
final statistics = await _testStatisticsDto(userModel.id!, test.id);
final questionsList = questions.map((q) {
final body = json.decode(q.body) as Map<String, dynamic>;
return AbstractTestQuestion.fromJson({
'questionType': q.questionType,
...body,
});
}).toList();
testDtos.add(TestDto(
id: test.id.toString(),
name: test.name,
color: test.color,
cover: test.cover,
version: test.version ?? '1.0',
time: test.time,
timeSubtitle: test.timeSubtitle,
questions: questionsList,
statistics: statistics,
));
}
return testDtos;
}
Future<List<TestDto>> fetchPackTests(
UserModel user,
CardPackModel model,
) async {
final packId = model.id;
if (packId == null) return [];
final tests = await _db.testDao.getTestsByPackId(packId);
final testDtos = <TestDto>[];
for (final test in tests) {
final questions = await _db.testDao.getTestQuestions(test.id);
final statistics = await _testStatisticsDto(user.id!, test.id);
final questionsList = questions.map((q) {
final body = json.decode(q.body) as Map<String, dynamic>;
return AbstractTestQuestion.fromJson({
'questionType': q.questionType,
...body,
});
}).toList();
testDtos.add(TestDto(
id: test.id.toString(),
name: test.name,
color: test.color,
cover: test.cover,
version: test.version ?? '1.0',
time: test.time,
timeSubtitle: test.timeSubtitle,
questions: questionsList,
statistics: statistics,
));
}
return testDtos;
}
Future<bool> _updateGeneratedTestsIfRequired(CardPackModel model) async {
final packId = model.id;
if (packId == null) return false;
// Check if pack has any generated tests
final existingTests = await _db.testDao.getTestsByPackId(packId);
final hasGeneratedTests = existingTests.any((test) =>
test.version?.contains('generated') ?? false);
// Generate tests if none exist
if (!hasGeneratedTests) {
await updateGeneratedTests(model);
return true;
}
return false;
}
Future<void> refreshCustomCreationTestsData() async {
// Load custom creation test data from database
// For now, keep it simple
_customCreationTestData = [];
}
Future<void> updateGeneratedTests(CardPackModel model) async {
final packId = model.id;
if (packId == null) return;
// Get pack data from database
final pack = await _db.packDao.getPackById(packId);
if (pack == null) return;
// Get all cards for the pack
final cards = await _db.packDao.getPackCards(packId);
if (cards.isEmpty) return;
// Create creation test data
final testDataItems = cards.map((card) {
return TestDataItem(
id: card.id.toString(),
original: card.original,
translation: card.translation,
mnemo: card.mnemo,
image: card.image,
back: card.back,
transcription: card.transcription,
);
}).toList();
final creationTestData = CreationTestData(
items: testDataItems,
color: pack.color,
packId: packId.toString(),
);
// Generate test using PackTestGenerator
final generator = PackTestGenerator(creationTestData);
final testDto = await generator.generate(
name: '${pack.title} Test',
ratios: {
TestQuestionType.simple: 0.7,
TestQuestionType.input_buttons: 0.3,
},
multiply: 1.0,
);
// Save test to database
await addTest(testDto);
// Link test to pack
final testId = int.tryParse(testDto.id ?? '');
if (testId != null) {
await _db.testDao.linkTestToPack(testId, packId);
}
}
Future<void> addTest(TestDto testDto) async {
await _db.transaction(() async {
// Create test
final testCompanion = TestsCompanion.insert(
name: testDto.name,
color: drift.Value(testDto.color),
cover: drift.Value(testDto.cover),
version: drift.Value(testDto.version),
time: drift.Value(testDto.time),
timeSubtitle: drift.Value(testDto.timeSubtitle),
);
final testId = await _db.testDao.createTest(testCompanion);
// Create questions
for (final question in testDto.questions) {
final questionCompanion = TestQuestionsCompanion.insert(
testId: testId,
questionType: question.questionType.name,
body: json.encode(question.toJson()),
);
await _db.testDao.createTestQuestion(questionCompanion);
}
});
}
}