Skip to content

Commit e356f14

Browse files
committed
refactor: use RepositoryContext
1 parent 9580631 commit e356f14

File tree

14 files changed

+667
-478
lines changed

14 files changed

+667
-478
lines changed

crates/infera-management-api/src/handlers/audit_logs.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use axum::{
77
use chrono::{DateTime, Utc};
88
use infera_management_core::{
99
entities::{AuditEventType, AuditLog, AuditResourceType},
10-
AuditLogFilters, AuditLogRepository,
10+
AuditLogFilters, RepositoryContext,
1111
};
1212
use serde::{Deserialize, Serialize};
1313

@@ -42,7 +42,7 @@ pub async fn create_audit_log(
4242
State(state): State<AppState>,
4343
Json(payload): Json<CreateAuditLogRequest>,
4444
) -> Response {
45-
let repo = AuditLogRepository::new((*state.storage).clone());
45+
let repos = RepositoryContext::new((*state.storage).clone());
4646

4747
// Build audit log entry
4848
let mut log = AuditLog::new(payload.event_type, payload.organization_id, payload.user_id);
@@ -67,7 +67,7 @@ pub async fn create_audit_log(
6767
log = log.with_user_agent(ua);
6868
}
6969

70-
match repo.create(log).await {
70+
match repos.audit_log.create(log).await {
7171
Ok(_) => (
7272
StatusCode::CREATED,
7373
Json(CreateAuditLogResponse { success: true }),
@@ -162,8 +162,9 @@ pub async fn list_audit_logs(
162162
};
163163

164164
// Query audit logs
165-
let audit_repo = AuditLogRepository::new((*state.storage).clone());
166-
match audit_repo
165+
let repos = RepositoryContext::new((*state.storage).clone());
166+
match repos
167+
.audit_log
167168
.list_by_organization(org_ctx.organization_id, filters, limit, offset)
168169
.await
169170
{

crates/infera-management-api/src/handlers/auth.rs

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ use infera_management_core::{
1111
UserEmail, UserEmailVerificationToken, UserSession,
1212
},
1313
error::Error as CoreError,
14-
hash_password, verify_password, IdGenerator, OrganizationMemberRepository,
15-
OrganizationRepository, UserEmailRepository, UserEmailVerificationTokenRepository,
16-
UserPasswordResetToken, UserPasswordResetTokenRepository, UserRepository,
17-
UserSessionRepository,
14+
hash_password, verify_password, IdGenerator, RepositoryContext, UserPasswordResetToken,
1815
};
1916
use infera_management_grpc::ServerApiClient;
2017
use infera_management_storage::Backend;
@@ -258,6 +255,9 @@ pub async fn register(
258255
jar: CookieJar,
259256
Json(payload): Json<RegisterRequest>,
260257
) -> Result<(CookieJar, Json<RegisterResponse>)> {
258+
// Initialize repository context
259+
let repos = RepositoryContext::new((*state.storage).clone());
260+
261261
// Validate inputs
262262
if payload.name.trim().is_empty() {
263263
return Err(CoreError::Validation("Name cannot be empty".to_string()).into());
@@ -268,16 +268,14 @@ pub async fn register(
268268
}
269269

270270
// Check if email is already in use
271-
let email_repo = UserEmailRepository::new((*state.storage).clone());
272-
if email_repo.is_email_in_use(&payload.email).await? {
271+
if repos.user_email.is_email_in_use(&payload.email).await? {
273272
return Err(
274273
CoreError::Validation(format!("Email '{}' is already in use", payload.email)).into(),
275274
);
276275
}
277276

278277
// Check if name is available
279-
let user_repo = UserRepository::new((*state.storage).clone());
280-
if !user_repo.is_name_available(&payload.name).await? {
278+
if !repos.user.is_name_available(&payload.name).await? {
281279
return Err(
282280
CoreError::Validation(format!("Name '{}' is already taken", payload.name)).into(),
283281
);
@@ -294,18 +292,20 @@ pub async fn register(
294292
// Create user
295293
let mut user = User::new(user_id, payload.name.clone(), Some(password_hash))?;
296294
user.accept_tos(); // Auto-accept TOS on registration
297-
user_repo.create(user).await?;
295+
repos.user.create(user).await?;
298296

299297
// Create email (unverified)
300298
let email = UserEmail::new(email_id, user_id, payload.email.clone(), true)?;
301-
email_repo.create(email.clone()).await?;
299+
repos.user_email.create(email.clone()).await?;
302300

303301
// Create email verification token
304302
let token_id = IdGenerator::next_id();
305303
let token_string = UserEmailVerificationToken::generate_token();
306304
let verification_token = UserEmailVerificationToken::new(token_id, email_id, token_string)?;
307-
let verification_repo = UserEmailVerificationTokenRepository::new((*state.storage).clone());
308-
verification_repo.create(verification_token.clone()).await?;
305+
repos
306+
.user_email_verification_token
307+
.create(verification_token.clone())
308+
.await?;
309309

310310
// Send verification email (fire-and-forget - don't block registration)
311311
if let Some(email_service) = &state.email_service {
@@ -348,22 +348,19 @@ pub async fn register(
348348

349349
// Create session
350350
let session = UserSession::new(session_id, user_id, SessionType::Web, None, None);
351-
let session_repo = UserSessionRepository::new((*state.storage).clone());
352-
session_repo.create(session).await?;
351+
repos.user_session.create(session).await?;
353352

354353
// Create default organization with same name as user
355354
let org_id = IdGenerator::next_id();
356355
let member_id = IdGenerator::next_id();
357356

358357
let organization =
359358
Organization::new(org_id, payload.name.clone(), OrganizationTier::TierDevV1)?;
360-
let org_repo = OrganizationRepository::new((*state.storage).clone());
361-
org_repo.create(organization).await?;
359+
repos.org.create(organization).await?;
362360

363361
// Create organization member (owner role)
364362
let member = OrganizationMember::new(member_id, org_id, user_id, OrganizationRole::Owner);
365-
let member_repo = OrganizationMemberRepository::new((*state.storage).clone());
366-
member_repo.create(member).await?;
363+
repos.org_member.create(member).await?;
367364

368365
// Set session cookie
369366
let cookie = Cookie::build((SESSION_COOKIE_NAME, session_id.to_string()))
@@ -398,16 +395,18 @@ pub async fn login(
398395
jar: CookieJar,
399396
Json(payload): Json<LoginRequest>,
400397
) -> Result<(CookieJar, Json<LoginResponse>)> {
398+
let repos = RepositoryContext::new((*state.storage).clone());
399+
401400
// Find user by email
402-
let email_repo = UserEmailRepository::new((*state.storage).clone());
403-
let email = email_repo
401+
let email = repos
402+
.user_email
404403
.get_by_email(&payload.email)
405404
.await?
406405
.ok_or_else(|| CoreError::Auth("Invalid email or password".to_string()))?;
407406

408407
// Get user
409-
let user_repo = UserRepository::new((*state.storage).clone());
410-
let user = user_repo
408+
let user = repos
409+
.user
411410
.get(email.user_id)
412411
.await?
413412
.ok_or_else(|| CoreError::Auth("Invalid email or password".to_string()))?;
@@ -422,8 +421,7 @@ pub async fn login(
422421
// Create session
423422
let session_id = IdGenerator::next_id();
424423
let session = UserSession::new(session_id, user.id, SessionType::Web, None, None);
425-
let session_repo = UserSessionRepository::new((*state.storage).clone());
426-
session_repo.create(session).await?;
424+
repos.user_session.create(session).await?;
427425

428426
// Set session cookie
429427
let cookie = Cookie::build((SESSION_COOKIE_NAME, session_id.to_string()))
@@ -458,10 +456,10 @@ pub async fn logout(
458456
// Get session ID from cookie
459457
if let Some(cookie) = jar.get(SESSION_COOKIE_NAME) {
460458
if let Ok(session_id) = cookie.value().parse::<i64>() {
459+
let repos = RepositoryContext::new((*state.storage).clone());
461460
// Revoke session
462-
let session_repo = UserSessionRepository::new((*state.storage).clone());
463461
// Ignore errors if session doesn't exist
464-
let _ = session_repo.revoke(session_id).await;
462+
let _ = repos.user_session.revoke(session_id).await;
465463
}
466464
}
467465

@@ -501,10 +499,11 @@ pub async fn verify_email(
501499
State(state): State<AppState>,
502500
Json(payload): Json<VerifyEmailRequest>,
503501
) -> Result<Json<VerifyEmailResponse>> {
504-
let token_repo = UserEmailVerificationTokenRepository::new((*state.storage).clone());
502+
let repos = RepositoryContext::new((*state.storage).clone());
505503

506504
// Get token
507-
let mut token = token_repo
505+
let mut token = repos
506+
.user_email_verification_token
508507
.get_by_token(&payload.token)
509508
.await?
510509
.ok_or_else(|| {
@@ -519,8 +518,8 @@ pub async fn verify_email(
519518
}
520519

521520
// Get the email
522-
let email_repo = UserEmailRepository::new((*state.storage).clone());
523-
let mut email = email_repo
521+
let mut email = repos
522+
.user_email
524523
.get(token.user_email_id)
525524
.await?
526525
.ok_or_else(|| CoreError::NotFound("Email not found".to_string()))?;
@@ -535,11 +534,11 @@ pub async fn verify_email(
535534

536535
// Mark email as verified
537536
email.verify();
538-
email_repo.update(email.clone()).await?;
537+
repos.user_email.update(email.clone()).await?;
539538

540539
// Mark token as used
541540
token.mark_used();
542-
token_repo.update(token).await?;
541+
repos.user_email_verification_token.update(token).await?;
543542

544543
Ok(Json(VerifyEmailResponse {
545544
message: "Email verified successfully".to_string(),
@@ -570,11 +569,11 @@ pub async fn request_password_reset(
570569
State(state): State<AppState>,
571570
Json(payload): Json<PasswordResetRequestRequest>,
572571
) -> Result<Json<PasswordResetRequestResponse>> {
573-
let email_repo = UserEmailRepository::new((*state.storage).clone());
574-
let user_repo = UserRepository::new((*state.storage).clone());
572+
let repos = RepositoryContext::new((*state.storage).clone());
575573

576574
// Find the email
577-
let email = email_repo
575+
let email = repos
576+
.user_email
578577
.get_by_email(&payload.email)
579578
.await?
580579
.ok_or_else(|| {
@@ -590,7 +589,8 @@ pub async fn request_password_reset(
590589
}
591590

592591
// Get the user to ensure they exist and aren't deleted
593-
let user = user_repo
592+
let user = repos
593+
.user
594594
.get(email.user_id)
595595
.await?
596596
.ok_or_else(|| CoreError::NotFound("User not found".to_string()))?;
@@ -600,13 +600,12 @@ pub async fn request_password_reset(
600600
}
601601

602602
// Generate password reset token
603-
let token_repo = UserPasswordResetTokenRepository::new((*state.storage).clone());
604603
let token_id = IdGenerator::next_id();
605604
let token_string = UserPasswordResetToken::generate_token();
606605
let reset_token = UserPasswordResetToken::new(token_id, user.id, token_string.clone())?;
607606

608607
// Store the token
609-
token_repo.create(reset_token).await?;
608+
repos.user_password_reset_token.create(reset_token).await?;
610609

611610
// Send password reset email (fire-and-forget - don't block request)
612611
if let Some(email_service) = &state.email_service {
@@ -687,10 +686,11 @@ pub async fn confirm_password_reset(
687686
.into());
688687
}
689688

690-
let token_repo = UserPasswordResetTokenRepository::new((*state.storage).clone());
689+
let repos = RepositoryContext::new((*state.storage).clone());
691690

692691
// Get token
693-
let mut token = token_repo
692+
let mut token = repos
693+
.user_password_reset_token
694694
.get_by_token(&payload.token)
695695
.await?
696696
.ok_or_else(|| CoreError::Validation("Invalid or expired reset token".to_string()))?;
@@ -701,8 +701,8 @@ pub async fn confirm_password_reset(
701701
}
702702

703703
// Get the user
704-
let user_repo = UserRepository::new((*state.storage).clone());
705-
let mut user = user_repo
704+
let mut user = repos
705+
.user
706706
.get(token.user_id)
707707
.await?
708708
.ok_or_else(|| CoreError::NotFound("User not found".to_string()))?;
@@ -716,16 +716,15 @@ pub async fn confirm_password_reset(
716716

717717
// Update user's password
718718
user.set_password_hash(password_hash);
719-
user_repo.update(user).await?;
719+
repos.user.update(user).await?;
720720

721721
// Mark token as used
722722
let user_id = token.user_id;
723723
token.mark_used();
724-
token_repo.update(token).await?;
724+
repos.user_password_reset_token.update(token).await?;
725725

726726
// Invalidate all user sessions for security
727-
let session_repo = UserSessionRepository::new((*state.storage).clone());
728-
session_repo.revoke_user_sessions(user_id).await?;
727+
repos.user_session.revoke_user_sessions(user_id).await?;
729728
tracing::info!(
730729
"Password reset successfully for user {} - all sessions revoked",
731730
user_id
@@ -942,15 +941,16 @@ mod tests {
942941
app.clone().oneshot(register_request).await.unwrap();
943942

944943
// Manually verify the email since we don't have email sending
945-
let email_repo = UserEmailRepository::new((*storage).clone());
946-
let mut email = email_repo
944+
let repos = RepositoryContext::new((*storage).clone());
945+
let mut email = repos
946+
.user_email
947947
.get_by_email("alice@example.com")
948948
.await
949949
.unwrap()
950950
.unwrap();
951951
let user_id = email.user_id;
952952
email.verify();
953-
email_repo.update(email).await.unwrap();
953+
repos.user_email.update(email).await.unwrap();
954954

955955
// Request password reset
956956
let reset_request = axum::http::Request::builder()
@@ -969,8 +969,11 @@ mod tests {
969969
assert_eq!(response.status(), StatusCode::OK);
970970

971971
// Get the reset token from the repository
972-
let token_repo = UserPasswordResetTokenRepository::new((*storage).clone());
973-
let tokens = token_repo.get_by_user(user_id).await.unwrap();
972+
let tokens = repos
973+
.user_password_reset_token
974+
.get_by_user(user_id)
975+
.await
976+
.unwrap();
974977
assert_eq!(tokens.len(), 1);
975978
let reset_token = tokens[0].token.clone();
976979

@@ -1077,18 +1080,18 @@ mod tests {
10771080
app.clone().oneshot(register_request).await.unwrap();
10781081

10791082
// Manually verify the email
1080-
let email_repo = UserEmailRepository::new((*storage).clone());
1081-
let mut email = email_repo
1083+
let repos = RepositoryContext::new((*storage).clone());
1084+
let mut email = repos
1085+
.user_email
10821086
.get_by_email("alice@example.com")
10831087
.await
10841088
.unwrap()
10851089
.unwrap();
10861090
let user_id = email.user_id;
10871091
email.verify();
1088-
email_repo.update(email).await.unwrap();
1092+
repos.user_email.update(email).await.unwrap();
10891093

10901094
// Create additional sessions to verify they all get revoked
1091-
let session_repo = UserSessionRepository::new((*storage).clone());
10921095
let session2 = UserSession::new(
10931096
IdGenerator::next_id(),
10941097
user_id,
@@ -1103,11 +1106,11 @@ mod tests {
11031106
None,
11041107
None,
11051108
);
1106-
session_repo.create(session2.clone()).await.unwrap();
1107-
session_repo.create(session3.clone()).await.unwrap();
1109+
repos.user_session.create(session2.clone()).await.unwrap();
1110+
repos.user_session.create(session3.clone()).await.unwrap();
11081111

11091112
// Verify we have 3 active sessions (1 from registration + 2 created)
1110-
let sessions_before = session_repo.get_user_sessions(user_id).await.unwrap();
1113+
let sessions_before = repos.user_session.get_user_sessions(user_id).await.unwrap();
11111114
let active_before: Vec<_> = sessions_before.iter().filter(|s| s.is_active()).collect();
11121115
assert_eq!(
11131116
active_before.len(),
@@ -1131,8 +1134,11 @@ mod tests {
11311134
app.clone().oneshot(reset_request).await.unwrap();
11321135

11331136
// Get the reset token
1134-
let token_repo = UserPasswordResetTokenRepository::new((*storage).clone());
1135-
let tokens = token_repo.get_by_user(user_id).await.unwrap();
1137+
let tokens = repos
1138+
.user_password_reset_token
1139+
.get_by_user(user_id)
1140+
.await
1141+
.unwrap();
11361142
let reset_token = tokens[0].token.clone();
11371143

11381144
// Confirm password reset
@@ -1153,7 +1159,7 @@ mod tests {
11531159
assert_eq!(response.status(), StatusCode::OK);
11541160

11551161
// Verify ALL sessions are now revoked
1156-
let sessions_after = session_repo.get_user_sessions(user_id).await.unwrap();
1162+
let sessions_after = repos.user_session.get_user_sessions(user_id).await.unwrap();
11571163
let active_after: Vec<_> = sessions_after.iter().filter(|s| s.is_active()).collect();
11581164
assert_eq!(
11591165
active_after.len(),

0 commit comments

Comments
 (0)