@@ -26,7 +26,7 @@ class DatabaseSeedingService {
2626 _log.info ('Starting database seeding process...' );
2727
2828 await _ensureIndexes ();
29- await _seedInitialAdminUser ();
29+ await _seedOverrideAdminUser ();
3030
3131 await _seedCollection <Country >(
3232 collectionName: 'countries' ,
@@ -75,31 +75,54 @@ class DatabaseSeedingService {
7575 _log.info ('Database seeding process completed.' );
7676 }
7777
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;
8283
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+ );
8588 return ;
8689 }
8790
8891 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+ );
9095
96+ // Case 1: An admin exists.
9197 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);
94115 }
95116
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,
103126 createdAt: DateTime .now (),
104127 feedActionStatus: Map .fromEntries (
105128 FeedActionType .values.map (
@@ -110,12 +133,31 @@ class DatabaseSeedingService {
110133 );
111134
112135 await usersCollection.insertOne (
113- {'_id' : adminId , ...adminUser .toJson ()..remove ('id' )},
136+ {'_id' : newAdminId , ...newAdminUser .toJson ()..remove ('id' )},
114137 );
115138
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 {
117159 final defaultAppSettings = UserAppSettings (
118- id: adminId .oid,
160+ id: userId .oid,
119161 displaySettings: const DisplaySettings (
120162 baseTheme: AppBaseTheme .system,
121163 accentTheme: AppAccentTheme .defaultBlue,
@@ -131,24 +173,20 @@ class DatabaseSeedingService {
131173 showPublishDateInHeadlineFeed: true ,
132174 ),
133175 );
134-
135176 await _db.collection ('user_app_settings' ).insertOne (
136- {'_id' : adminId , ...defaultAppSettings.toJson ()..remove ('id' )},
177+ {'_id' : userId , ...defaultAppSettings.toJson ()..remove ('id' )},
137178 );
138179
139180 final defaultUserPreferences = UserContentPreferences (
140- id: adminId .oid,
181+ id: userId .oid,
141182 followedCountries: const [],
142183 followedSources: const [],
143184 followedTopics: const [],
144185 savedHeadlines: const [],
145186 );
146-
147187 await _db.collection ('user_content_preferences' ).insertOne (
148- {'_id' : adminId , ...defaultUserPreferences.toJson ()..remove ('id' )},
188+ {'_id' : userId , ...defaultUserPreferences.toJson ()..remove ('id' )},
149189 );
150-
151- _log.info ('Successfully created initial admin user for $adminEmail .' );
152190 }
153191
154192 /// Seeds a specific collection from a given list of fixture data.
0 commit comments