@@ -26,7 +26,7 @@ class DatabaseSeedingService {
26
26
_log.info ('Starting database seeding process...' );
27
27
28
28
await _ensureIndexes ();
29
- await _seedInitialAdminUser ();
29
+ await _seedOverrideAdminUser ();
30
30
31
31
await _seedCollection <Country >(
32
32
collectionName: 'countries' ,
@@ -75,31 +75,54 @@ class DatabaseSeedingService {
75
75
_log.info ('Database seeding process completed.' );
76
76
}
77
77
78
- /// Seeds the initial administrator user from the environment variable.
79
- Future <void > _seedInitialAdminUser () async {
80
- _log.info ('Checking for initial admin user...' );
81
- final adminEmail = EnvironmentConfig .initialAdminEmail;
78
+ /// Ensures the single administrator account is correctly configured based on
79
+ /// the `OVERRIDE_ADMIN_EMAIL` environment variable.
80
+ Future <void > _seedOverrideAdminUser () async {
81
+ _log.info ('Checking for admin user override...' );
82
+ final overrideEmail = EnvironmentConfig .overrideAdminEmail;
82
83
83
- if (adminEmail == null || adminEmail.isEmpty) {
84
- _log.info ('INITIAL_ADMIN_EMAIL not set. Skipping admin user seeding.' );
84
+ if (overrideEmail == null || overrideEmail.isEmpty) {
85
+ _log.info (
86
+ 'OVERRIDE_ADMIN_EMAIL not set. Skipping admin user override.' ,
87
+ );
85
88
return ;
86
89
}
87
90
88
91
final usersCollection = _db.collection ('users' );
89
- final existingAdmin = await usersCollection.findOne ({'email' : adminEmail});
92
+ final existingAdmin = await usersCollection.findOne (
93
+ where.eq ('dashboardRole' , DashboardUserRole .admin.name),
94
+ );
90
95
96
+ // Case 1: An admin exists.
91
97
if (existingAdmin != null ) {
92
- _log.info ('Admin user with email $adminEmail already exists.' );
93
- return ;
98
+ final existingAdminEmail = existingAdmin['email' ] as String ;
99
+ // If the existing admin's email is the same as the override, do nothing.
100
+ if (existingAdminEmail == overrideEmail) {
101
+ _log.info (
102
+ 'Admin user with email $overrideEmail already exists and matches '
103
+ 'override. No action needed.' ,
104
+ );
105
+ return ;
106
+ }
107
+
108
+ // If emails differ, delete the old admin and their data.
109
+ _log.warning (
110
+ 'Found existing admin with email "$existingAdminEmail ". It will be '
111
+ 'replaced by the override email "$overrideEmail ".' ,
112
+ );
113
+ final oldAdminId = existingAdmin['_id' ] as ObjectId ;
114
+ await _deleteUserAndData (oldAdminId);
94
115
}
95
116
96
- _log.info ('Creating initial admin user for email: $adminEmail ' );
97
- final adminId = ObjectId ();
98
- final adminUser = User (
99
- id: adminId.oid,
100
- email: adminEmail,
101
- appRole: AppUserRole .standardUser, // Admins are standard app users
102
- dashboardRole: DashboardUserRole .admin, // With admin dashboard role
117
+ // Case 2: No admin exists, or the old one was just deleted.
118
+ // Create the new admin.
119
+ _log.info ('Creating admin user for email: $overrideEmail ' );
120
+ final newAdminId = ObjectId ();
121
+ final newAdminUser = User (
122
+ id: newAdminId.oid,
123
+ email: overrideEmail,
124
+ appRole: AppUserRole .standardUser,
125
+ dashboardRole: DashboardUserRole .admin,
103
126
createdAt: DateTime .now (),
104
127
feedActionStatus: Map .fromEntries (
105
128
FeedActionType .values.map (
@@ -110,12 +133,31 @@ class DatabaseSeedingService {
110
133
);
111
134
112
135
await usersCollection.insertOne (
113
- {'_id' : adminId , ...adminUser .toJson ()..remove ('id' )},
136
+ {'_id' : newAdminId , ...newAdminUser .toJson ()..remove ('id' )},
114
137
);
115
138
116
- // Also create their default settings and preferences documents
139
+ // Create default settings and preferences for the new admin.
140
+ await _createUserSubDocuments (newAdminId);
141
+
142
+ _log.info ('Successfully created admin user for $overrideEmail .' );
143
+ }
144
+
145
+ /// Deletes a user and their associated sub-documents.
146
+ Future <void > _deleteUserAndData (ObjectId userId) async {
147
+ await _db.collection ('users' ).deleteOne (where.eq ('_id' , userId));
148
+ await _db
149
+ .collection ('user_app_settings' )
150
+ .deleteOne (where.eq ('_id' , userId));
151
+ await _db
152
+ .collection ('user_content_preferences' )
153
+ .deleteOne (where.eq ('_id' , userId));
154
+ _log.info ('Deleted user and associated data for ID: ${userId .oid }' );
155
+ }
156
+
157
+ /// Creates the default sub-documents (settings, preferences) for a new user.
158
+ Future <void > _createUserSubDocuments (ObjectId userId) async {
117
159
final defaultAppSettings = UserAppSettings (
118
- id: adminId .oid,
160
+ id: userId .oid,
119
161
displaySettings: const DisplaySettings (
120
162
baseTheme: AppBaseTheme .system,
121
163
accentTheme: AppAccentTheme .defaultBlue,
@@ -131,24 +173,20 @@ class DatabaseSeedingService {
131
173
showPublishDateInHeadlineFeed: true ,
132
174
),
133
175
);
134
-
135
176
await _db.collection ('user_app_settings' ).insertOne (
136
- {'_id' : adminId , ...defaultAppSettings.toJson ()..remove ('id' )},
177
+ {'_id' : userId , ...defaultAppSettings.toJson ()..remove ('id' )},
137
178
);
138
179
139
180
final defaultUserPreferences = UserContentPreferences (
140
- id: adminId .oid,
181
+ id: userId .oid,
141
182
followedCountries: const [],
142
183
followedSources: const [],
143
184
followedTopics: const [],
144
185
savedHeadlines: const [],
145
186
);
146
-
147
187
await _db.collection ('user_content_preferences' ).insertOne (
148
- {'_id' : adminId , ...defaultUserPreferences.toJson ()..remove ('id' )},
188
+ {'_id' : userId , ...defaultUserPreferences.toJson ()..remove ('id' )},
149
189
);
150
-
151
- _log.info ('Successfully created initial admin user for $adminEmail .' );
152
190
}
153
191
154
192
/// Seeds a specific collection from a given list of fixture data.
0 commit comments