utils
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Web App CI / test (push) Waiting to run
Web App 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

This commit is contained in:
Dmitry 2025-12-19 06:20:21 +03:00
parent 47005a357a
commit 8b754bbd9f
2 changed files with 116 additions and 6 deletions

View file

@ -283,15 +283,22 @@ class PackDao extends DatabaseAccessor<AppDatabase> with _$PackDaoMixin {
Future<List<VoiceModel>> getCardVoices(String cardId) async {
print('🔍 DAO getCardVoices: Querying voices for card $cardId');
// First, check if there are any voices in CardVoices table for this card
// First, check if there are any voices in VoiceModels table with direct cardId link
final directVoicesQuery = select(voiceModels)
..where((v) => v.cardId.equals(cardId));
final directVoices = await directVoicesQuery.get();
print('🔍 DAO getCardVoices: Found ${directVoices.length} voices in VoiceModels with direct cardId link');
// Check if there are any voices in CardVoices table for this card
final countExpr = cardVoices.cardId.count();
final countQuery = selectOnly(cardVoices)
..addColumns([countExpr])
..where(cardVoices.cardId.equals(cardId));
final countResult = await countQuery.getSingle();
final count = countResult.read(countExpr) ?? 0;
print('🔍 DAO getCardVoices: Found $count entries in CardVoices table for card $cardId');
print('🔍 DAO getCardVoices: Found $count entries in CardVoices junction table for card $cardId');
// Query through junction table
final query = select(voiceModels).join([
innerJoin(
cardVoices,
@ -301,7 +308,13 @@ class PackDao extends DatabaseAccessor<AppDatabase> with _$PackDaoMixin {
]);
final result = await query.map((row) => row.readTable(voiceModels)).get();
print('🔍 DAO getCardVoices: Query returned ${result.length} voices');
print('🔍 DAO getCardVoices: Query through junction table returned ${result.length} voices');
// If junction table query returns nothing but direct link exists, return direct voices
if (result.isEmpty && directVoices.isNotEmpty) {
print('⚠️ DAO getCardVoices: Junction table is empty but direct link exists! Using direct voices.');
return directVoices;
}
return result;
}
@ -310,16 +323,44 @@ class PackDao extends DatabaseAccessor<AppDatabase> with _$PackDaoMixin {
Future<void> addVoiceToCard(String cardId, String voiceId) async {
print('🔍 DAO addVoiceToCard: Linking voice $voiceId to card $cardId');
try {
await into(cardVoices).insert(
// Check if voice exists
final voice = await getVoiceById(voiceId);
if (voice == null) {
print('❌ DAO addVoiceToCard: Voice $voiceId does not exist!');
throw Exception('Voice $voiceId does not exist');
}
print('✅ DAO addVoiceToCard: Voice $voiceId exists with cardId=${voice.cardId}');
// Check if card exists
final card = await getCardById(cardId);
if (card == null) {
print('❌ DAO addVoiceToCard: Card $cardId does not exist!');
throw Exception('Card $cardId does not exist');
}
print('✅ DAO addVoiceToCard: Card $cardId exists');
// Insert into junction table
final result = await into(cardVoices).insert(
CardVoicesCompanion.insert(
cardId: cardId,
voiceId: voiceId,
),
mode: InsertMode.insertOrIgnore,
);
print('✅ DAO addVoiceToCard: Successfully linked voice $voiceId to card $cardId');
} catch (e) {
print('✅ DAO addVoiceToCard: Insert result: $result');
// Verify the insert
final verifyQuery = select(cardVoices)
..where((cv) => cv.cardId.equals(cardId) & cv.voiceId.equals(voiceId));
final verifyResult = await verifyQuery.getSingleOrNull();
if (verifyResult == null) {
print('❌ DAO addVoiceToCard: Verification failed! Link was not created.');
} else {
print('✅ DAO addVoiceToCard: Successfully linked and verified voice $voiceId to card $cardId');
}
} catch (e, stackTrace) {
print('❌ DAO addVoiceToCard: Error linking voice $voiceId to card $cardId: $e');
print('Stack trace: $stackTrace');
rethrow;
}
}

View file

@ -0,0 +1,69 @@
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import '../domain/config/api_config_v2.dart';
/// Utility functions for working with card images
class CardImageUtils {
/// Get the display URL for a card's image
///
/// Priority:
/// 1. imageUrl (presigned URL from backend)
/// 2. image if it's a full URL (starts with http/https)
/// 3. image if it's a filename - convert to API endpoint URL
///
/// Returns null if no image is available
static String? getCardImageUrl(
GameCardDto card,
String packId,
) {
// First priority: use presigned URL if available
if (card.imageUrl != null && card.imageUrl!.isNotEmpty) {
return card.imageUrl;
}
// Second priority: check if image is a full URL
final image = card.image;
if (image != null && image.isNotEmpty) {
// If it's already a full URL, use it
if (image.startsWith('http://') || image.startsWith('https://')) {
return image;
}
// If it's a filename, convert to API endpoint URL
return ApiConfigV2.getCardImageUrl(packId, card.id);
}
return null;
}
/// Get the display URL for a card's back image
///
/// Priority:
/// 1. imageBackUrl (presigned URL from backend)
/// 2. imageBack if it's a full URL (starts with http/https)
/// 3. imageBack if it's a filename - convert to API endpoint URL
///
/// Returns null if no back image is available
static String? getCardImageBackUrl(
GameCardDto card,
String packId,
) {
// First priority: use presigned URL if available
if (card.imageBackUrl != null && card.imageBackUrl!.isNotEmpty) {
return card.imageBackUrl;
}
// Second priority: check if imageBack is a full URL
final imageBack = card.imageBack;
if (imageBack != null && imageBack.isNotEmpty) {
// If it's already a full URL, use it
if (imageBack.startsWith('http://') || imageBack.startsWith('https://')) {
return imageBack;
}
// If it's a filename, convert to API endpoint URL
return ApiConfigV2.getCardImageBackUrl(packId, card.id);
}
return null;
}
}