mnemo_cards/mnemo_cards_backend/lib/packs/pack_dto_converter.dart

223 lines
6.9 KiB
Dart
Raw Normal View History

2025-11-16 11:25:27 +00:00
import 'package:injectable/injectable.dart';
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_common/mnemo_cards_common.dart';
import 'products_price_resolver.dart';
2025-12-13 20:55:50 +00:00
bool canOpenForAd(String? id) => id != null;
2025-11-16 11:25:27 +00:00
@LazySingleton()
class PackDtoConverter {
final ProductsPriceResolver _productsPriceResolver;
final AdsManager _adsManager;
2025-12-20 18:26:15 +00:00
const PackDtoConverter(this._productsPriceResolver, this._adsManager);
2025-11-16 11:25:27 +00:00
Future<CardPackPreviewDto> toCardPackPreviewDto(
CardPackModel model,
UserModel? userModel,
) async {
2026-01-08 16:58:13 +00:00
bool available =
userModel != null &&
(userModel.packs.contains(model.id?.toString()) || userModel.admin);
2025-11-16 11:25:27 +00:00
if (userModel != null && !available) {
2025-12-20 18:26:15 +00:00
available =
userModel.subscriptionModel?.features.contains(
SubscriptionFeatureEnum.packs,
) ==
2025-11-16 11:25:27 +00:00
true;
}
String? price = model.price;
if (userModel != null && !available) {
price = await _productsPriceResolver.userPackPrice(userModel, model);
}
final canOpenForAdVal = !available && canOpenForAd(model.id);
2025-12-20 19:27:32 +00:00
// Generate cover image URL
String? coverUrl;
if (model.cover != null && model.cover!.isNotEmpty) {
final coverValue = model.cover!.trim();
2026-01-08 13:02:47 +00:00
2025-12-20 19:27:32 +00:00
// If it's already a remote URL, use it directly
2026-01-08 13:02:47 +00:00
if (coverValue.startsWith('http://') ||
coverValue.startsWith('https://')) {
2025-12-20 19:27:32 +00:00
coverUrl = coverValue;
}
// If it's a UUID or any other value, use API endpoint
else if (coverValue.isNotEmpty) {
coverUrl = '/api/v2/packs/${model.id.toString()}/cover';
}
}
2025-11-16 11:25:27 +00:00
return CardPackPreviewDto(
id: model.id.toString(),
title: model.title,
subtitle: model.subtitle,
cards: model.cards.length,
tests: model.tests.length,
price: price,
2025-12-20 19:27:32 +00:00
imageUrl: coverUrl,
2025-11-16 11:25:27 +00:00
color: model.color,
isAvailable: available,
// trail: 'asset:icons/gift.png',
tip: available
? null
: canOpenForAdVal
2025-12-20 18:26:15 +00:00
? AssetPackTip('icons/ad.webp', position: PackTipPosition.bottomRight)
: AssetPackTip(
'icons/lock.webp',
position: PackTipPosition.bottomRight,
),
2025-11-16 11:25:27 +00:00
version: model.version,
);
}
Future<CardPackBuyDto> toCardPackBuyDto(
CardPackModel model,
UserModel? userModel,
) async {
final price = userModel == null
? model.price
: await _productsPriceResolver.userPackPrice(userModel, model);
final canOpenForAdVal = userModel != null && canOpenForAd(model.id);
String? _adsKey;
if (canOpenForAdVal) {
_adsKey = _adsManager.getAdsKey([model], userModel);
}
return CardPackBuyDto(
id: model.id.toString(),
title: model.title,
subtitle: model.subtitle,
appStoreId: model.appStoreId,
rustoreId: model.rustoreId,
googlePlayId: model.googlePlayId,
cards: await Future.wait(
(model.previewCards.isNotEmpty
? model.previewCards
: model.cards.take(3))
.toDtosList(model.cardsOrder)
.map(
(dto) async => dto.copyWith(
2025-12-20 18:26:15 +00:00
image:
null, // Legacy: card images should be stored in MinIO, not read from disk
2025-11-16 11:25:27 +00:00
),
),
),
items: [
2025-12-20 18:26:15 +00:00
if (model.description != null) TextItem(title: model.description),
2025-11-16 11:25:27 +00:00
if (_adsKey == null) ...[
SpacerItem(),
TextItem(
subtitle: 'Открыть все темы с подпиской!',
deeplink: SubscriptionOpenDeeplink().uri.toString(),
),
],
if (_adsKey != null) ...[
SpacerItem(),
TextItem(
subtitle: 'Эту тему можно открыть, посмотрев рекламу',
deeplink: ProductForAdDeeplink(
model.toDto(),
_adsKey,
).uri.toString(),
),
],
2025-12-20 18:26:15 +00:00
SpacerItem(flex: 0, height: 10),
2025-11-16 11:25:27 +00:00
if (_adsKey == null) ...[
TextItem(
subtitle: 'Оплатить российской картой',
deeplink: PurchaseInitDeeplink(
id: model.id.toString(),
productType: MnemoCardsProductType.pack,
paymentId: model.id.toString(),
paymentSystem: PaymentSystem.yookassa,
).uri.toString(),
),
],
2025-12-20 18:26:15 +00:00
SpacerItem(height: 20, flex: 0),
2025-11-16 11:25:27 +00:00
],
color: model.color,
version: model.version,
price: price,
);
}
Future<EditCardPackDto> toEditDto(
CardPackModel model, {
bool withCards = true,
bool withTests = false,
bool withUsers = false,
}) async {
return EditCardPackDto(
id: model.id.toString(),
title: model.title,
subtitle: model.subtitle,
color: model.color,
version: model.version,
2025-12-20 18:26:15 +00:00
cover:
null, // Legacy: covers should be stored in MinIO, not read from disk
2025-11-16 11:25:27 +00:00
size: model.size,
googlePlayId: model.googlePlayId,
rustoreId: model.rustoreId,
appStoreId: model.appStoreId,
price: model.price,
description: model.description,
enabled: model.enabled,
2025-12-20 18:26:15 +00:00
addCardIds: withCards
? model.cards.map((c) => c.id.toString()).toList()
: null,
addTestIds: withTests
? model.tests.map((t) => t.id.toString()).toList()
: null,
2025-11-16 11:25:27 +00:00
removeCardIds: null,
removeTestIds: null,
previewCards: model.previewCards
2025-12-19 01:09:04 +00:00
.map((card) => card.id.toString())
2025-11-16 11:25:27 +00:00
.whereNotNull()
.toList(),
order: model.order,
cardsOrder: model.cardsOrder,
);
}
CardPackDto toDto(CardPackModel model) {
return CardPackDto(
id: model.id.toString(),
title: model.title,
subtitle: model.subtitle,
cards: model.cards.toDtosList(model.cardsOrder),
color: model.color,
version: model.version,
);
}
CardPackModel toModel(EditCardPackDto dto, CardPackModel? model) {
return CardPackModel(
title: dto.title ?? model?.title ?? '',
subtitle: dto.subtitle ?? model?.subtitle ?? '',
size: dto.size ?? model?.size ?? 0,
color: dto.color ?? model?.color,
cover: dto.cover ?? model?.cover,
description: dto.description ?? model?.description,
version: dto.version ?? model?.version,
2025-12-13 20:55:50 +00:00
id: model?.id ?? dto.id,
2025-11-16 11:25:27 +00:00
googlePlayId: dto.googlePlayId ?? model?.googlePlayId,
rustoreId: dto.rustoreId ?? model?.rustoreId,
appStoreId: dto.appStoreId ?? model?.appStoreId,
price: dto.price ?? model?.price,
enabled: dto.enabled ?? model?.enabled ?? false,
order: dto.order ?? model?.order ?? 0,
cardsOrder: dto.cardsOrder ?? model?.cardsOrder ?? const [],
2026-01-08 16:07:56 +00:00
currency: model?.currency ?? 'RUB',
2025-11-16 11:25:27 +00:00
);
}
}