product availability
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
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
This commit is contained in:
parent
efe1a8f898
commit
b5f6a78845
1 changed files with 206 additions and 0 deletions
206
mnemo_cards_backend/lib/packs/product_availability_manager.dart
Normal file
206
mnemo_cards_backend/lib/packs/product_availability_manager.dart
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
import 'dart:developer';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:mnemo_cards_backend/database/database.dart';
|
||||
import 'package:mnemo_cards_backend/packs/pack_manager.dart';
|
||||
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart';
|
||||
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
||||
|
||||
/// Менеджер для проверки доступности и управления доступом к продуктам (пакам, подпискам) пользователю
|
||||
@lazySingleton
|
||||
class ProductAvailabilityManager {
|
||||
final PackManager _packManager;
|
||||
final AppDatabase _db;
|
||||
final Set<String> _publicPackIds;
|
||||
|
||||
ProductAvailabilityManager(
|
||||
this._packManager,
|
||||
this._db, {
|
||||
Set<String>? publicPackIds,
|
||||
}) : _publicPackIds = publicPackIds ?? const {'10'};
|
||||
|
||||
/// Проверить доступность пакета для пользователя
|
||||
///
|
||||
/// Возвращает true, если пакет доступен пользователю по одной из причин:
|
||||
/// - Пакет является публичным (в списке publicPackIds)
|
||||
/// - Пользователь является администратором
|
||||
/// - У пользователя есть прямой доступ к пакету (через user_packs)
|
||||
/// - У пользователя есть активная подписка с фичей SubscriptionFeatureEnum.packs
|
||||
///
|
||||
/// Параметры:
|
||||
/// - [packId] - ID пакета для проверки
|
||||
/// - [user] - пользователь (может быть null для неавторизованных)
|
||||
///
|
||||
/// Возвращает:
|
||||
/// - true если пакет доступен
|
||||
/// - false если пакет недоступен или не существует
|
||||
Future<bool> isPackAvailable({
|
||||
required String packId,
|
||||
required UserModel? user,
|
||||
}) async {
|
||||
// Проверить существование и статус пакета
|
||||
final pack = await _packManager.getPack(packId);
|
||||
if (pack == null || !pack.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Публичные паки доступны всем
|
||||
if (_publicPackIds.contains(packId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Администраторы имеют доступ ко всем пакетам
|
||||
if (user?.admin == true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Для неавторизованных пользователей доступны только публичные паки
|
||||
if (user == null || user.id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Проверить прямой доступ через user_packs
|
||||
final hasDirectAccess = await _db.userDao.hasPackAccess(user.id!, packId);
|
||||
if (hasDirectAccess) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Проверить доступ через подписку
|
||||
if (user.subscriptionModel != null && user.subscriptionModel!.isActive) {
|
||||
final hasSubscriptionAccess = user.subscriptionModel!.features.contains(
|
||||
SubscriptionFeatureEnum.packs,
|
||||
);
|
||||
if (hasSubscriptionAccess) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Проверить доступность продукта для пользователя
|
||||
///
|
||||
/// Универсальный метод для проверки доступности любого типа продукта
|
||||
///
|
||||
/// Параметры:
|
||||
/// - [productId] - ID продукта
|
||||
/// - [productType] - тип продукта (pack, subscription)
|
||||
/// - [user] - пользователь (может быть null для неавторизованных)
|
||||
///
|
||||
/// Возвращает:
|
||||
/// - true если продукт доступен
|
||||
/// - false если продукт недоступен
|
||||
Future<bool> isProductAvailable({
|
||||
required String productId,
|
||||
required MnemoCardsProductType productType,
|
||||
required UserModel? user,
|
||||
}) async {
|
||||
switch (productType) {
|
||||
case MnemoCardsProductType.pack:
|
||||
return await isPackAvailable(packId: productId, user: user);
|
||||
case MnemoCardsProductType.subscription:
|
||||
// Подписки не проверяются на доступность, они являются продуктами для покупки
|
||||
// Но можно проверить, есть ли у пользователя уже активная подписка
|
||||
if (user?.subscriptionModel != null &&
|
||||
user!.subscriptionModel!.isActive) {
|
||||
// Пользователь уже имеет активную подписку
|
||||
// В зависимости от бизнес-логики, можно вернуть true или false
|
||||
return false; // По умолчанию, если есть активная подписка, покупка новой недоступна
|
||||
}
|
||||
return true; // Подписка доступна для покупки
|
||||
case MnemoCardsProductType.discount:
|
||||
case MnemoCardsProductType.game:
|
||||
case MnemoCardsProductType.unknown:
|
||||
// Для discount, game и unknown типов проверка доступности не применима
|
||||
// Они являются продуктами для покупки или служебными типами
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Проверить, является ли пакет публичным
|
||||
bool isPublicPack(String packId) {
|
||||
return _publicPackIds.contains(packId);
|
||||
}
|
||||
|
||||
/// Получить список публичных пакетов
|
||||
Set<String> get publicPackIds => _publicPackIds;
|
||||
|
||||
/// Предоставить пользователю доступ к пакету
|
||||
///
|
||||
/// Параметры:
|
||||
/// - [userId] - ID пользователя
|
||||
/// - [packId] - ID пакета
|
||||
/// - [grantType] - тип предоставления доступа ('purchase', 'promo_code', 'free' и т.д.)
|
||||
///
|
||||
/// Метод автоматически проверяет существование пакета перед предоставлением доступа.
|
||||
/// Если пакет не существует или отключен, выбрасывается исключение.
|
||||
Future<void> grantPackAccess({
|
||||
required String userId,
|
||||
required String packId,
|
||||
String grantType = 'purchase',
|
||||
}) async {
|
||||
// Проверить существование и статус пакета
|
||||
final pack = await _packManager.getPack(packId);
|
||||
if (pack == null) {
|
||||
throw ArgumentError('Pack not found: $packId');
|
||||
}
|
||||
if (!pack.enabled) {
|
||||
throw ArgumentError('Pack is disabled: $packId');
|
||||
}
|
||||
|
||||
await _db.userDao.grantPackAccess(
|
||||
userId: userId,
|
||||
packId: packId,
|
||||
grantType: grantType,
|
||||
);
|
||||
log('Granted access to pack $packId for user $userId (type: $grantType)');
|
||||
}
|
||||
|
||||
/// Отозвать доступ пользователя к пакету
|
||||
///
|
||||
/// Параметры:
|
||||
/// - [userId] - ID пользователя
|
||||
/// - [packId] - ID пакета
|
||||
Future<void> revokePackAccess({
|
||||
required String userId,
|
||||
required String packId,
|
||||
}) async {
|
||||
await _db.userDao.revokePackAccess(userId, packId);
|
||||
log('Revoked access to pack $packId for user $userId');
|
||||
}
|
||||
|
||||
/// Предоставить пользователю доступ к продукту
|
||||
///
|
||||
/// Универсальный метод для предоставления доступа к любому типу продукта
|
||||
///
|
||||
/// Параметры:
|
||||
/// - [userId] - ID пользователя
|
||||
/// - [product] - продукт (DTO)
|
||||
/// - [grantType] - тип предоставления доступа
|
||||
Future<void> grantProductAccess({
|
||||
required String userId,
|
||||
required MnemoCardsProductDto product,
|
||||
String grantType = 'purchase',
|
||||
}) async {
|
||||
switch (product.type) {
|
||||
case MnemoCardsProductType.pack:
|
||||
if (product.id == null) {
|
||||
throw ArgumentError('Product ID is required for pack');
|
||||
}
|
||||
await grantPackAccess(
|
||||
userId: userId,
|
||||
packId: product.id!,
|
||||
grantType: grantType,
|
||||
);
|
||||
break;
|
||||
case MnemoCardsProductType.subscription:
|
||||
case MnemoCardsProductType.discount:
|
||||
case MnemoCardsProductType.game:
|
||||
case MnemoCardsProductType.unknown:
|
||||
// Для этих типов продуктов логика предоставления доступа находится в других менеджерах
|
||||
// (например, SubscriptionManager для подписок)
|
||||
throw ArgumentError(
|
||||
'Granting access for product type ${product.type} is not supported by ProductAvailabilityManager',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue