Skip to content

Commit be05a6a

Browse files
authored
Merge pull request #96 from flutter-news-app-full-source-code/refactor/sync-with-core-package-update
Refactor/sync with core package update
2 parents 9200f61 + 271c8ce commit be05a6a

12 files changed

+302
-321
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ The API automatically validates the structure of all incoming data, ensuring tha
7676
### 📲 Dynamic & Personalized Notifications
7777
A complete, multi-provider notification engine that empowers you to engage users with timely, relevant, and personalized alerts.
7878
- **Editorial-Driven Alerts:** Any piece of content can be designated as "breaking news" from the content dashboard, triggering immediate, high-priority alerts to subscribed users.
79-
- **User-Crafted Notification Streams:** Users can create and save persistent **Interests** based on any combination of content filters (such as topics, sources, or regions). They can then subscribe to notifications for that interest, receiving alerts only for the news they care about.
79+
- **User-Crafted Notification Streams:** Users can create and save persistent **Saved Headline Filters** based on any combination of content filters (such as topics, sources, or regions). They can then subscribe to notifications for that filter, receiving alerts only for the news they care about.
8080
- **Flexible Delivery Mechanisms:** The system is architected to support multiple notification types for each subscription, from immediate alerts to scheduled daily or weekly digests.
8181
- **Provider Agnostic:** The engine is built to be provider-agnostic, with out-of-the-box support for Firebase (FCM) and OneSignal. The active provider can be switched remotely without any code changes.
8282
> **Your Advantage:** You get a complete, secure, and scalable notification system that enhances user engagement and can be managed entirely from the web dashboard.

lib/src/database/migrations/20251111000000_unify_interests_and_remote_config.dart

Lines changed: 0 additions & 229 deletions
This file was deleted.
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import 'package:core/core.dart';
2+
import 'package:flutter_news_app_api_server_full_source_code/src/database/migration.dart';
3+
import 'package:logging/logging.dart';
4+
import 'package:mongo_dart/mongo_dart.dart';
5+
6+
/// {@template refactor_user_preferences_and_remote_config}
7+
/// A migration to refactor the database schema to align with the updated
8+
/// `UserContentPreferences` and `RemoteConfig` models from the core package.
9+
///
10+
/// This migration performs two critical transformations:
11+
///
12+
/// 1. **User Preferences Transformation:** It iterates through all
13+
/// `user_content_preferences` documents. For each user, it adds the new
14+
/// `savedHeadlineFilters` and `savedSourceFilters` fields as empty lists
15+
/// and removes the now-obsolete `interests` field.
16+
///
17+
/// 2. **Remote Config Transformation:** It updates the single `remote_configs`
18+
/// document by removing the deprecated `interestConfig` and replacing the
19+
/// individual limit fields in `userPreferenceConfig` with the new,
20+
/// flexible role-based map structure.
21+
/// {@endtemplate}
22+
class RefactorUserPreferencesAndRemoteConfig extends Migration {
23+
/// {@macro refactor_user_preferences_and_remote_config}
24+
RefactorUserPreferencesAndRemoteConfig()
25+
: super(
26+
prDate: '20251112000000',
27+
prId: '78',
28+
prSummary:
29+
'Refactors UserContentPreferences and RemoteConfig to support new SavedFilter models.',
30+
);
31+
32+
@override
33+
Future<void> up(Db db, Logger log) async {
34+
log.info('Starting migration: RefactorUserPreferencesAndRemoteConfig.up');
35+
36+
// --- 1. Migrate user_content_preferences ---
37+
log.info('Migrating user_content_preferences collection...');
38+
final preferencesCollection = db.collection('user_content_preferences');
39+
final result = await preferencesCollection.updateMany(
40+
where.exists('interests'),
41+
modify
42+
.set('savedHeadlineFilters', <dynamic>[])
43+
.set('savedSourceFilters', <dynamic>[])
44+
.unset('interests'),
45+
);
46+
log.info(
47+
'Updated user_content_preferences: ${result.nModified} documents modified.',
48+
);
49+
50+
// --- 2. Migrate remote_configs ---
51+
log.info('Migrating remote_configs collection...');
52+
final remoteConfigCollection = db.collection('remote_configs');
53+
final remoteConfig = await remoteConfigCollection.findOne();
54+
55+
if (remoteConfig != null) {
56+
// Define the new UserPreferenceConfig structure based on the new model.
57+
// This uses the structure from the "NEW REMOTE CONFIG" example.
58+
const newConfig = UserPreferenceConfig(
59+
followedItemsLimit: {
60+
AppUserRole.guestUser: 5,
61+
AppUserRole.standardUser: 15,
62+
AppUserRole.premiumUser: 30,
63+
},
64+
savedHeadlinesLimit: {
65+
AppUserRole.guestUser: 10,
66+
AppUserRole.standardUser: 30,
67+
AppUserRole.premiumUser: 100,
68+
},
69+
savedHeadlineFiltersLimit: {
70+
AppUserRole.guestUser: SavedFilterLimits(
71+
total: 3,
72+
pinned: 3,
73+
notificationSubscriptions: {
74+
PushNotificationSubscriptionDeliveryType.breakingOnly: 1,
75+
PushNotificationSubscriptionDeliveryType.dailyDigest: 0,
76+
PushNotificationSubscriptionDeliveryType.weeklyRoundup: 0,
77+
},
78+
),
79+
AppUserRole.standardUser: SavedFilterLimits(
80+
total: 10,
81+
pinned: 5,
82+
notificationSubscriptions: {
83+
PushNotificationSubscriptionDeliveryType.breakingOnly: 3,
84+
PushNotificationSubscriptionDeliveryType.dailyDigest: 2,
85+
PushNotificationSubscriptionDeliveryType.weeklyRoundup: 2,
86+
},
87+
),
88+
AppUserRole.premiumUser: SavedFilterLimits(
89+
total: 25,
90+
pinned: 10,
91+
notificationSubscriptions: {
92+
PushNotificationSubscriptionDeliveryType.breakingOnly: 10,
93+
PushNotificationSubscriptionDeliveryType.dailyDigest: 10,
94+
PushNotificationSubscriptionDeliveryType.weeklyRoundup: 10,
95+
},
96+
),
97+
},
98+
savedSourceFiltersLimit: {
99+
AppUserRole.guestUser: SavedFilterLimits(total: 3, pinned: 3),
100+
AppUserRole.standardUser: SavedFilterLimits(total: 10, pinned: 5),
101+
AppUserRole.premiumUser: SavedFilterLimits(total: 25, pinned: 10),
102+
},
103+
);
104+
105+
await remoteConfigCollection.updateOne(
106+
where.id(remoteConfig['_id'] as ObjectId),
107+
modify
108+
// Set the entire userPreferenceConfig to the new structure
109+
.set('userPreferenceConfig', newConfig.toJson())
110+
// Remove the obsolete interestConfig
111+
.unset('interestConfig'),
112+
);
113+
log.info('Successfully migrated remote_configs document.');
114+
} else {
115+
log.warning('Remote config document not found. Skipping migration.');
116+
}
117+
118+
log.info('Migration RefactorUserPreferencesAndRemoteConfig.up completed.');
119+
}
120+
121+
@override
122+
Future<void> down(Db db, Logger log) async {
123+
log.warning(
124+
'Executing "down" for RefactorUserPreferencesAndRemoteConfig. '
125+
'This is a destructive operation and may result in data loss.',
126+
);
127+
128+
// --- 1. Revert user_content_preferences ---
129+
final preferencesCollection = db.collection('user_content_preferences');
130+
await preferencesCollection.updateMany(
131+
where.exists('savedHeadlineFilters'), // Target documents to revert
132+
modify
133+
.unset('savedHeadlineFilters')
134+
.unset('savedSourceFilters')
135+
.set('interests', <dynamic>[]),
136+
);
137+
log.info(
138+
'Reverted user_content_preferences: removed new filter fields and '
139+
're-added empty "interests" field.',
140+
);
141+
142+
// --- 2. Revert remote_configs ---
143+
// This is a best-effort revert and will not restore the exact previous
144+
// state but will remove the new fields.
145+
final remoteConfigCollection = db.collection('remote_configs');
146+
await remoteConfigCollection.updateMany(
147+
where.exists('userPreferenceConfig.followedItemsLimit'),
148+
modify
149+
.unset('userPreferenceConfig')
150+
.set('interestConfig', <String, dynamic>{}),
151+
);
152+
log.info(
153+
'Reverted remote_configs: removed new userPreferenceConfig structure.',
154+
);
155+
156+
log.info(
157+
'Migration RefactorUserPreferencesAndRemoteConfig.down completed.',
158+
);
159+
}
160+
}

0 commit comments

Comments
 (0)