From 89d6195aecbb479846f6da28c5dcaa442d70d0f9 Mon Sep 17 00:00:00 2001 From: fulleni Date: Sun, 31 Aug 2025 15:47:36 +0100 Subject: [PATCH 1/9] feat(dependencies): add local ad repository - Implement DataRepository for local ad management - Add localAdRepository to AppDependencies class - Create DataMongodb client for MongoDB operations --- lib/src/config/app_dependencies.dart | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/src/config/app_dependencies.dart b/lib/src/config/app_dependencies.dart index 2667118..76dcff2 100644 --- a/lib/src/config/app_dependencies.dart +++ b/lib/src/config/app_dependencies.dart @@ -59,6 +59,7 @@ class AppDependencies { late final DataRepository userContentPreferencesRepository; late final DataRepository remoteConfigRepository; + late final DataRepository localAdRepository; late final EmailRepository emailRepository; // Services @@ -201,6 +202,16 @@ class AppDependencies { emailRepository = EmailRepository(emailClient: emailClient); + final localAdClient = DataMongodb( + connectionManager: _mongoDbConnectionManager, + modelName: 'local_ads', + fromJson: LocalAd.fromJson, + toJson: LocalAd.toJson, + searchableFields: ['title'], + logger: Logger('DataMongodb'), + ); + localAdRepository = DataRepository(dataClient: localAdClient); + // 5. Initialize Services tokenBlacklistService = MongoDbTokenBlacklistService( connectionManager: _mongoDbConnectionManager, From a2a5e465cf7e3d5b697a5ee80555d33817c38596 Mon Sep 17 00:00:00 2001 From: fulleni Date: Sun, 31 Aug 2025 15:48:26 +0100 Subject: [PATCH 2/9] feat(data): add localAd data operations - Register read, readAll, create, update, and delete operations for LocalAd - Integrate LocalAd operations into existing DataOperationRegistry structure --- lib/src/registry/data_operation_registry.dart | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/src/registry/data_operation_registry.dart b/lib/src/registry/data_operation_registry.dart index 9f45053..19aa7b4 100644 --- a/lib/src/registry/data_operation_registry.dart +++ b/lib/src/registry/data_operation_registry.dart @@ -108,6 +108,8 @@ class DataOperationRegistry { .read(id: id, userId: null), 'remote_config': (c, id) => c.read>().read(id: id, userId: null), + 'localAd': (c, id) => + c.read>().read(id: id, userId: null), 'dashboard_summary': (c, id) => c.read().getSummary(), }); @@ -159,6 +161,12 @@ class DataOperationRegistry { sort: s, pagination: p, ), + 'localAd': (c, uid, f, s, p) => c.read>().readAll( + userId: uid, + filter: f, + sort: s, + pagination: p, + ), }); // --- Register Item Creators --- @@ -186,6 +194,10 @@ class DataOperationRegistry { 'remote_config': (c, item, uid) => c .read>() .create(item: item as RemoteConfig, userId: uid), + 'localAd': (c, item, uid) => c.read>().create( + item: item as LocalAd, + userId: uid, + ), }); // --- Register Item Updaters --- @@ -228,6 +240,11 @@ class DataOperationRegistry { 'remote_config': (c, id, item, uid) => c .read>() .update(id: id, item: item as RemoteConfig, userId: uid), + 'localAd': (c, id, item, uid) => c.read>().update( + id: id, + item: item as LocalAd, + userId: uid, + ), }); // --- Register Item Deleters --- @@ -251,6 +268,8 @@ class DataOperationRegistry { .delete(id: id, userId: uid), 'remote_config': (c, id, uid) => c.read>().delete(id: id, userId: uid), + 'localAd': (c, id, uid) => + c.read>().delete(id: id, userId: uid), }); } } From 677e85fed3d59dc3748833296cca1518d36e735b Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:32:59 +0100 Subject: [PATCH 3/9] feat(rbac): add local ad permissions - Add create, read, update, and delete permissions for local ads - New permissions are included in the Permissions abstract class --- lib/src/rbac/permissions.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/rbac/permissions.dart b/lib/src/rbac/permissions.dart index 33821ee..abc3b15 100644 --- a/lib/src/rbac/permissions.dart +++ b/lib/src/rbac/permissions.dart @@ -68,6 +68,12 @@ abstract class Permissions { static const String userPreferenceBypassLimits = 'user_preference.bypass_limits'; + // Local Ad Permissions + static const String localAdCreate = 'localAd.create'; + static const String localAdRead = 'localAd.read'; + static const String localAdUpdate = 'localAd.update'; + static const String localAdDelete = 'localAd.delete'; + // General System Permissions static const String rateLimitingBypass = 'rate_limiting.bypass'; } From b38cc4a8660c0b79c9163bdc091ac523a0d60d75 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:33:22 +0100 Subject: [PATCH 4/9] feat(rbac): add localAd permissions for guest and admin users - Add localAd read permission for app guest users - Add localAd CRUD permissions for dashboard admin users --- lib/src/rbac/role_permissions.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/src/rbac/role_permissions.dart b/lib/src/rbac/role_permissions.dart index ec892c1..a6660ef 100644 --- a/lib/src/rbac/role_permissions.dart +++ b/lib/src/rbac/role_permissions.dart @@ -14,6 +14,7 @@ final Set _appGuestUserPermissions = { Permissions.userContentPreferencesReadOwned, Permissions.userContentPreferencesUpdateOwned, Permissions.remoteConfigRead, + Permissions.localAdRead, // Allows a user to update their own User object. This is essential for // features like updating the `feedActionStatus` (e.g., when a user // dismisses an in-feed prompt, etc). The endpoint handler ensures only @@ -72,6 +73,11 @@ final Set _dashboardAdminPermissions = { Permissions.remoteConfigUpdate, Permissions.remoteConfigDelete, Permissions.userPreferenceBypassLimits, + // Added localAd CRUD permissions for admins + Permissions.localAdCreate, + Permissions.localAdRead, + Permissions.localAdUpdate, + Permissions.localAdDelete, }; /// Defines the mapping between user roles (both app and dashboard) and the From 41163eaf1e07df47db91eea9f2080ef92d3b3e64 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:33:39 +0100 Subject: [PATCH 5/9] feat(registry): add LocalAd model to registry - Add LocalAd model with appropriate permissions to modelRegistry - Set up permissions for reading, creating, updating, and deleting local ads - Define local_ad as a global resource with no owner --- lib/src/registry/model_registry.dart | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/src/registry/model_registry.dart b/lib/src/registry/model_registry.dart index 427e257..645c870 100644 --- a/lib/src/registry/model_registry.dart +++ b/lib/src/registry/model_registry.dart @@ -362,6 +362,31 @@ final modelRegistry = >{ type: RequiredPermissionType.unsupported, ), ), + 'local_ad': ModelConfig( + fromJson: LocalAd.fromJson, + getId: (ad) => (ad as dynamic).id as String, // Corrected to access id + getOwnerId: null, // LocalAd is a global resource, not user-owned + getCollectionPermission: const ModelActionPermission( + type: RequiredPermissionType.specificPermission, + permission: Permissions.localAdRead, + ), + getItemPermission: const ModelActionPermission( + type: RequiredPermissionType.specificPermission, + permission: Permissions.localAdRead, + ), + postPermission: const ModelActionPermission( + type: RequiredPermissionType.adminOnly, + permission: Permissions.localAdCreate, + ), + putPermission: const ModelActionPermission( + type: RequiredPermissionType.adminOnly, + permission: Permissions.localAdUpdate, + ), + deletePermission: const ModelActionPermission( + type: RequiredPermissionType.adminOnly, + permission: Permissions.localAdDelete, + ), + ), }; /// Type alias for the ModelRegistry map for easier provider usage. From c52d0be571ac01ac7f6f4b32ff318a4fbcc77b20 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:33:57 +0100 Subject: [PATCH 6/9] refactor(data): rename 'localAd' to 'local_ad' in data operation registry - Update 'localAd' to 'local_ad' in all relevant method registrations - Adjust method calls to use the new 'local_ad' key - Improve consistency in naming convention within the registry --- lib/src/registry/data_operation_registry.dart | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/src/registry/data_operation_registry.dart b/lib/src/registry/data_operation_registry.dart index 19aa7b4..c8cb253 100644 --- a/lib/src/registry/data_operation_registry.dart +++ b/lib/src/registry/data_operation_registry.dart @@ -108,7 +108,7 @@ class DataOperationRegistry { .read(id: id, userId: null), 'remote_config': (c, id) => c.read>().read(id: id, userId: null), - 'localAd': (c, id) => + 'local_ad': (c, id) => c.read>().read(id: id, userId: null), 'dashboard_summary': (c, id) => c.read().getSummary(), @@ -161,12 +161,9 @@ class DataOperationRegistry { sort: s, pagination: p, ), - 'localAd': (c, uid, f, s, p) => c.read>().readAll( - userId: uid, - filter: f, - sort: s, - pagination: p, - ), + 'local_ad': (c, uid, f, s, p) => c + .read>() + .readAll(userId: uid, filter: f, sort: s, pagination: p), }); // --- Register Item Creators --- @@ -194,7 +191,7 @@ class DataOperationRegistry { 'remote_config': (c, item, uid) => c .read>() .create(item: item as RemoteConfig, userId: uid), - 'localAd': (c, item, uid) => c.read>().create( + 'local_ad': (c, item, uid) => c.read>().create( item: item as LocalAd, userId: uid, ), @@ -240,11 +237,9 @@ class DataOperationRegistry { 'remote_config': (c, id, item, uid) => c .read>() .update(id: id, item: item as RemoteConfig, userId: uid), - 'localAd': (c, id, item, uid) => c.read>().update( - id: id, - item: item as LocalAd, - userId: uid, - ), + 'local_ad': (c, id, item, uid) => c + .read>() + .update(id: id, item: item as LocalAd, userId: uid), }); // --- Register Item Deleters --- @@ -268,7 +263,7 @@ class DataOperationRegistry { .delete(id: id, userId: uid), 'remote_config': (c, id, uid) => c.read>().delete(id: id, userId: uid), - 'localAd': (c, id, uid) => + 'local_ad': (c, id, uid) => c.read>().delete(id: id, userId: uid), }); } From d19ce2cd23d38ef6b4f5faca0af4c0bee108c6a0 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:34:25 +0100 Subject: [PATCH 7/9] feat(database): add local ads collection seeding and indexing - Implement seeding for local ads collection - Add index on 'adType' field for efficient querying - Include necessary imports and fixtures for local ads --- lib/src/services/database_seeding_service.dart | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/src/services/database_seeding_service.dart b/lib/src/services/database_seeding_service.dart index 1c4636b..8a8d14f 100644 --- a/lib/src/services/database_seeding_service.dart +++ b/lib/src/services/database_seeding_service.dart @@ -45,6 +45,13 @@ class DatabaseSeedingService { getId: (item) => item.id, toJson: (item) => item.toJson(), ); + await _seedCollection( + collectionName: 'local_ads', + fixtureData: localAdsFixturesData, + getId: (item) => (item as dynamic).id as String, + // ignore: unnecessary_lambdas + toJson: (item) => LocalAd.toJson(item), + ); _log.info('Database seeding process completed.'); } @@ -131,6 +138,13 @@ class DatabaseSeedingService { .collection('countries') .createIndex(keys: {'name': 1}, name: 'countries_name_index'); + /// Index for searching local ads by adType. + /// This index supports efficient queries and filtering on the 'adType' field + /// of local ad documents. + await _db + .collection('local_ads') + .createIndex(keys: {'adType': 1}, name: 'local_ads_adType_index'); + // --- TTL and Unique Indexes via runCommand --- // The following indexes are created using the generic `runCommand` because // they require specific options not exposed by the simpler `createIndex` From 0a279a07e330cfdbcf8fa79bf949e0878259f508 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:34:34 +0100 Subject: [PATCH 8/9] feat(routes): add dependency injection for local ad repository - Add provider for DataRepository in middleware - Inject localAdRepository using deps.localAdRepository --- routes/_middleware.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/routes/_middleware.dart b/routes/_middleware.dart index 51acc21..e21a84c 100644 --- a/routes/_middleware.dart +++ b/routes/_middleware.dart @@ -127,6 +127,11 @@ Handler middleware(Handler handler) { (_) => deps.remoteConfigRepository, ), ) + .use( + provider>( + (_) => deps.localAdRepository, + ), + ) .use(provider((_) => deps.emailRepository)) .use( provider( From ea11a392c12a8d76750fe4fe16a7fbba2b47ae1d Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 1 Sep 2025 06:53:05 +0100 Subject: [PATCH 9/9] feat(routes): add dependency injection for local ad repository - Add provider for DataRepository in middleware - Inject localAdRepository using deps.localAdRepository --- lib/src/rbac/permissions.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/rbac/permissions.dart b/lib/src/rbac/permissions.dart index abc3b15..8bd383f 100644 --- a/lib/src/rbac/permissions.dart +++ b/lib/src/rbac/permissions.dart @@ -69,10 +69,10 @@ abstract class Permissions { 'user_preference.bypass_limits'; // Local Ad Permissions - static const String localAdCreate = 'localAd.create'; - static const String localAdRead = 'localAd.read'; - static const String localAdUpdate = 'localAd.update'; - static const String localAdDelete = 'localAd.delete'; + static const String localAdCreate = 'local_ad.create'; + static const String localAdRead = 'local_ad.read'; + static const String localAdUpdate = 'local_ad.update'; + static const String localAdDelete = 'local_ad.delete'; // General System Permissions static const String rateLimitingBypass = 'rate_limiting.bypass';