From 4b75cad501c1940d07f1289a59174fc47215ddc0 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 13 Nov 2025 07:50:29 +0100 Subject: [PATCH] chore: drop all stale migrations --- ...800__refactor_ad_config_to_role_based.dart | 160 ------------------ ...add_saved_filters_to_user_preferences.dart | 40 ----- ...57_add_saved_filters_to_remote_config.dart | 52 ------ ...0251024000000_add_logo_url_to_sources.dart | 66 -------- ...251103073226_remove_local_ad_platform.dart | 65 ------- ...07000000_add_is_breaking_to_headlines.dart | 51 ------ ..._notification_config_to_remote_config.dart | 62 ------- ...or_user_preferences_and_remote_config.dart | 160 ------------------ .../database/migrations/all_migrations.dart | 19 +-- 9 files changed, 1 insertion(+), 674 deletions(-) delete mode 100644 lib/src/database/migrations/20250924084800__refactor_ad_config_to_role_based.dart delete mode 100644 lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart delete mode 100644 lib/src/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart delete mode 100644 lib/src/database/migrations/20251024000000_add_logo_url_to_sources.dart delete mode 100644 lib/src/database/migrations/20251103073226_remove_local_ad_platform.dart delete mode 100644 lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart delete mode 100644 lib/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart delete mode 100644 lib/src/database/migrations/20251112000000_refactor_user_preferences_and_remote_config.dart diff --git a/lib/src/database/migrations/20250924084800__refactor_ad_config_to_role_based.dart b/lib/src/database/migrations/20250924084800__refactor_ad_config_to_role_based.dart deleted file mode 100644 index 6edf33e..0000000 --- a/lib/src/database/migrations/20250924084800__refactor_ad_config_to_role_based.dart +++ /dev/null @@ -1,160 +0,0 @@ -// ignore_for_file: comment_references - -import 'package:core/core.dart'; -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'; - -/// {@template refactor_ad_config_to_role_based} -/// A comprehensive migration to refactor the `adConfig` structure within -/// `RemoteConfig` documents to a new role-based `visibleTo` map approach. -/// -/// This migration addresses significant changes introduced by a PR (see -/// [gitHubPullRequest]) that aimed to enhance flexibility and maintainability -/// of ad configurations. It transforms old, role-specific ad frequency and -/// placement fields into new `visibleTo` maps for `FeedAdConfiguration`, -/// `ArticleAdConfiguration`, and `InterstitialAdConfiguration`. -/// -/// The migration ensures that existing `RemoteConfig` documents are updated -/// to conform to the latest model structure, preventing deserialization errors -/// and enabling granular control over ad display for different user roles. -/// {@endtemplate} -class RefactorAdConfigToRoleBased extends Migration { - /// {@macro refactor_ad_config_to_role_based} - RefactorAdConfigToRoleBased() - : super( - prDate: '20250924084800', - prSummary: 'Refactor adConfig to use role-based visibleTo maps', - prId: '50', - ); - - @override - Future up(Db db, Logger log) async { - log.info( - 'Applying migration PR#$prId (Date: $prDate): $prSummary.', - ); - - final remoteConfigCollection = db.collection('remote_configs'); - - // Define default FeedAdFrequencyConfig for roles - const defaultGuestFeedAdFrequency = FeedAdFrequencyConfig( - adFrequency: 5, - adPlacementInterval: 3, - ); - const defaultStandardUserFeedAdFrequency = FeedAdFrequencyConfig( - adFrequency: 10, - adPlacementInterval: 5, - ); - // Define default InterstitialAdFrequencyConfig for roles - const defaultGuestInterstitialAdFrequency = InterstitialAdFrequencyConfig( - transitionsBeforeShowingInterstitialAds: 5, - ); - const defaultStandardUserInterstitialAdFrequency = - InterstitialAdFrequencyConfig( - transitionsBeforeShowingInterstitialAds: 10, - ); - - // Define default ArticleAdSlot visibility for roles - final defaultArticleAdSlots = { - InArticleAdSlotType.aboveArticleContinueReadingButton.name: true, - InArticleAdSlotType.belowArticleContinueReadingButton.name: true, - }; - - final result = await remoteConfigCollection.updateMany( - // Find documents that still have the old structure (e.g., old frequency fields) - where.exists( - 'adConfig.feedAdConfiguration.frequencyConfig.guestAdFrequency', - ), - ModifierBuilder() - // --- FeedAdConfiguration Transformation --- - // Remove old frequencyConfig fields - ..unset('adConfig.feedAdConfiguration.frequencyConfig.guestAdFrequency') - ..unset( - 'adConfig.feedAdConfiguration.frequencyConfig.guestAdPlacementInterval', - ) - ..unset( - 'adConfig.feedAdConfiguration.frequencyConfig.authenticatedAdFrequency', - ) - ..unset( - 'adConfig.feedAdConfiguration.frequencyConfig.authenticatedAdPlacementInterval', - ) - ..unset( - 'adConfig.feedAdConfiguration.frequencyConfig.premiumAdFrequency', - ) - ..unset( - 'adConfig.feedAdConfiguration.frequencyConfig.premiumAdPlacementInterval', - ) - // Set the new visibleTo map for FeedAdConfiguration - ..set( - 'adConfig.feedAdConfiguration.visibleTo', - { - AppUserRole.guestUser.name: defaultGuestFeedAdFrequency.toJson(), - AppUserRole.standardUser.name: defaultStandardUserFeedAdFrequency - .toJson(), - }, - ) - // --- ArticleAdConfiguration Transformation --- - // Remove old inArticleAdSlotConfigurations list - ..unset('adConfig.articleAdConfiguration.inArticleAdSlotConfigurations') - // Set the new visibleTo map for ArticleAdConfiguration - ..set( - 'adConfig.articleAdConfiguration.visibleTo', - { - AppUserRole.guestUser.name: defaultArticleAdSlots, - AppUserRole.standardUser.name: defaultArticleAdSlots, - }, - ) - // --- InterstitialAdConfiguration Transformation --- - // Remove old feedInterstitialAdFrequencyConfig fields - ..unset( - 'adConfig.interstitialAdConfiguration.feedInterstitialAdFrequencyConfig.guestTransitionsBeforeShowingInterstitialAds', - ) - ..unset( - 'adConfig.interstitialAdConfiguration.feedInterstitialAdFrequencyConfig.standardUserTransitionsBeforeShowingInterstitialAds', - ) - ..unset( - 'adConfig.interstitialAdConfiguration.feedInterstitialAdFrequencyConfig.premiumUserTransitionsBeforeShowingInterstitialAds', - ) - // Set the new visibleTo map for InterstitialAdConfiguration - ..set( - 'adConfig.interstitialAdConfiguration.visibleTo', - { - AppUserRole.guestUser.name: defaultGuestInterstitialAdFrequency - .toJson(), - AppUserRole.standardUser.name: - defaultStandardUserInterstitialAdFrequency.toJson(), - }, - ), - ); - - log.info( - 'Updated ${result.nModified} remote_config documents ' - 'to new role-based adConfig structure.', - ); - } - - @override - Future down(Db db, Logger log) async { - log.warning( - 'Reverting migration: Revert adConfig to old structure ' - '(not recommended for production).', - ); - // This down migration is complex and primarily for development/testing rollback. - // Reverting to the old structure would require re-introducing the old fields - // and potentially losing data if the new structure was used. - // For simplicity in this example, we'll just unset the new fields. - final result = await db - .collection('remote_configs') - .updateMany( - where.exists('adConfig.feedAdConfiguration.visibleTo'), - ModifierBuilder() - ..unset('adConfig.feedAdConfiguration.visibleTo') - ..unset('adConfig.articleAdConfiguration.visibleTo') - ..unset('adConfig.interstitialAdConfiguration.visibleTo'), - ); - log.warning( - 'Reverted ${result.nModified} remote_config documents ' - 'by unsetting new adConfig fields.', - ); - } -} 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 deleted file mode 100644 index da1a245..0000000 --- a/lib/src/database/migrations/20251013000056_add_saved_filters_to_user_preferences.dart +++ /dev/null @@ -1,40 +0,0 @@ -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: - 'This pull request introduces the ability for users to save and manage custom filter combinations for news headlines. It achieves this by adding a new SavedFilter data model, integrating it into the existing user content preferences, and implementing configurable limits for these saved filters based on user tiers', - ); - - @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.'); - } -} diff --git a/lib/src/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart b/lib/src/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart deleted file mode 100644 index f64ff79..0000000 --- a/lib/src/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart +++ /dev/null @@ -1,52 +0,0 @@ -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 `savedFiltersLimit` fields to existing -/// `remote_configs` documents within the `userPreferenceConfig` sub-document. -class AddSavedFiltersToRemoteConfig extends Migration { - /// {@macro add_saved_filters_to_remote_config} - AddSavedFiltersToRemoteConfig() - : super( - prDate: '20251013000057', - prId: '57', - prSummary: - 'This pull request introduces the ability for users to save and manage custom filter combinations for news headlines. It achieves this by adding a new SavedFilter data model, integrating it into the existing user content preferences, and implementing configurable limits for these saved filters based on user tiers', - ); - - @override - Future up(Db db, Logger log) async { - final collection = db.collection('remote_configs'); - final result = await collection.updateMany( - // Filter for documents where 'userPreferenceConfig.guestSavedFiltersLimit' does not exist. - // This assumes if one is missing, all are likely missing. - where.notExists('userPreferenceConfig.guestSavedFiltersLimit'), - // Set 'guestSavedFiltersLimit', 'authenticatedSavedFiltersLimit', - // and 'premiumSavedFiltersLimit' to a default value. - modify - .set('userPreferenceConfig.guestSavedFiltersLimit', 3) - .set('userPreferenceConfig.authenticatedSavedFiltersLimit', 10) - .set('userPreferenceConfig.premiumSavedFiltersLimit', 25), - ); - log.info( - 'Updated ${result.nModified} documents in remote_configs ' - 'to include savedFiltersLimit fields.', - ); - } - - @override - Future down(Db db, Logger log) async { - final collection = db.collection('remote_configs'); - await collection.updateMany( - where.exists('userPreferenceConfig.guestSavedFiltersLimit'), - modify - .unset('userPreferenceConfig.guestSavedFiltersLimit') - .unset('userPreferenceConfig.authenticatedSavedFiltersLimit') - .unset('userPreferenceConfig.premiumSavedFiltersLimit'), - ); - log.info( - 'Removed "savedFiltersLimit" fields from remote_configs ' - 'userPreferenceConfig sub-document.', - ); - } -} diff --git a/lib/src/database/migrations/20251024000000_add_logo_url_to_sources.dart b/lib/src/database/migrations/20251024000000_add_logo_url_to_sources.dart deleted file mode 100644 index 914173d..0000000 --- a/lib/src/database/migrations/20251024000000_add_logo_url_to_sources.dart +++ /dev/null @@ -1,66 +0,0 @@ -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 `logoUrl` field to existing `sources` documents. -class AddLogoUrlToSources extends Migration { - /// {@macro add_logo_url_to_sources} - AddLogoUrlToSources() - : super( - prDate: '20251024000000', - prId: '60', - prSummary: - 'Adds the required `logoUrl` field to all existing ' - 'documents in the `sources` collection to align with the ' - 'core v1.3.0 model update.', - ); - - @override - Future up(Db db, Logger log) async { - final collection = db.collection('sources'); - final sourcesToUpdate = await collection - .find(where.notExists('logoUrl')) - .toList(); - - if (sourcesToUpdate.isEmpty) { - log.info('No sources found needing a logoUrl. Migration is up to date.'); - return; - } - - log.info( - 'Found ${sourcesToUpdate.length} sources to update with a logoUrl.', - ); - var count = 0; - for (final source in sourcesToUpdate) { - final sourceUrl = source['url'] as String?; - if (sourceUrl != null && sourceUrl.isNotEmpty) { - try { - final host = Uri.parse(sourceUrl).host; - final logoUrl = 'https://logo.clearbit.com/$host?size=200'; - await collection.updateOne( - where.id(source['_id'] as ObjectId), - modify.set('logoUrl', logoUrl), - ); - count++; - } catch (e) { - log.warning( - 'Could not parse URL for source ${source['_id']}: $sourceUrl', - ); - } - } - } - log.info('Updated $count sources with a new logoUrl.'); - } - - @override - Future down(Db db, Logger log) async { - final collection = db.collection('sources'); - await collection.updateMany( - where.exists('logoUrl'), - modify.unset('logoUrl'), - ); - log.info( - 'Removed "logoUrl" field from all documents in the sources collection.', - ); - } -} diff --git a/lib/src/database/migrations/20251103073226_remove_local_ad_platform.dart b/lib/src/database/migrations/20251103073226_remove_local_ad_platform.dart deleted file mode 100644 index 8311871..0000000 --- a/lib/src/database/migrations/20251103073226_remove_local_ad_platform.dart +++ /dev/null @@ -1,65 +0,0 @@ -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 remove the legacy `local` ad platform from the `remote_configs` -/// collection. -/// -/// This migration performs two critical cleanup tasks: -/// 1. It removes the `local` key from the `adConfig.platformAdIdentifiers` map -/// in all `remote_configs` documents. -/// 2. It updates any `remote_configs` document where the `primaryAdPlatform` -/// is set to `local`, changing it to `admob`. -/// -/// This ensures data consistency after the removal of the `AdPlatformType.local` -/// enum value and prevents deserialization errors in the application. -class RemoveLocalAdPlatform extends Migration { - /// {@macro remove_local_ad_platform} - RemoveLocalAdPlatform() - : super( - prDate: '20251103073226', - prId: '57', - prSummary: - 'Removes the legacy local ad platform from the remote config, migrating existing data to use admob as the default.', - ); - - @override - Future up(Db db, Logger log) async { - final collection = db.collection('remote_configs'); - - // Step 1: Unset the 'local' key from the platformAdIdentifiers map. - // This removes the field entirely from any document where it exists. - log.info( - 'Attempting to remove "adConfig.platformAdIdentifiers.local" field...', - ); - final unsetResult = await collection.updateMany( - where.exists('adConfig.platformAdIdentifiers.local'), - modify.unset('adConfig.platformAdIdentifiers.local'), - ); - log.info( - 'Removed "adConfig.platformAdIdentifiers.local" from ${unsetResult.nModified} documents.', - ); - - // Step 2: Update the primaryAdPlatform from 'local' to 'admob'. - // This ensures that no document is left with an invalid primary platform. - log.info( - 'Attempting to migrate primaryAdPlatform from "local" to "admob"...', - ); - final updateResult = await collection.updateMany( - where.eq('adConfig.primaryAdPlatform', 'local'), - modify.set('adConfig.primaryAdPlatform', 'admob'), - ); - log.info( - 'Migrated primaryAdPlatform to "admob" for ${updateResult.nModified} documents.', - ); - } - - @override - Future down(Db db, Logger log) async { - // Reverting this change is not safe as it would require re-introducing - // an enum value that no longer exists in the code. - log.warning( - 'Reverting "RemoveLocalAdPlatform" is not supported. The "local" ad platform configuration would need to be manually restored if required.', - ); - } -} diff --git a/lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart b/lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart deleted file mode 100644 index 01abe0f..0000000 --- a/lib/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart +++ /dev/null @@ -1,51 +0,0 @@ -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 `isBreaking` field to existing `Headline` documents. -/// -/// This migration ensures that all existing documents in the `headlines` -/// collection have the `isBreaking` boolean field, defaulting to `false` -/// if it does not already exist. This is crucial for schema consistency -/// when introducing the breaking news feature. -class AddIsBreakingToHeadlines extends Migration { - /// {@macro add_is_breaking_to_headlines} - AddIsBreakingToHeadlines() - : super( - prDate: '20251107000000', - prId: '71', - prSummary: - 'Adds the isBreaking field to existing Headline documents, ' - 'defaulting to false.', - ); - - @override - Future up(Db db, Logger log) async { - final collection = db.collection('headlines'); - - log.info( - 'Attempting to add "isBreaking: false" to Headline documents ' - 'where the field is missing...', - ); - - // Update all documents in the 'headlines' collection that do not - // already have the 'isBreaking' field, setting it to false. - final updateResult = await collection.updateMany( - // Select documents where 'isBreaking' does not exist. - where.notExists('isBreaking'), - modify.set('isBreaking', false), // Set isBreaking to false - ); - - log.info( - 'Added "isBreaking: false" to ${updateResult.nModified} Headline documents.', - ); - } - - @override - Future down(Db db, Logger log) async { - log.warning( - 'Reverting "AddIsBreakingToHeadlines" is not supported. ' - 'The "isBreaking" field would need to be manually removed if required.', - ); - } -} diff --git a/lib/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart b/lib/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart deleted file mode 100644 index 6f2d1a3..0000000 --- a/lib/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:core/core.dart'; -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'; - -/// {@template add_push_notification_config_to_remote_config} -/// A database migration to add the `pushNotificationConfig` field to the -/// `remote_configs` document. -/// -/// This migration ensures that the `remote_configs` document contains the -/// necessary structure for push notification settings, preventing errors when -/// the application starts and tries to access this configuration. It is -/// designed to be idempotent and safe to run multiple times. -/// {@endtemplate} -class AddPushNotificationConfigToRemoteConfig extends Migration { - /// {@macro add_push_notification_config_to_remote_config} - AddPushNotificationConfigToRemoteConfig() - : super( - prId: '71', - prSummary: - 'Add pushNotificationConfig field to the remote_configs document.', - prDate: '20251108103300', - ); - - @override - Future up(Db db, Logger log) async { - log.info('Running up migration: $prSummary'); - - final remoteConfigCollection = db.collection('remote_configs'); - final remoteConfigId = ObjectId.fromHexString(kRemoteConfigId); - - // Default structure for the push notification configuration. - final pushNotificationConfig = - remoteConfigsFixturesData.first.pushNotificationConfig; - - // Use $set to add the field only if it doesn't exist. - // This is an idempotent operation. - await remoteConfigCollection.updateOne( - where - .id(remoteConfigId) - .and( - where.notExists('pushNotificationConfig'), - ), - modify.set('pushNotificationConfig', pushNotificationConfig.toJson()), - ); - - log.info('Successfully completed up migration for $prDate.'); - } - - @override - Future down(Db db, Logger log) async { - log.info('Running down migration: $prSummary'); - // This migration is additive. The `down` method will unset the field. - final remoteConfigCollection = db.collection('remote_configs'); - final remoteConfigId = ObjectId.fromHexString(kRemoteConfigId); - await remoteConfigCollection.updateOne( - where.id(remoteConfigId), - modify.unset('pushNotificationConfig'), - ); - log.info('Successfully completed down migration for $prDate.'); - } -} diff --git a/lib/src/database/migrations/20251112000000_refactor_user_preferences_and_remote_config.dart b/lib/src/database/migrations/20251112000000_refactor_user_preferences_and_remote_config.dart deleted file mode 100644 index 0e7811f..0000000 --- a/lib/src/database/migrations/20251112000000_refactor_user_preferences_and_remote_config.dart +++ /dev/null @@ -1,160 +0,0 @@ -import 'package:core/core.dart'; -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'; - -/// {@template refactor_user_preferences_and_remote_config} -/// A migration to refactor the database schema to align with the updated -/// `UserContentPreferences` and `RemoteConfig` models from the core package. -/// -/// This migration performs two critical transformations: -/// -/// 1. **User Preferences Transformation:** It iterates through all -/// `user_content_preferences` documents. For each user, it adds the new -/// `savedHeadlineFilters` and `savedSourceFilters` fields as empty lists -/// and removes the now-obsolete `interests` field. -/// -/// 2. **Remote Config Transformation:** It updates the single `remote_configs` -/// document by removing the deprecated `interestConfig` and replacing the -/// individual limit fields in `userPreferenceConfig` with the new, -/// flexible role-based map structure. -/// {@endtemplate} -class RefactorUserPreferencesAndRemoteConfig extends Migration { - /// {@macro refactor_user_preferences_and_remote_config} - RefactorUserPreferencesAndRemoteConfig() - : super( - prDate: '20251112000000', - prId: '78', - prSummary: - 'Refactors UserContentPreferences and RemoteConfig to support new SavedFilter models.', - ); - - @override - Future up(Db db, Logger log) async { - log.info('Starting migration: RefactorUserPreferencesAndRemoteConfig.up'); - - // --- 1. Migrate user_content_preferences --- - log.info('Migrating user_content_preferences collection...'); - final preferencesCollection = db.collection('user_content_preferences'); - final result = await preferencesCollection.updateMany( - where.exists('interests'), - modify - .set('savedHeadlineFilters', []) - .set('savedSourceFilters', []) - .unset('interests'), - ); - log.info( - 'Updated user_content_preferences: ${result.nModified} documents modified.', - ); - - // --- 2. Migrate remote_configs --- - log.info('Migrating remote_configs collection...'); - final remoteConfigCollection = db.collection('remote_configs'); - final remoteConfig = await remoteConfigCollection.findOne(); - - if (remoteConfig != null) { - // Define the new UserPreferenceConfig structure based on the new model. - // This uses the structure from the "NEW REMOTE CONFIG" example. - const newConfig = UserPreferenceConfig( - followedItemsLimit: { - AppUserRole.guestUser: 5, - AppUserRole.standardUser: 15, - AppUserRole.premiumUser: 30, - }, - savedHeadlinesLimit: { - AppUserRole.guestUser: 10, - AppUserRole.standardUser: 30, - AppUserRole.premiumUser: 100, - }, - savedHeadlineFiltersLimit: { - AppUserRole.guestUser: SavedFilterLimits( - total: 3, - pinned: 3, - notificationSubscriptions: { - PushNotificationSubscriptionDeliveryType.breakingOnly: 1, - PushNotificationSubscriptionDeliveryType.dailyDigest: 0, - PushNotificationSubscriptionDeliveryType.weeklyRoundup: 0, - }, - ), - AppUserRole.standardUser: SavedFilterLimits( - total: 10, - pinned: 5, - notificationSubscriptions: { - PushNotificationSubscriptionDeliveryType.breakingOnly: 3, - PushNotificationSubscriptionDeliveryType.dailyDigest: 2, - PushNotificationSubscriptionDeliveryType.weeklyRoundup: 2, - }, - ), - AppUserRole.premiumUser: SavedFilterLimits( - total: 25, - pinned: 10, - notificationSubscriptions: { - PushNotificationSubscriptionDeliveryType.breakingOnly: 10, - PushNotificationSubscriptionDeliveryType.dailyDigest: 10, - PushNotificationSubscriptionDeliveryType.weeklyRoundup: 10, - }, - ), - }, - savedSourceFiltersLimit: { - AppUserRole.guestUser: SavedFilterLimits(total: 3, pinned: 3), - AppUserRole.standardUser: SavedFilterLimits(total: 10, pinned: 5), - AppUserRole.premiumUser: SavedFilterLimits(total: 25, pinned: 10), - }, - ); - - await remoteConfigCollection.updateOne( - where.id(remoteConfig['_id'] as ObjectId), - modify - // Set the entire userPreferenceConfig to the new structure - .set('userPreferenceConfig', newConfig.toJson()) - // Remove the obsolete interestConfig - .unset('interestConfig'), - ); - log.info('Successfully migrated remote_configs document.'); - } else { - log.warning('Remote config document not found. Skipping migration.'); - } - - log.info('Migration RefactorUserPreferencesAndRemoteConfig.up completed.'); - } - - @override - Future down(Db db, Logger log) async { - log.warning( - 'Executing "down" for RefactorUserPreferencesAndRemoteConfig. ' - 'This is a destructive operation and may result in data loss.', - ); - - // --- 1. Revert user_content_preferences --- - final preferencesCollection = db.collection('user_content_preferences'); - await preferencesCollection.updateMany( - where.exists('savedHeadlineFilters'), // Target documents to revert - modify - .unset('savedHeadlineFilters') - .unset('savedSourceFilters') - .set('interests', []), - ); - log.info( - 'Reverted user_content_preferences: removed new filter fields and ' - 're-added empty "interests" field.', - ); - - // --- 2. Revert remote_configs --- - // This is a best-effort revert and will not restore the exact previous - // state but will remove the new fields. - final remoteConfigCollection = db.collection('remote_configs'); - await remoteConfigCollection.updateMany( - where.exists('userPreferenceConfig.followedItemsLimit'), - modify - .unset('userPreferenceConfig') - .set('interestConfig', {}), - ); - log.info( - 'Reverted remote_configs: removed new userPreferenceConfig structure.', - ); - - log.info( - 'Migration RefactorUserPreferencesAndRemoteConfig.down completed.', - ); - } -} diff --git a/lib/src/database/migrations/all_migrations.dart b/lib/src/database/migrations/all_migrations.dart index 454ebd2..f9c66c4 100644 --- a/lib/src/database/migrations/all_migrations.dart +++ b/lib/src/database/migrations/all_migrations.dart @@ -1,12 +1,4 @@ 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/database/migrations/20251013000057_add_saved_filters_to_remote_config.dart'; -import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251024000000_add_logo_url_to_sources.dart'; -import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251103073226_remove_local_ad_platform.dart'; -import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251107000000_add_is_breaking_to_headlines.dart'; -import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251108103300_add_push_notification_config_to_remote_config.dart'; -import 'package:flutter_news_app_api_server_full_source_code/src/database/migrations/20251112000000_refactor_user_preferences_and_remote_config.dart'; import 'package:flutter_news_app_api_server_full_source_code/src/services/database_migration_service.dart' show DatabaseMigrationService; @@ -15,13 +7,4 @@ import 'package:flutter_news_app_api_server_full_source_code/src/services/databa /// New migration classes should be added to this list. The /// [DatabaseMigrationService] will automatically sort and apply them based /// on their `prDate` property. -final List allMigrations = [ - RefactorAdConfigToRoleBased(), - AddSavedFiltersToUserPreferences(), - AddSavedFiltersToRemoteConfig(), - AddLogoUrlToSources(), - RemoveLocalAdPlatform(), - AddIsBreakingToHeadlines(), - AddPushNotificationConfigToRemoteConfig(), - RefactorUserPreferencesAndRemoteConfig(), -]; +final List allMigrations = [];