From 809bd920dc38b4d76df368581d5c473b89096f9f Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 08:34:38 +0100 Subject: [PATCH 1/8] build(deps): update git dependencies to tagged versions - Update core from commit 828b984 to tag v1.2.0 - Update data-client, data-mongodb, data-repository, email-client, email-repository, and email-sendgrid from specific commits to tag v1.0.0 - Update http-client from commit 57f6bcf to tag v1.0.1 --- pubspec.lock | 34 +++++++++++++++++----------------- pubspec.yaml | 16 ++++++++-------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 21a7955..243c0c3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -117,11 +117,11 @@ packages: dependency: "direct main" description: path: "." - ref: "828b984517edec069266579c624c7af9fbe0e2ac" - resolved-ref: "828b984517edec069266579c624c7af9fbe0e2ac" + ref: "v1.2.0" + resolved-ref: d052799c1ebb7bcdd1a725a2a7919948c14fa001 url: "https://github.com/flutter-news-app-full-source-code/core.git" source: git - version: "0.0.0" + version: "1.2.0" coverage: dependency: transitive description: @@ -158,8 +158,8 @@ packages: dependency: "direct main" description: path: "." - ref: "960a00882045ee252274d9d57bfca606c1fe5d64" - resolved-ref: "960a00882045ee252274d9d57bfca606c1fe5d64" + ref: "v1.0.0" + resolved-ref: b9a8a8c2c660928c22f2d38d657000bcae4c74d6 url: "https://github.com/flutter-news-app-full-source-code/data-client.git" source: git version: "0.0.0" @@ -167,8 +167,8 @@ packages: dependency: "direct main" description: path: "." - ref: ee2ace6243f1ad4710c192c36215d3ce9e91c7a3 - resolved-ref: ee2ace6243f1ad4710c192c36215d3ce9e91c7a3 + ref: "v1.0.0" + resolved-ref: f55b686acdbc0af9c617df4833733a07f9208b57 url: "https://github.com/flutter-news-app-full-source-code/data-mongodb.git" source: git version: "0.0.0" @@ -176,8 +176,8 @@ packages: dependency: "direct main" description: path: "." - ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf - resolved-ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf + ref: "v1.0.0" + resolved-ref: "7f9242d810d60fefd2f883b19e1650e8e4eb41a3" url: "https://github.com/flutter-news-app-full-source-code/data-repository.git" source: git version: "0.0.0" @@ -225,8 +225,8 @@ packages: dependency: "direct main" description: path: "." - ref: c5e36d06b58918056dde4a58d177a39fb66bfe24 - resolved-ref: c5e36d06b58918056dde4a58d177a39fb66bfe24 + ref: "v1.0.0" + resolved-ref: "31faf0e429aeea519204dfdd26afdba36ea1d8dc" url: "https://github.com/flutter-news-app-full-source-code/email-client.git" source: git version: "0.0.0" @@ -234,8 +234,8 @@ packages: dependency: "direct main" description: path: "." - ref: a68acd99c37b844af4eb3ed9f2eb9fd494c57f73 - resolved-ref: a68acd99c37b844af4eb3ed9f2eb9fd494c57f73 + ref: "v1.0.0" + resolved-ref: "2be152f3c48acd35d0a79a01d7258a4e8e8ab399" url: "https://github.com/flutter-news-app-full-source-code/email-repository.git" source: git version: "0.0.0" @@ -243,8 +243,8 @@ packages: dependency: "direct main" description: path: "." - ref: "4cd256b1a65a648db2519d8b26b4e9174d4d3a0c" - resolved-ref: "4cd256b1a65a648db2519d8b26b4e9174d4d3a0c" + ref: "v1.0.0" + resolved-ref: f28572a0c0598348391df7701a205249f2454031 url: "https://github.com/flutter-news-app-full-source-code/email-sendgrid.git" source: git version: "0.0.0" @@ -316,8 +316,8 @@ packages: dependency: "direct main" description: path: "." - ref: "57f6bcfc0f209ecc135fdcb688194045ec87e6e8" - resolved-ref: "57f6bcfc0f209ecc135fdcb688194045ec87e6e8" + ref: "v1.0.1" + resolved-ref: ce550196f78ee2e95aa9e985759179265983689d url: "https://github.com/flutter-news-app-full-source-code/http-client.git" source: git version: "0.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b29a480..ac4d802 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,38 +11,38 @@ dependencies: core: git: url: https://github.com/flutter-news-app-full-source-code/core.git - ref: 828b984517edec069266579c624c7af9fbe0e2ac + ref: v1.2.0 dart_frog: ^1.1.0 dart_jsonwebtoken: ^3.2.0 data_client: git: url: https://github.com/flutter-news-app-full-source-code/data-client.git - ref: 960a00882045ee252274d9d57bfca606c1fe5d64 + ref: v1.0.0 data_mongodb: git: url: https://github.com/flutter-news-app-full-source-code/data-mongodb.git - ref: ee2ace6243f1ad4710c192c36215d3ce9e91c7a3 + ref: v1.0.0 data_repository: git: url: https://github.com/flutter-news-app-full-source-code/data-repository.git - ref: f8f01f1191286efbba41fa2bb369fb16eb652ccf + ref: v1.0.0 dotenv: ^4.2.0 email_client: git: url: https://github.com/flutter-news-app-full-source-code/email-client.git - ref: c5e36d06b58918056dde4a58d177a39fb66bfe24 + ref: v1.0.0 email_repository: git: url: https://github.com/flutter-news-app-full-source-code/email-repository.git - ref: a68acd99c37b844af4eb3ed9f2eb9fd494c57f73 + ref: v1.0.0 email_sendgrid: git: url: https://github.com/flutter-news-app-full-source-code/email-sendgrid.git - ref: 4cd256b1a65a648db2519d8b26b4e9174d4d3a0c + ref: v1.0.0 http_client: git: url: https://github.com/flutter-news-app-full-source-code/http-client.git - ref: 57f6bcfc0f209ecc135fdcb688194045ec87e6e8 + ref: v1.0.1 json_annotation: ^4.9.0 logging: ^1.3.0 meta: ^1.16.0 From 617af8b90fbd4438982348add7d0927d98d6cdb1 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:13:46 +0100 Subject: [PATCH 2/8] fix(auth_service): add savedFilters to default user preferences - Add savedFilters to the list of followedSources, followedTopics, and savedHeadlines in the defaultUserPreferences object - This ensures that new user preferences will have an empty list for savedFilters by default --- lib/src/services/auth_service.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/services/auth_service.dart b/lib/src/services/auth_service.dart index 1dfe650..eb0a751 100644 --- a/lib/src/services/auth_service.dart +++ b/lib/src/services/auth_service.dart @@ -564,6 +564,7 @@ class AuthService { followedSources: const [], followedTopics: const [], savedHeadlines: const [], + savedFilters: const [], ); await _userContentPreferencesRepository.create( item: defaultUserPreferences, From 70432589b5d65142fa4229d17c431748c498b4e8 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:13:56 +0100 Subject: [PATCH 3/8] fix(database): add savedFilters to user_content_preferences - Add savedFilters field to user_content_preferences collection - Initialize savedFilters as an empty list for existing users --- lib/src/services/database_seeding_service.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/services/database_seeding_service.dart b/lib/src/services/database_seeding_service.dart index dd139da..fc89de8 100644 --- a/lib/src/services/database_seeding_service.dart +++ b/lib/src/services/database_seeding_service.dart @@ -362,6 +362,7 @@ class DatabaseSeedingService { followedSources: const [], followedTopics: const [], savedHeadlines: const [], + savedFilters: const [], ); await _db.collection('user_content_preferences').insertOne({ '_id': userId, From 156bac539d74845c2eafa2d22ea88e2eab6fee1d Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:15:15 +0100 Subject: [PATCH 4/8] feat(limits): add saved filters limit check - Implement limit check for saved filters based on user account type - Update existing limit logic to handle country, source, and topic items separately - Add new Premium, Standard, and Guest limits for saved filters --- ...default_user_preference_limit_service.dart | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/src/services/default_user_preference_limit_service.dart b/lib/src/services/default_user_preference_limit_service.dart index b57d0c2..b299cb5 100644 --- a/lib/src/services/default_user_preference_limit_service.dart +++ b/lib/src/services/default_user_preference_limit_service.dart @@ -50,18 +50,28 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService { // 2. Determine the limit based on the user's app role. int limit; String accountType; + final isFollowedItem = + itemType == 'country' || itemType == 'source' || itemType == 'topic'; switch (user.appRole) { case AppUserRole.premiumUser: accountType = 'premium'; - limit = (itemType == 'headline') - ? limits.premiumSavedHeadlinesLimit - : limits.premiumFollowedItemsLimit; + if (isFollowedItem) { + limit = limits.premiumFollowedItemsLimit; + } else if (itemType == 'headline') { + limit = limits.premiumSavedHeadlinesLimit; + } else { + limit = limits.premiumSavedFiltersLimit; + } case AppUserRole.standardUser: accountType = 'standard'; - limit = (itemType == 'headline') - ? limits.authenticatedSavedHeadlinesLimit - : limits.authenticatedFollowedItemsLimit; + if (isFollowedItem) { + limit = limits.authenticatedFollowedItemsLimit; + } else if (itemType == 'headline') { + limit = limits.authenticatedSavedHeadlinesLimit; + } else { + limit = limits.authenticatedSavedFiltersLimit; + } case AppUserRole.guestUser: accountType = 'guest'; limit = (itemType == 'headline') @@ -113,6 +123,7 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService { // 2. Determine limits based on the user's app role. int followedItemsLimit; int savedHeadlinesLimit; + int savedFiltersLimit; String accountType; switch (user.appRole) { @@ -120,14 +131,17 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService { accountType = 'premium'; followedItemsLimit = limits.premiumFollowedItemsLimit; savedHeadlinesLimit = limits.premiumSavedHeadlinesLimit; + savedFiltersLimit = limits.premiumSavedFiltersLimit; case AppUserRole.standardUser: accountType = 'standard'; followedItemsLimit = limits.authenticatedFollowedItemsLimit; savedHeadlinesLimit = limits.authenticatedSavedHeadlinesLimit; + savedFiltersLimit = limits.authenticatedSavedFiltersLimit; case AppUserRole.guestUser: accountType = 'guest'; followedItemsLimit = limits.guestFollowedItemsLimit; savedHeadlinesLimit = limits.guestSavedHeadlinesLimit; + savedFiltersLimit = limits.guestSavedFiltersLimit; } // 3. Check if proposed preferences exceed limits @@ -155,6 +169,12 @@ class DefaultUserPreferenceLimitService implements UserPreferenceLimitService { 'for your account type ($accountType).', ); } + if (updatedPreferences.savedFilters.length > savedFiltersLimit) { + throw ForbiddenException( + 'You have reached the maximum number of saved filters allowed ' + 'for your account type ($accountType).', + ); + } } on HttpException { // Propagate known exceptions from repositories rethrow; From 933af74fd369b74fc0b5d87e40205deb8e37f030 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:15:39 +0100 Subject: [PATCH 5/8] feat(database): add saved filters to user preferences migration - Add new migration class for adding saved filters to user preferences - Update allMigrations list to include the new migration --- lib/src/database/migrations/all_migrations.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/src/database/migrations/all_migrations.dart b/lib/src/database/migrations/all_migrations.dart index 4c5a728..596767a 100644 --- a/lib/src/database/migrations/all_migrations.dart +++ b/lib/src/database/migrations/all_migrations.dart @@ -1,13 +1,15 @@ import 'package:flutter_news_app_api_server_full_source_code/src/database/migration.dart'; import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20250924084800__refactor_ad_config_to_role_based.dart'; +import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart'; import 'package:flutter_news_app_api_server_full_source_code/src/services/database_migration_service.dart' show DatabaseMigrationService; /// A central list of all database migrations to be applied. /// /// New migration classes should be added to this list. The -/// [DatabaseMigrationService] will automatically sort and apply them based on -/// their `prDate` property. +/// [DatabaseMigrationService] will automatically sort and apply them based +/// on their `prDate` property. final List allMigrations = [ RefactorAdConfigToRoleBased(), + AddSavedFiltersToUserPreferences(), ]; From 4e605f00e4d2459a47851d2514541595be54e79c Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:15:52 +0100 Subject: [PATCH 6/8] feat(database): add savedFilters field to user_content_preferences - Create new migration to add 'savedFilters' field to existing user_content_preferences documents - Set default value as an empty array for existing documents - Implement 'up' method to add the field and 'down' method to remove it --- ...add_saved_filters_to_user_preferences.dart | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart diff --git a/lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart b/lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart new file mode 100644 index 0000000..919df74 --- /dev/null +++ b/lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart @@ -0,0 +1,39 @@ +import 'package:flutter_news_app_api_server_full_source_code/src/database/migration.dart'; +import 'package:logging/logging.dart'; +import 'package:mongo_dart/mongo_dart.dart'; + +/// Migration to add the `savedFilters` field to existing +/// `user_content_preferences` documents. +class AddSavedFiltersToUserPreferences extends Migration { + /// {@macro add_saved_filters_to_user_preferences} + AddSavedFiltersToUserPreferences() + : super( + prDate: '20251013000056', + prId: '56', + prSummary: 'Add savedFilters field to user_content_preferences', + ); + + @override + Future up(Db db, Logger log) async { + final collection = db.collection('user_content_preferences'); + final result = await collection.updateMany( + // Filter for documents where 'savedFilters' does not exist. + where.notExists('savedFilters'), + // Set 'savedFilters' to an empty array. + modify.set('savedFilters', []), + ); + log.info( + 'Updated ${result.nModified} documents in user_content_preferences.', + ); + } + + @override + Future down(Db db, Logger log) async { + final collection = db.collection('user_content_preferences'); + await collection.updateMany( + where.exists('savedFilters'), + modify.unset('savedFilters'), + ); + log.info('Removed "savedFilters" field from user_content_preferences.'); + } +} From 2731d770ac6d3d6de3afbef85824e603e31bcf7c Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:30:14 +0100 Subject: [PATCH 7/8] build: add initial version number to pubspec.yaml - Add version 1.0.0 to pubspec.yaml for initial release --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index ac4d802..93e93ed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,6 +2,7 @@ name: flutter_news_app_api_server_full_source_code description: The complete backend API server for the Flutter News App Toolkit, built with Dart Frog. Powers authentication, data management, user settings, and more. repository: https://github.com/flutter-news-app-full-source-code/flutter-news-app-api-server-full-source-code publish_to: none +version: 1.0.0 environment: sdk: ^3.9.0 From 66593c59f03977de466920eac280943fa95b9941 Mon Sep 17 00:00:00 2001 From: fulleni Date: Mon, 13 Oct 2025 09:30:26 +0100 Subject: [PATCH 8/8] chore: add initial CHANGELOG.md for version 1.0.0 release - Create CHANGELOG.md file with initial entry for 1.0.0 release - Add date and description of the initial release under semantic versioning --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e448ae7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# 1.0.0 - 2025-10-13 + +* chore!: initial release under semantic versioning. \ No newline at end of file