@@ -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,141 @@ 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
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...' ,
109+ );
110+
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
120+ .read (id: currentAuthUser.id, userId: currentAuthUser.id);
121+ print (
122+ 'Fetched existing settings and preferences for anonymous user '
123+ '${currentAuthUser .id }.' ,
124+ );
125+ } on NotFoundException {
126+ print (
127+ 'No existing settings/preferences found for anonymous user '
128+ '${currentAuthUser .id }. Creating new ones.' ,
129+ );
130+ // If not found, proceed to create new ones later.
131+ } catch (e) {
132+ print (
133+ 'Error fetching existing settings/preferences for anonymous user '
134+ '${currentAuthUser .id }: $e ' ,
135+ );
136+ // Log and continue, new defaults will be created.
137+ }
138+
139+ // Update the existing anonymous user to be permanent
140+ user = currentAuthUser.copyWith (
117141 email: email,
118- role: UserRole .standardUser, // Email verified user is standard user
142+ role: UserRole .standardUser,
119143 );
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
144+ user = await _userRepository.update (id: user.id, item: user);
145+ print (
146+ 'Updated anonymous user ${user .id } to permanent with email $email .' ,
128147 );
129- print ('Created default UserAppSettings for user: ${user .id }' );
130148
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
136- );
137- print ('Created default UserContentPreferences for user: ${user .id }' );
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 (
232+ 'Unexpected error during user lookup/creation/migration for $email : $e ' ,
233+ );
146234 throw const OperationFailedException ('Failed to process user account.' );
147235 }
148236
0 commit comments