Skip to content

Commit 523040a

Browse files
committed
refactor(auth): Link anon user on email sign-in
- Migrates anon user data to new account - Updates user role to standard user - Handles settings/pref migration
1 parent d3acf70 commit 523040a

File tree

1 file changed

+126
-40
lines changed

1 file changed

+126
-40
lines changed

lib/src/services/auth_service.dart

Lines changed: 126 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ class AuthService {
7474
/// Throws [OperationFailedException] for user lookup/creation or token errors.
7575
Future<({User user, String token})> completeEmailSignIn(
7676
String email,
77-
String code,
78-
// User? currentAuthUser, // Parameter for potential future linking logic
79-
) async {
77+
String code, {
78+
User? currentAuthUser, // Parameter for potential future linking logic
79+
}) async {
8080
// 1. Validate the code for standard sign-in
8181
final isValidCode = await _verificationCodeStorageService
8282
.validateSignInCode(email, code);
@@ -96,53 +96,139 @@ class AuthService {
9696
);
9797
}
9898

99-
// 2. Find or create the user
99+
// 2. Find or create the user, and migrate data if anonymous
100100
User user;
101101
try {
102-
// Attempt to find user by email (assuming a query method exists)
103-
// NOTE: HtDataRepository<User> currently lacks findByEmail.
104-
// We'll simulate this by querying all and filtering for now.
105-
// Replace with a proper query when available.
106-
final query = {'email': email}; // Hypothetical query
107-
final paginatedResponse = await _userRepository.readAllByQuery(query);
108-
109-
if (paginatedResponse.items.isNotEmpty) {
110-
user = paginatedResponse.items.first;
111-
print('Found existing user: ${user.id} for email $email');
112-
} else {
113-
// User not found, create a new one
114-
print('User not found for $email, creating new user.');
115-
user = User(
116-
id: _uuid.v4(), // Generate new ID
117-
email: email,
118-
role: UserRole.standardUser, // Email verified user is standard user
119-
);
120-
user = await _userRepository.create(item: user); // Save the new user
121-
print('Created new user: ${user.id}');
122-
123-
// Create default UserAppSettings for the new user
124-
final defaultAppSettings = UserAppSettings(id: user.id);
125-
await _userAppSettingsRepository.create(
126-
item: defaultAppSettings,
127-
userId: user.id, // Pass user ID for scoping
102+
if (currentAuthUser != null &&
103+
currentAuthUser.role == UserRole.guestUser) {
104+
// This is an anonymous user linking their account.
105+
// Migrate their existing data to the new permanent user.
106+
print(
107+
'Anonymous user ${currentAuthUser.id} is linking email $email. '
108+
'Migrating data...',
128109
);
129-
print('Created default UserAppSettings for user: ${user.id}');
130110

131-
// Create default UserContentPreferences for the new user
132-
final defaultUserPreferences = UserContentPreferences(id: user.id);
133-
await _userContentPreferencesRepository.create(
134-
item: defaultUserPreferences,
135-
userId: user.id, // Pass user ID for scoping
111+
// Fetch existing settings and preferences for the anonymous user
112+
UserAppSettings? existingAppSettings;
113+
UserContentPreferences? existingUserPreferences;
114+
try {
115+
existingAppSettings = await _userAppSettingsRepository.read(
116+
id: currentAuthUser.id,
117+
userId: currentAuthUser.id,
118+
);
119+
existingUserPreferences = await _userContentPreferencesRepository.read(
120+
id: currentAuthUser.id,
121+
userId: currentAuthUser.id,
122+
);
123+
print(
124+
'Fetched existing settings and preferences for anonymous user '
125+
'${currentAuthUser.id}.',
126+
);
127+
} on NotFoundException {
128+
print(
129+
'No existing settings/preferences found for anonymous user '
130+
'${currentAuthUser.id}. Creating new ones.',
131+
);
132+
// If not found, proceed to create new ones later.
133+
} catch (e) {
134+
print(
135+
'Error fetching existing settings/preferences for anonymous user '
136+
'${currentAuthUser.id}: $e',
137+
);
138+
// Log and continue, new defaults will be created.
139+
}
140+
141+
// Update the existing anonymous user to be permanent
142+
user = currentAuthUser.copyWith(
143+
email: email,
144+
role: UserRole.standardUser,
136145
);
137-
print('Created default UserContentPreferences for user: ${user.id}');
146+
user = await _userRepository.update(id: user.id, item: user);
147+
print('Updated anonymous user ${user.id} to permanent with email $email.');
148+
149+
// Update or create UserAppSettings for the now-permanent user
150+
if (existingAppSettings != null) {
151+
// Update existing settings with the new user ID (though it's the same)
152+
// and persist.
153+
await _userAppSettingsRepository.update(
154+
id: existingAppSettings.id,
155+
item: existingAppSettings.copyWith(id: user.id),
156+
userId: user.id,
157+
);
158+
print('Migrated UserAppSettings for user: ${user.id}');
159+
} else {
160+
// Create default settings if none existed for the anonymous user
161+
final defaultAppSettings = UserAppSettings(id: user.id);
162+
await _userAppSettingsRepository.create(
163+
item: defaultAppSettings,
164+
userId: user.id,
165+
);
166+
print('Created default UserAppSettings for user: ${user.id}');
167+
}
168+
169+
// Update or create UserContentPreferences for the now-permanent user
170+
if (existingUserPreferences != null) {
171+
// Update existing preferences with the new user ID (though it's the same)
172+
// and persist.
173+
await _userContentPreferencesRepository.update(
174+
id: existingUserPreferences.id,
175+
item: existingUserPreferences.copyWith(id: user.id),
176+
userId: user.id,
177+
);
178+
print('Migrated UserContentPreferences for user: ${user.id}');
179+
} else {
180+
// Create default preferences if none existed for the anonymous user
181+
final defaultUserPreferences = UserContentPreferences(id: user.id);
182+
await _userContentPreferencesRepository.create(
183+
item: defaultUserPreferences,
184+
userId: user.id,
185+
);
186+
print('Created default UserContentPreferences for user: ${user.id}');
187+
}
188+
} else {
189+
// Standard sign-in/sign-up flow (not anonymous linking)
190+
// Attempt to find user by email
191+
final query = {'email': email};
192+
final paginatedResponse = await _userRepository.readAllByQuery(query);
193+
194+
if (paginatedResponse.items.isNotEmpty) {
195+
user = paginatedResponse.items.first;
196+
print('Found existing user: ${user.id} for email $email');
197+
} else {
198+
// User not found, create a new one
199+
print('User not found for $email, creating new user.');
200+
user = User(
201+
id: _uuid.v4(), // Generate new ID
202+
email: email,
203+
role: UserRole.standardUser, // Email verified user is standard user
204+
);
205+
user = await _userRepository.create(item: user); // Save the new user
206+
print('Created new user: ${user.id}');
207+
208+
// Create default UserAppSettings for the new user
209+
final defaultAppSettings = UserAppSettings(id: user.id);
210+
await _userAppSettingsRepository.create(
211+
item: defaultAppSettings,
212+
userId: user.id, // Pass user ID for scoping
213+
);
214+
print('Created default UserAppSettings for user: ${user.id}');
215+
216+
// Create default UserContentPreferences for the new user
217+
final defaultUserPreferences = UserContentPreferences(id: user.id);
218+
await _userContentPreferencesRepository.create(
219+
item: defaultUserPreferences,
220+
userId: user.id, // Pass user ID for scoping
221+
);
222+
print('Created default UserContentPreferences for user: ${user.id}');
223+
}
138224
}
139225
} on HtHttpException catch (e) {
140-
print('Error finding/creating user for $email: $e');
226+
print('Error finding/creating/migrating user for $email: $e');
141227
throw const OperationFailedException(
142-
'Failed to find or create user account.',
228+
'Failed to find, create, or migrate user account.',
143229
);
144230
} catch (e) {
145-
print('Unexpected error during user lookup/creation for $email: $e');
231+
print('Unexpected error during user lookup/creation/migration for $email: $e');
146232
throw const OperationFailedException('Failed to process user account.');
147233
}
148234

0 commit comments

Comments
 (0)