From ce9614f676649639b14e5b660933c0f0c5f6e288 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 19 Dec 2025 04:09:04 +0300 Subject: [PATCH] fixes --- .../lib/api/v2/packs_api_v2.dart | 115 +----------------- .../lib/packs/pack_dto_converter.dart | 13 +- .../lib/packs/pack_manager.dart | 50 -------- .../lib/packs/pack_manager_extensions.dart | 56 --------- .../lib/storage/minio_config.dart | 2 +- .../pages/pack_details/pack_details_page.dart | 7 +- .../widgets/card_flipper/card_flipper.dart | 7 +- .../lib/presentation/widgets/card_viewer.dart | 14 +-- .../presentation/widgets/pack_card_item.dart | 7 +- 9 files changed, 21 insertions(+), 250 deletions(-) delete mode 100644 mnemo_cards_backend/lib/packs/pack_manager_extensions.dart diff --git a/mnemo_cards_backend/lib/api/v2/packs_api_v2.dart b/mnemo_cards_backend/lib/api/v2/packs_api_v2.dart index 3d9a585..95f0582 100644 --- a/mnemo_cards_backend/lib/api/v2/packs_api_v2.dart +++ b/mnemo_cards_backend/lib/api/v2/packs_api_v2.dart @@ -1,7 +1,5 @@ import 'dart:convert'; -import 'dart:io'; -import 'package:drift/drift.dart' as d; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_backend/api/authorize/acl_types.dart'; import 'package:mnemo_cards_backend/api/authorize/access_service.dart'; @@ -10,7 +8,7 @@ import 'package:mnemo_cards_backend/database/database.dart' hide VoiceModel; import 'package:mnemo_cards_backend/database/database.dart' as drift show VoiceModel; import 'package:mnemo_cards_backend/packs/card_pack_drift_extension.dart'; import 'package:mnemo_cards_backend/packs/card_image_storage.dart'; -import 'package:mnemo_cards_backend/packs/pack_manager.dart' show PackManager, PackManagerUtils; +import 'package:mnemo_cards_backend/packs/pack_manager.dart' show PackManager; import 'package:mnemo_cards_backend/packs/voice_storage.dart'; import 'package:mnemo_cards_backend/storage/minio_config.dart'; import 'package:mnemo_cards_backend/storage/minio_service.dart'; @@ -511,25 +509,8 @@ class PacksApiV2 { return Response.found(imageValue); } - // Legacy: try to resolve from local file system - final resolved = await CardImageStorage.tryResolveLocalFile( - cardId: cardId, - imageValue: imageValue, - isBack: false, - ); - - if (resolved == null) { - print('Could not resolve image file for card $cardId'); - return _notFound('Image not found'); - } - - return Response.ok( - resolved.bytes, - headers: { - 'Content-Type': resolved.contentType, - 'Cache-Control': 'public, max-age=86400', // Cache for 1 day - }, - ); + // Not a UUID and not a remote URL - image not found + return _notFound('Image not found'); } catch (e, s) { print('Error fetching card image: $e\n$s'); return _internalServerError('Error loading image'); @@ -601,57 +582,8 @@ class PacksApiV2 { return Response.found(imageValue); } - // Legacy: try to resolve from local file system - final resolved = await CardImageStorage.tryResolveLocalFile( - cardId: cardId, - imageValue: imageValue, - isBack: true, - ); - - if (resolved != null) { - if (resolved.fileName != card.imageBack) { - await _db.packDao.updateCard( - card.copyWith(imageBack: d.Value(resolved.fileName)), - ); - } - - return Response.ok( - resolved.bytes, - headers: { - 'Content-Type': resolved.contentType, - 'Cache-Control': 'public, max-age=86400', // Cache for 1 day - }, - ); - } - - final stored = await CardImageStorage.persistFromBase64( - cardId: cardId, - imageValue: imageValue, - preferredFileName: null, - isBack: true, - ); - - if (stored == null) { - return _notFound('Back image not found'); - } - - await _db.packDao.updateCard( - card.copyWith(imageBack: d.Value(stored.fileName)), - ); - - final file = File('${PackManagerUtils.assetsDirectory.path}/cards/${stored.fileName}'); - if (!file.existsSync()) { - return _notFound('Back image not found'); - } - final bytes = await file.readAsBytes(); - - return Response.ok( - bytes, - headers: { - 'Content-Type': stored.contentType, - 'Cache-Control': 'public, max-age=86400', // Cache for 1 day - }, - ); + // Not a UUID and not a remote URL - image not found + return _notFound('Back image not found'); } catch (e, s) { print('Error fetching card back image: $e\n$s'); return _internalServerError('Error loading back image'); @@ -826,42 +758,7 @@ class PacksApiV2 { return _notFound('Voice file not found in storage'); } - // Legacy: local voice file - final resolved = await VoiceStorage.tryResolveLocalFile( - voiceValue: voiceValue, - ); - if (resolved != null) { - return Response.ok( - resolved.bytes, - headers: { - 'Content-Type': resolved.contentType, - 'Cache-Control': 'public, max-age=86400', - }, - ); - } - - // Legacy base64 stored in DB: migrate to file and serve bytes. - final stored = await VoiceStorage.persistFromBase64( - voiceId: voice.id, - voiceValue: voiceValue, - ); - - if (stored != null) { - await _db.packDao.updateVoiceUrl(voice.id, stored.fileName); - final migratedResolved = await VoiceStorage.tryResolveLocalFile( - voiceValue: stored.fileName, - ); - if (migratedResolved != null) { - return Response.ok( - migratedResolved.bytes, - headers: { - 'Content-Type': migratedResolved.contentType, - 'Cache-Control': 'public, max-age=86400', - }, - ); - } - } - + // Not a UUID and not a remote URL - voice file not found return _notFound('Voice file not found'); } catch (e, s) { print('Error fetching voice file: $e\n$s'); diff --git a/mnemo_cards_backend/lib/packs/pack_dto_converter.dart b/mnemo_cards_backend/lib/packs/pack_dto_converter.dart index c4a542e..40c558f 100644 --- a/mnemo_cards_backend/lib/packs/pack_dto_converter.dart +++ b/mnemo_cards_backend/lib/packs/pack_dto_converter.dart @@ -3,7 +3,6 @@ import 'package:mnemo_cards_backend/api/ads/ads_manager.dart'; import 'package:mnemo_cards_backend/extensions.dart'; import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart'; import 'package:mnemo_cards_backend/packs/card_model_extension.dart'; -import 'package:mnemo_cards_backend/packs/pack_manager_extensions.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'products_price_resolver.dart'; @@ -45,9 +44,7 @@ class PackDtoConverter { cards: model.cards.length, tests: model.tests.length, price: price, - imageBase64: model.cover != null - ? await model.cover!.smallBase64Image - : null, + imageBase64: null, // Legacy: covers should be stored in MinIO, not read from disk color: model.color, isAvailable: available, // trail: 'asset:icons/gift.png', @@ -95,9 +92,7 @@ class PackDtoConverter { .toDtosList(model.cardsOrder) .map( (dto) async => dto.copyWith( - image: dto.image != null - ? await dto.image!.smallBase64Image - : null, + image: null, // Legacy: card images should be stored in MinIO, not read from disk ), ), ), @@ -158,7 +153,7 @@ class PackDtoConverter { subtitle: model.subtitle, color: model.color, version: model.version, - cover: model.cover != null ? await model.cover!.base64Image : null, + cover: null, // Legacy: covers should be stored in MinIO, not read from disk size: model.size, googlePlayId: model.googlePlayId, rustoreId: model.rustoreId, @@ -173,7 +168,7 @@ class PackDtoConverter { removeCardIds: null, removeTestIds: null, previewCards: model.previewCards - .map((card) => card.id?.toString()) + .map((card) => card.id.toString()) .whereNotNull() .toList(), order: model.order, diff --git a/mnemo_cards_backend/lib/packs/pack_manager.dart b/mnemo_cards_backend/lib/packs/pack_manager.dart index 0e76c3d..2ed2f08 100644 --- a/mnemo_cards_backend/lib/packs/pack_manager.dart +++ b/mnemo_cards_backend/lib/packs/pack_manager.dart @@ -1,14 +1,11 @@ import 'dart:async'; -import 'dart:developer'; import 'dart:io'; -import 'dart:typed_data'; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_backend/database/database.dart'; import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart' hide VoiceModel; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'pack_dto_converter.dart'; -import 'pack_manager_extensions.dart'; import 'card_pack_drift_extension.dart'; @lazySingleton @@ -76,53 +73,6 @@ class PackManager { return await pack.toDto(cards, voices, userModel); } - Future> getPackPreviewImages(String packId) async { - final pack = await getPack(packId); - if (pack == null) { - throw StateError('Pack not found'); - } - - final previewCards = await _db.packDao.getPreviewCards(packId); - final cards = previewCards.isNotEmpty ? previewCards : (await getCards(packId)).take(6).toList(); - - final images = []; - for (final card in previewCards) { - if (card.image.isNotEmpty) { - try { - final image = await card.image.base64Image; - images.add(image); - } catch (e, s) { - log('error while reading image', error: e, stackTrace: s); - } - } - } - - // If we don't have enough preview images, fill with empty strings - while (images.length < 6) { - images.add(''); - } - - return images; - } - - Future> getPackImages(String packId) async { - final cards = await getCards(packId); - final result = {}; - - for (final card in cards) { - if (card.image.isNotEmpty) { - try { - result[card.id.toString()] = - File('${PackManagerUtils.assetsDirectory.path}/cards/${card.image}') - .readAsBytesSync(); - } catch (e, s) { - log('error while reading image', error: e, stackTrace: s); - } - } - } - - return result; - } } // Static utility functions for PackManager diff --git a/mnemo_cards_backend/lib/packs/pack_manager_extensions.dart b/mnemo_cards_backend/lib/packs/pack_manager_extensions.dart deleted file mode 100644 index 5fcc98e..0000000 --- a/mnemo_cards_backend/lib/packs/pack_manager_extensions.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Extensions and utilities for PackManager - -import 'dart:typed_data'; -import 'dart:io'; -import 'dart:convert'; -import 'package:image/image.dart'; -import 'pack_manager.dart'; - -enum _ImageSize { - big, - medium, - small, - extraSmall, -} - -extension on _ImageSize { - int get width => switch (this) { - _ImageSize.big => 1024, - _ImageSize.medium => 512, - _ImageSize.small => 320, - _ImageSize.extraSmall => 192, - }; -} - -extension CoverStringExt on String? { - Future get base64Image => _base64Image(); - - Future _base64Image([_ImageSize? size]) async { - if (this == null) return ''; - try { - final bytes = _getById(this!, 'covers', size); - return base64Encode(bytes); - } catch (e) { - return ''; - } - } - - Uint8List _getById(String id, String type, _ImageSize? size) { - try { - return File('${PackManagerUtils.assetsDirectory.path}/$type/$id') - .readAsBytesSync(); - } catch (e) { - print('Error loading image $id of type $type: $e'); - return Uint8List(0); - } - } - - Future get smallBase64Image => _base64Image(_ImageSize.small); - - Future get extraSmallBase64Image => - _base64Image(_ImageSize.extraSmall); - - Future get mediumBase64Image => _base64Image(_ImageSize.medium); - - Future get bigBase64Image => _base64Image(null); -} \ No newline at end of file diff --git a/mnemo_cards_backend/lib/storage/minio_config.dart b/mnemo_cards_backend/lib/storage/minio_config.dart index 99d1ccc..488bc77 100644 --- a/mnemo_cards_backend/lib/storage/minio_config.dart +++ b/mnemo_cards_backend/lib/storage/minio_config.dart @@ -27,7 +27,7 @@ class MinioConfig { factory MinioConfig.fromEnvironment() { return MinioConfig( endpoint: const String.fromEnvironment( - 'MINIO_ENDPOINT', + 'MINIO_SERVER_URL', defaultValue: 'minio-rsso80cks4ck4oc44s0og80c.147.45.152.129.sslip.io', ), diff --git a/mnemo_cards_web_v2/lib/presentation/pages/pack_details/pack_details_page.dart b/mnemo_cards_web_v2/lib/presentation/pages/pack_details/pack_details_page.dart index 87b9508..d492a1b 100644 --- a/mnemo_cards_web_v2/lib/presentation/pages/pack_details/pack_details_page.dart +++ b/mnemo_cards_web_v2/lib/presentation/pages/pack_details/pack_details_page.dart @@ -823,11 +823,8 @@ class _PackDetailsPageState extends State { /// Изображение карточки (вынесено в отдельный метод для переиспользования) Widget _buildCardImage(GameCardDto card, double width, double height) { - // Use presigned URL from DTO if available, fallback to building URL - final imageUrl = card.imageUrl ?? - (card.image != null && card.image!.isNotEmpty - ? ApiConfigV2.getCardImageUrl(widget.packId, card.id) - : null); + // Use presigned URL from DTO + final imageUrl = card.imageUrl; if (imageUrl == null || imageUrl.isEmpty) { return Center( diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart b/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart index 61c5f3f..0caaf9b 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart @@ -720,11 +720,8 @@ class _CardSide extends StatelessWidget { } Widget _buildImage() { - // Use presigned URL from DTO if available, fallback to building URL - final imageUrl = card.imageUrl ?? - (card.image != null && card.image!.isNotEmpty - ? ApiConfigV2.getCardImageUrl(packId, card.id) - : null); + // Use presigned URL from DTO + final imageUrl = card.imageUrl; if (imageUrl == null || imageUrl.isEmpty) { return Container( diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart b/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart index 953823b..5e7c1f7 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart @@ -565,11 +565,8 @@ class _CardSide extends StatelessWidget { } Widget _buildImage() { - // Use presigned URL from DTO if available, fallback to building URL - final imageUrl = card.imageUrl ?? - (card.image != null && card.image!.isNotEmpty - ? ApiConfigV2.getCardImageUrl(packId, card.id) - : null); + // Use presigned URL from DTO + final imageUrl = card.imageUrl; if (imageUrl == null || imageUrl.isEmpty) { return Container( @@ -603,11 +600,8 @@ class _CardSide extends StatelessWidget { } Widget _buildImageBack() { - // Use presigned URL from DTO if available, fallback to building URL - final imageBackUrl = card.imageBackUrl ?? - (card.imageBack != null && card.imageBack!.isNotEmpty - ? ApiConfigV2.getCardImageBackUrl(packId, card.id) - : null); + // Use presigned URL from DTO + final imageBackUrl = card.imageBackUrl; if (imageBackUrl == null || imageBackUrl.isEmpty) { return Container( diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart b/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart index b10e4da..3a73024 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart @@ -260,11 +260,8 @@ class PackCardItem extends StatelessWidget { /// Отображает изображение карточки /// Загружает изображение с бэкенда по URL Widget _buildImage(BuildContext context, double cardWidth, double cardHeight) { - // Use presigned URL from DTO if available, fallback to building URL - final imageUrl = card.imageUrl ?? - (card.image != null && card.image!.isNotEmpty - ? ApiConfigV2.getCardImageUrl(packId, card.id) - : null); + // Use presigned URL from DTO + final imageUrl = card.imageUrl; if (imageUrl == null || imageUrl.isEmpty) { return const SizedBox.shrink();