Skip to content

Commit 71a9e05

Browse files
committed
refactor(database): improve admin user seeding and override process
- Rename `_seedInitialAdminUser` to `_seedOverrideAdminUser` - Update logic to handle admin user override based on OVERRIDE_ADMIN_EMAIL - Add functionality to delete existing admin user and their data if overridden - Separate user sub-document creation into a reusable method - Update method names and variables to reflect new functionality
1 parent 43bf7df commit 71a9e05

File tree

1 file changed

+65
-27
lines changed

1 file changed

+65
-27
lines changed

lib/src/services/database_seeding_service.dart

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)