@@ -3,6 +3,7 @@ import 'package:ht_api/src/services/verification_code_storage_service.dart';
3
3
import 'package:ht_data_repository/ht_data_repository.dart' ;
4
4
import 'package:ht_email_repository/ht_email_repository.dart' ;
5
5
import 'package:ht_shared/ht_shared.dart' ;
6
+ import 'package:logging/logging.dart' ;
6
7
import 'package:uuid/uuid.dart' ;
7
8
8
9
/// {@template auth_service}
@@ -22,13 +23,15 @@ class AuthService {
22
23
required HtDataRepository <UserContentPreferences >
23
24
userContentPreferencesRepository,
24
25
required Uuid uuidGenerator,
26
+ required Logger log,
25
27
}) : _userRepository = userRepository,
26
28
_authTokenService = authTokenService,
27
29
_verificationCodeStorageService = verificationCodeStorageService,
28
30
_emailRepository = emailRepository,
29
31
_userAppSettingsRepository = userAppSettingsRepository,
30
32
_userContentPreferencesRepository = userContentPreferencesRepository,
31
- _uuid = uuidGenerator;
33
+ _uuid = uuidGenerator,
34
+ _log = log;
32
35
33
36
final HtDataRepository <User > _userRepository;
34
37
final AuthTokenService _authTokenService;
@@ -37,6 +40,7 @@ class AuthService {
37
40
final HtDataRepository <UserAppSettings > _userAppSettingsRepository;
38
41
final HtDataRepository <UserContentPreferences >
39
42
_userContentPreferencesRepository;
43
+ final Logger _log;
40
44
final Uuid _uuid;
41
45
42
46
/// Initiates the email sign-in process.
@@ -67,7 +71,7 @@ class AuthService {
67
71
if (isDashboardLogin) {
68
72
final user = await _findUserByEmail (email);
69
73
if (user == null ) {
70
- print ('Dashboard login failed: User $email not found.' );
74
+ _log. warning ('Dashboard login failed: User $email not found.' );
71
75
throw const UnauthorizedException (
72
76
'This email address is not registered for dashboard access.' ,
73
77
);
@@ -77,14 +81,14 @@ class AuthService {
77
81
user.dashboardRole == DashboardUserRole .publisher;
78
82
79
83
if (! hasRequiredRole) {
80
- print (
84
+ _log. warning (
81
85
'Dashboard login failed: User ${user .id } lacks required roles.' ,
82
86
);
83
87
throw const ForbiddenException (
84
88
'Your account does not have the required permissions to sign in.' ,
85
89
);
86
90
}
87
- print ('Dashboard user ${user .id } verified successfully.' );
91
+ _log. info ('Dashboard user ${user .id } verified successfully.' );
88
92
}
89
93
90
94
// Generate and store the code for standard sign-in
@@ -93,13 +97,13 @@ class AuthService {
93
97
94
98
// Send the code via email
95
99
await _emailRepository.sendOtpEmail (recipientEmail: email, otpCode: code);
96
- print ('Initiated email sign-in for $email , code sent.' );
100
+ _log. info ('Initiated email sign-in for $email , code sent.' );
97
101
} on HtHttpException {
98
102
// Propagate known exceptions from dependencies
99
103
rethrow ;
100
104
} catch (e) {
101
105
// Catch unexpected errors during orchestration
102
- print ('Error during initiateEmailSignIn for $email : $e ' );
106
+ _log. severe ('Error during initiateEmailSignIn for $email : $e ' );
103
107
throw const OperationFailedException (
104
108
'Failed to initiate email sign-in process.' ,
105
109
);
@@ -140,7 +144,7 @@ class AuthService {
140
144
await _verificationCodeStorageService.clearSignInCode (email);
141
145
} catch (e) {
142
146
// Log or handle if clearing fails, but don't let it block sign-in
143
- print (
147
+ _log. warning (
144
148
'Warning: Failed to clear sign-in code for $email after validation: $e ' ,
145
149
);
146
150
}
@@ -157,14 +161,14 @@ class AuthService {
157
161
if (isDashboardLogin) {
158
162
// This should not happen if the request-code flow is correct.
159
163
// It's a safeguard.
160
- print (
164
+ _log. severe (
161
165
'Error: Dashboard login verification failed for non-existent user $email .' ,
162
166
);
163
167
throw const UnauthorizedException ('User account does not exist.' );
164
168
}
165
169
166
170
// Create a new user for the standard app flow.
167
- print ('User not found for $email , creating new user.' );
171
+ _log. info ('User not found for $email , creating new user.' );
168
172
169
173
// All new users created via the public API get the standard role.
170
174
// Admin users must be provisioned out-of-band (e.g., via fixtures).
@@ -184,7 +188,7 @@ class AuthService {
184
188
),
185
189
);
186
190
user = await _userRepository.create (item: user);
187
- print (
191
+ _log. info (
188
192
'Created new user: ${user .id } with appRole: ${user .appRole }' ,
189
193
);
190
194
@@ -194,33 +198,33 @@ class AuthService {
194
198
item: defaultAppSettings,
195
199
userId: user.id,
196
200
);
197
- print ('Created default UserAppSettings for user: ${user .id }' );
201
+ _log. info ('Created default UserAppSettings for user: ${user .id }' );
198
202
199
203
// Create default UserContentPreferences for the new user
200
204
final defaultUserPreferences = UserContentPreferences (id: user.id);
201
205
await _userContentPreferencesRepository.create (
202
206
item: defaultUserPreferences,
203
207
userId: user.id,
204
208
);
205
- print ('Created default UserContentPreferences for user: ${user .id }' );
209
+ _log. info ('Created default UserContentPreferences for user: ${user .id }' );
206
210
}
207
211
} on HtHttpException catch (e) {
208
- print ('Error finding/creating user for $email : $e ' );
212
+ _log. severe ('Error finding/creating user for $email : $e ' );
209
213
throw const OperationFailedException (
210
214
'Failed to find or create user account.' ,
211
215
);
212
216
} catch (e) {
213
- print ('Unexpected error during user lookup/creation for $email : $e ' );
217
+ _log. severe ('Unexpected error during user lookup/creation for $email : $e ' );
214
218
throw const OperationFailedException ('Failed to process user account.' );
215
219
}
216
220
217
221
// 3. Generate authentication token
218
222
try {
219
223
final token = await _authTokenService.generateToken (user);
220
- print ('Generated token for user ${user .id }' );
224
+ _log. info ('Generated token for user ${user .id }' );
221
225
return (user: user, token: token);
222
226
} catch (e) {
223
- print ('Error generating token for user ${user .id }: $e ' );
227
+ _log. severe ('Error generating token for user ${user .id }: $e ' );
224
228
throw const OperationFailedException (
225
229
'Failed to generate authentication token.' ,
226
230
);
@@ -254,12 +258,12 @@ class AuthService {
254
258
),
255
259
);
256
260
user = await _userRepository.create (item: user);
257
- print ('Created anonymous user: ${user .id }' );
261
+ _log. info ('Created anonymous user: ${user .id }' );
258
262
} on HtHttpException catch (e) {
259
- print ('Error creating anonymous user: $e ' );
263
+ _log. severe ('Error creating anonymous user: $e ' );
260
264
throw const OperationFailedException ('Failed to create anonymous user.' );
261
265
} catch (e) {
262
- print ('Unexpected error during anonymous user creation: $e ' );
266
+ _log. severe ('Unexpected error during anonymous user creation: $e ' );
263
267
throw const OperationFailedException (
264
268
'Failed to process anonymous sign-in.' ,
265
269
);
@@ -271,25 +275,25 @@ class AuthService {
271
275
item: defaultAppSettings,
272
276
userId: user.id, // Pass user ID for scoping
273
277
);
274
- print ('Created default UserAppSettings for anonymous user: ${user .id }' );
278
+ _log. info ('Created default UserAppSettings for anonymous user: ${user .id }' );
275
279
276
280
// Create default UserContentPreferences for the new anonymous user
277
281
final defaultUserPreferences = UserContentPreferences (id: user.id);
278
282
await _userContentPreferencesRepository.create (
279
283
item: defaultUserPreferences,
280
284
userId: user.id, // Pass user ID for scoping
281
285
);
282
- print (
286
+ _log. info (
283
287
'Created default UserContentPreferences for anonymous user: ${user .id }' ,
284
288
);
285
289
286
290
// 2. Generate token
287
291
try {
288
292
final token = await _authTokenService.generateToken (user);
289
- print ('Generated token for anonymous user ${user .id }' );
293
+ _log. info ('Generated token for anonymous user ${user .id }' );
290
294
return (user: user, token: token);
291
295
} catch (e) {
292
- print ('Error generating token for anonymous user ${user .id }: $e ' );
296
+ _log. severe ('Error generating token for anonymous user ${user .id }: $e ' );
293
297
throw const OperationFailedException (
294
298
'Failed to generate authentication token.' ,
295
299
);
@@ -319,32 +323,32 @@ class AuthService {
319
323
required String userId,
320
324
required String token,
321
325
}) async {
322
- print (
323
- '[AuthService] Received request for server-side sign-out actions '
326
+ _log. info (
327
+ 'Received request for server-side sign-out actions '
324
328
'for user $userId .' ,
325
329
);
326
330
327
331
try {
328
332
// Invalidate the token using the AuthTokenService
329
333
await _authTokenService.invalidateToken (token);
330
- print (
331
- '[AuthService] Token invalidation logic executed for user $userId .' ,
334
+ _log. info (
335
+ 'Token invalidation logic executed for user $userId .' ,
332
336
);
333
337
} on HtHttpException catch (_) {
334
338
// Propagate known exceptions from the token service
335
339
rethrow ;
336
340
} catch (e) {
337
341
// Catch unexpected errors during token invalidation
338
- print (
339
- '[AuthService] Error during token invalidation for user $userId : $e ' ,
342
+ _log. severe (
343
+ 'Error during token invalidation for user $userId : $e ' ,
340
344
);
341
345
throw const OperationFailedException (
342
346
'Failed server-side sign-out: Token invalidation failed.' ,
343
347
);
344
348
}
345
349
346
- print (
347
- '[AuthService] Server-side sign-out actions complete for user $userId .' ,
350
+ _log. info (
351
+ 'Server-side sign-out actions complete for user $userId .' ,
348
352
);
349
353
}
350
354
@@ -396,13 +400,13 @@ class AuthService {
396
400
recipientEmail: emailToLink,
397
401
otpCode: code,
398
402
);
399
- print (
403
+ _log. info (
400
404
'Initiated email link for user ${anonymousUser .id } to email $emailToLink , code sent: $code .' ,
401
405
);
402
406
} on HtHttpException {
403
407
rethrow ;
404
408
} catch (e) {
405
- print (
409
+ _log. severe (
406
410
'Error during initiateLinkEmailProcess for user ${anonymousUser .id }, email $emailToLink : $e ' ,
407
411
);
408
412
throw OperationFailedException (
@@ -453,24 +457,24 @@ class AuthService {
453
457
id: updatedUser.id,
454
458
item: updatedUser,
455
459
);
456
- print (
460
+ _log. info (
457
461
'User ${permanentUser .id } successfully linked with email $linkedEmail .' ,
458
462
);
459
463
460
464
// 3. Generate a new authentication token for the now-permanent user.
461
465
final newToken = await _authTokenService.generateToken (permanentUser);
462
- print ('Generated new token for linked user ${permanentUser .id }' );
466
+ _log. info ('Generated new token for linked user ${permanentUser .id }' );
463
467
464
468
// 4. Invalidate the old anonymous token.
465
469
try {
466
470
await _authTokenService.invalidateToken (oldAnonymousToken);
467
- print (
471
+ _log. info (
468
472
'Successfully invalidated old anonymous token for user ${permanentUser .id }.' ,
469
473
);
470
474
} catch (e) {
471
475
// Log error but don't fail the whole linking process if invalidation fails.
472
476
// The new token is more important.
473
- print (
477
+ _log. warning (
474
478
'Warning: Failed to invalidate old anonymous token for user ${permanentUser .id }: $e ' ,
475
479
);
476
480
}
@@ -479,7 +483,7 @@ class AuthService {
479
483
try {
480
484
await _verificationCodeStorageService.clearLinkCode (anonymousUser.id);
481
485
} catch (e) {
482
- print (
486
+ _log. warning (
483
487
'Warning: Failed to clear link code for user ${anonymousUser .id } after linking: $e ' ,
484
488
);
485
489
}
@@ -488,7 +492,7 @@ class AuthService {
488
492
} on HtHttpException {
489
493
rethrow ;
490
494
} catch (e) {
491
- print (
495
+ _log. severe (
492
496
'Error during completeLinkEmailProcess for user ${anonymousUser .id }: $e ' ,
493
497
);
494
498
throw OperationFailedException (
@@ -508,21 +512,21 @@ class AuthService {
508
512
try {
509
513
// Fetch the user first to get their email if needed for cleanup
510
514
final userToDelete = await _userRepository.read (id: userId);
511
- print ( '[AuthService] Found user ${userToDelete .id } for deletion.' );
515
+ _log. info ( ' Found user ${userToDelete .id } for deletion.' );
512
516
513
517
// 1. Delete the user record from the repository.
514
518
// This implicitly invalidates tokens that rely on user lookup.
515
519
await _userRepository.delete (id: userId);
516
- print ( '[AuthService] User ${userToDelete .id } deleted from repository.' );
520
+ _log. info ( ' User ${userToDelete .id } deleted from repository.' );
517
521
518
522
// 2. Clear any pending verification codes for this user ID (linking).
519
523
try {
520
524
await _verificationCodeStorageService.clearLinkCode (userId);
521
- print ( '[AuthService] Cleared link code for user ${userToDelete .id }.' );
525
+ _log. info ( ' Cleared link code for user ${userToDelete .id }.' );
522
526
} catch (e) {
523
527
// Log but don't fail deletion if clearing codes fails
524
- print (
525
- '[AuthService] Warning: Failed to clear link code for user ${userToDelete .id }: $e ' ,
528
+ _log. warning (
529
+ 'Warning: Failed to clear link code for user ${userToDelete .id }: $e ' ,
526
530
);
527
531
}
528
532
@@ -532,13 +536,13 @@ class AuthService {
532
536
await _verificationCodeStorageService.clearSignInCode (
533
537
userToDelete.email! ,
534
538
);
535
- print (
536
- '[AuthService] Cleared sign-in code for email ${userToDelete .email }.' ,
539
+ _log. info (
540
+ 'Cleared sign-in code for email ${userToDelete .email }.' ,
537
541
);
538
542
} catch (e) {
539
543
// Log but don't fail deletion if clearing codes fails
540
- print (
541
- '[AuthService] Warning: Failed to clear sign-in code for email ${userToDelete .email }: $e ' ,
544
+ _log. warning (
545
+ 'Warning: Failed to clear sign-in code for email ${userToDelete .email }: $e ' ,
542
546
);
543
547
}
544
548
}
@@ -547,8 +551,8 @@ class AuthService {
547
551
// user-related data (e.g., settings, content) from other repositories
548
552
// once those features are implemented.
549
553
550
- print (
551
- '[AuthService] Account deletion process completed for user $userId .' ,
554
+ _log. info (
555
+ 'Account deletion process completed for user $userId .' ,
552
556
);
553
557
} on NotFoundException {
554
558
// Propagate NotFoundException if user doesn't exist
@@ -558,7 +562,7 @@ class AuthService {
558
562
rethrow ;
559
563
} catch (e) {
560
564
// Catch unexpected errors during orchestration
561
- print ('Error during deleteAccount for user $userId : $e ' );
565
+ _log. severe ('Error during deleteAccount for user $userId : $e ' );
562
566
throw OperationFailedException ('Failed to delete user account: $e ' );
563
567
}
564
568
}
0 commit comments