11import 'package:core/core.dart' ;
22import 'package:data_repository/data_repository.dart' ;
3- import 'package:flutter_news_app_api_server_full_source_code/src/services/user_preference_limit_service .dart' ;
3+ import 'package:flutter_news_app_api_server_full_source_code/src/services/user_action_limit_service .dart' ;
44import 'package:logging/logging.dart' ;
55
6- /// {@template default_user_preference_limit_service }
7- /// Default implementation of [UserPreferenceLimitService ] that enforces limits
8- /// based on user role and the `InterestConfig` and `UserPreferenceConfig `
6+ /// {@template default_user_action_limit_service }
7+ /// Default implementation of [UserActionLimitService ] that enforces limits
8+ /// based on user role and the `UserLimitsConfig `
99/// sections within the application's [RemoteConfig] .
1010/// {@endtemplate}
11- class DefaultUserPreferenceLimitService implements UserPreferenceLimitService {
12- /// {@macro default_user_preference_limit_service }
13- const DefaultUserPreferenceLimitService ({
11+ class DefaultUserActionLimitService implements UserActionLimitService {
12+ /// {@macro default_user_action_limit_service }
13+ const DefaultUserActionLimitService ({
1414 required DataRepository <RemoteConfig > remoteConfigRepository,
15+ required DataRepository <Engagement > engagementRepository,
16+ required DataRepository <Report > reportRepository,
1517 required Logger log,
1618 }) : _remoteConfigRepository = remoteConfigRepository,
19+ _engagementRepository = engagementRepository,
20+ _reportRepository = reportRepository,
1721 _log = log;
1822
1923 final DataRepository <RemoteConfig > _remoteConfigRepository;
24+ final DataRepository <Engagement > _engagementRepository;
25+ final DataRepository <Report > _reportRepository;
2026 final Logger _log;
2127
2228 // Assuming a fixed ID for the RemoteConfig document
@@ -28,7 +34,7 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService {
2834 required UserContentPreferences updatedPreferences,
2935 }) async {
3036 _log.info (
31- 'Checking all user content preferences limits for user ${user .id }.' ,
37+ 'Checking all user action limits for user ${user .id }.' ,
3238 );
3339 final remoteConfig = await _remoteConfigRepository.read (
3440 id: _remoteConfigId,
@@ -47,6 +53,8 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService {
4753 );
4854
4955 // --- 1. Check general preference limits ---
56+ // Note: The checks for commentsPerDay and reportsPerDay are not performed
57+ // here. They are action-based and enforced by the RateLimitService.
5058 if (updatedPreferences.followedCountries.length > followedItemsLimit) {
5159 _log.warning (
5260 'User ${user .id } exceeded followed countries limit: '
@@ -202,7 +210,7 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService {
202210 SavedFilterLimits savedHeadlineFiltersLimit,
203211 SavedFilterLimits savedSourceFiltersLimit,
204212 )
205- _getLimitsForRole (
213+ _getPreferenceLimitsForRole (
206214 AppUserRole role,
207215 UserLimitsConfig limits,
208216 ) {
@@ -237,4 +245,103 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService {
237245 savedSourceFiltersLimit,
238246 );
239247 }
248+
249+ @override
250+ Future <void > checkEngagementCreationLimit ({
251+ required User user,
252+ required Engagement engagement,
253+ }) async {
254+ _log.info ('Checking engagement creation limits for user ${user .id }.' );
255+ final remoteConfig = await _remoteConfigRepository.read (id: _remoteConfigId);
256+ final limits = remoteConfig.user.limits;
257+
258+ // --- 1. Check Reaction Limit ---
259+ final reactionsLimit = limits.reactionsPerDay[user.appRole];
260+ if (reactionsLimit == null ) {
261+ throw StateError (
262+ 'Reactions per day limit not configured for role: ${user .appRole }' ,
263+ );
264+ }
265+
266+ // Count all engagements in the last 24 hours for the reaction limit.
267+ final twentyFourHoursAgo = DateTime .now ().subtract (const Duration (hours: 24 ));
268+ final reactionCount = await _engagementRepository.count (
269+ filter: {
270+ 'userId' : user.id,
271+ 'createdAt' : {r'$gte' : twentyFourHoursAgo.toIso8601String ()},
272+ },
273+ );
274+
275+ if (reactionCount >= reactionsLimit) {
276+ _log.warning (
277+ 'User ${user .id } exceeded reactions per day limit: $reactionsLimit .' ,
278+ );
279+ throw ForbiddenException (
280+ 'You have reached your daily limit for reactions.' ,
281+ );
282+ }
283+
284+ // --- 2. Check Comment Limit (only if a comment is present) ---
285+ if (engagement.comment != null ) {
286+ final commentsLimit = limits.commentsPerDay[user.appRole];
287+ if (commentsLimit == null ) {
288+ throw StateError (
289+ 'Comments per day limit not configured for role: ${user .appRole }' ,
290+ );
291+ }
292+
293+ // Count engagements with comments in the last 24 hours.
294+ final commentCount = await _engagementRepository.count (
295+ filter: {
296+ 'userId' : user.id,
297+ 'comment' : {r'$exists' : true , r'$ne' : null },
298+ 'createdAt' : {r'$gte' : twentyFourHoursAgo.toIso8601String ()},
299+ },
300+ );
301+
302+ if (commentCount >= commentsLimit) {
303+ _log.warning (
304+ 'User ${user .id } exceeded comments per day limit: $commentsLimit .' ,
305+ );
306+ throw ForbiddenException (
307+ 'You have reached your daily limit for comments.' ,
308+ );
309+ }
310+ }
311+
312+ _log.info (
313+ 'Engagement creation limit checks passed for user ${user .id }.' ,
314+ );
315+ }
316+
317+ @override
318+ Future <void > checkReportCreationLimit ({required User user}) async {
319+ _log.info ('Checking report creation limits for user ${user .id }.' );
320+ final remoteConfig = await _remoteConfigRepository.read (id: _remoteConfigId);
321+ final limits = remoteConfig.user.limits;
322+
323+ final reportsLimit = limits.reportsPerDay[user.appRole];
324+ if (reportsLimit == null ) {
325+ throw StateError (
326+ 'Reports per day limit not configured for role: ${user .appRole }' ,
327+ );
328+ }
329+
330+ final twentyFourHoursAgo = DateTime .now ().subtract (const Duration (hours: 24 ));
331+ final reportCount = await _reportRepository.count (
332+ filter: {
333+ 'reporterUserId' : user.id,
334+ 'createdAt' : {r'$gte' : twentyFourHoursAgo.toIso8601String ()},
335+ },
336+ );
337+
338+ if (reportCount >= reportsLimit) {
339+ _log.warning (
340+ 'User ${user .id } exceeded reports per day limit: $reportsLimit .' ,
341+ );
342+ throw ForbiddenException ('You have reached your daily limit for reports.' );
343+ }
344+
345+ _log.info ('Report creation limit checks passed for user ${user .id }.' );
346+ }
240347}
0 commit comments