diff --git a/lib/src/registry/data_operation_registry.dart b/lib/src/registry/data_operation_registry.dart index c5574e0..a0533a7 100644 --- a/lib/src/registry/data_operation_registry.dart +++ b/lib/src/registry/data_operation_registry.dart @@ -318,6 +318,26 @@ class DataOperationRegistry { ); } + // Business Logic Check: Ensure a user can only have one engagement + // per headline to prevent duplicate reactions or comments. + final engagementRepository = context.read>(); + final existingEngagements = await engagementRepository.readAll( + filter: { + 'userId': authenticatedUser.id, + 'entityId': engagementToCreate.entityId, + 'entityType': engagementToCreate.entityType.name, + }, + ); + + if (existingEngagements.items.isNotEmpty) { + _log.warning( + 'User ${authenticatedUser.id} attempted to create a second engagement for entity ${engagementToCreate.entityId}.', + ); + throw const ConflictException( + 'An engagement for this item already exists.', + ); + } + // Limit Check: Delegate to the centralized service. await userActionLimitService.checkEngagementCreationLimit( user: authenticatedUser, diff --git a/lib/src/services/default_user_action_limit_service.dart b/lib/src/services/default_user_action_limit_service.dart index ca72890..9674eb1 100644 --- a/lib/src/services/default_user_action_limit_service.dart +++ b/lib/src/services/default_user_action_limit_service.dart @@ -265,24 +265,35 @@ class DefaultUserActionLimitService implements UserActionLimitService { ); } - // Count all engagements in the last 24 hours for the reaction limit. - final twentyFourHoursAgo = DateTime.now().subtract( - const Duration(hours: 24), - ); - final reactionCount = await _engagementRepository.count( - filter: { - 'userId': user.id, - 'createdAt': {r'$gte': twentyFourHoursAgo.toIso8601String()}, - }, - ); + // --- 1. Check Reaction Limit (only if a reaction is present) --- + if (engagement.reaction != null) { + final reactionsLimit = limits.reactionsPerDay[user.appRole]; + if (reactionsLimit == null) { + throw StateError( + 'Reactions per day limit not configured for role: ${user.appRole}', + ); + } - if (reactionCount >= reactionsLimit) { - _log.warning( - 'User ${user.id} exceeded reactions per day limit: $reactionsLimit.', + // Count engagements with reactions in the last 24 hours. + final twentyFourHoursAgo = DateTime.now().subtract( + const Duration(hours: 24), ); - throw const ForbiddenException( - 'You have reached your daily limit for reactions.', + final reactionCount = await _engagementRepository.count( + filter: { + 'userId': user.id, + 'reaction': {r'$exists': true, r'$ne': null}, + 'createdAt': {r'$gte': twentyFourHoursAgo.toIso8601String()}, + }, ); + + if (reactionCount >= reactionsLimit) { + _log.warning( + 'User ${user.id} exceeded reactions per day limit: $reactionsLimit.', + ); + throw const ForbiddenException( + 'You have reached your daily limit for reactions.', + ); + } } // --- 2. Check Comment Limit (only if a comment is present) --- @@ -295,6 +306,9 @@ class DefaultUserActionLimitService implements UserActionLimitService { } // Count engagements with comments in the last 24 hours. + final twentyFourHoursAgo = DateTime.now().subtract( + const Duration(hours: 24), + ); final commentCount = await _engagementRepository.count( filter: { 'userId': user.id, diff --git a/pubspec.lock b/pubspec.lock index 6fc6de9..b5fa979 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -181,8 +181,8 @@ packages: dependency: "direct main" description: path: "." - ref: "8bae6eb17369b76f72961870a22ee13d3073fa61" - resolved-ref: "8bae6eb17369b76f72961870a22ee13d3073fa61" + ref: e66e076572bd326e50e9d5286ef5059ff658ed65 + resolved-ref: e66e076572bd326e50e9d5286ef5059ff658ed65 url: "https://github.com/flutter-news-app-full-source-code/core.git" source: git version: "1.3.1" diff --git a/pubspec.yaml b/pubspec.yaml index a8dfd86..951b990 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -62,7 +62,7 @@ dependency_overrides: core: git: url: https://github.com/flutter-news-app-full-source-code/core.git - ref: 8bae6eb17369b76f72961870a22ee13d3073fa61 + ref: e66e076572bd326e50e9d5286ef5059ff658ed65 data_mongodb: git: url: https://github.com/flutter-news-app-full-source-code/data-mongodb.git