@@ -7,14 +7,14 @@ mod tests;
77
88use axum_login:: AuthUser as AxumLoginAuthUser ;
99pub use axum_login:: AuthnBackend ;
10- use db:: { Database , FetchModelByIndexError , FetchModelError , kv:: LaxSlug } ;
11- use miette:: { IntoDiagnostic , miette} ;
10+ use miette:: { Context , IntoDiagnostic , miette} ;
1211use models:: {
1312 AuthUser , Org , OrgIdent , User , UserAuthCredentials ,
14- UserSubmittedAuthCredentials , UserUniqueIndexSelector ,
15- dvf:: { EitherSlug , EmailAddress , HumanName } ,
13+ UserSubmittedAuthCredentials ,
14+ dvf:: { EmailAddress , HumanName } ,
1615 model:: RecordId ,
1716} ;
17+ pub use mutate_domain:: UpdateActiveOrgError ;
1818
1919pub use self :: errors:: * ;
2020
@@ -24,70 +24,29 @@ pub type AuthSession = axum_login::AuthSession<AuthDomainService>;
2424/// A dynamic [`AuthDomainService`] trait object.
2525#[ derive( Clone , Debug ) ]
2626pub struct AuthDomainService {
27- org_repo : Database < Org > ,
28- user_repo : Database < User > ,
27+ meta : meta_domain :: MetaService ,
28+ mutate : mutate_domain :: MutationService ,
2929}
3030
3131impl AuthDomainService {
3232 /// Creates a new [`AuthDomainService`].
3333 #[ must_use]
34- pub fn new ( org_repo : Database < Org > , user_repo : Database < User > ) -> Self {
35- Self {
36- org_repo ,
37- user_repo ,
38- }
34+ pub fn new (
35+ meta : meta_domain :: MetaService ,
36+ mutate : mutate_domain :: MutationService ,
37+ ) -> Self {
38+ Self { meta , mutate }
3939 }
4040}
4141
4242impl AuthDomainService {
43- /// Fetch a [`User`] by ID.
44- async fn fetch_user_by_id (
45- & self ,
46- id : RecordId < User > ,
47- ) -> Result < Option < User > , FetchModelError > {
48- self . user_repo . fetch_model_by_id ( id) . await
49- }
50-
51- /// Fetch a [`User`] by [`EmailAddress`](EmailAddress).
52- async fn fetch_user_by_email (
53- & self ,
54- email : EmailAddress ,
55- ) -> Result < Option < User > , FetchModelByIndexError > {
56- self
57- . user_repo
58- . fetch_model_by_unique_index (
59- UserUniqueIndexSelector :: Email ,
60- EitherSlug :: Lax ( LaxSlug :: new ( email. as_ref ( ) ) ) ,
61- )
62- . await
63- }
64-
65- /// Switch a [`User`]'s active org.
43+ /// Switches the active org of a [`User`].
6644 pub async fn switch_active_org (
6745 & self ,
6846 user : RecordId < User > ,
6947 new_active_org : RecordId < Org > ,
70- ) -> Result < RecordId < Org > , errors:: UpdateActiveOrgError > {
71- let user = self
72- . user_repo
73- . fetch_model_by_id ( user)
74- . await ?
75- . ok_or ( errors:: UpdateActiveOrgError :: MissingUser ( user) ) ?;
76-
77- let new_index = user
78- . iter_orgs ( )
79- . position ( |o| o == new_active_org)
80- . ok_or ( errors:: UpdateActiveOrgError :: InvalidOrg ( new_active_org) ) ?;
81-
82- self
83- . user_repo
84- . patch_model ( user. id , User {
85- active_org_index : new_index as _ ,
86- ..user
87- } )
88- . await ?;
89-
90- Ok ( new_active_org)
48+ ) -> Result < RecordId < Org > , UpdateActiveOrgError > {
49+ self . mutate . switch_active_org ( user, new_active_org) . await
9150 }
9251
9352 /// Sign up a [`User`].
@@ -99,7 +58,15 @@ impl AuthDomainService {
9958 ) -> Result < User , errors:: CreateUserError > {
10059 use argon2:: PasswordHasher ;
10160
102- if self . fetch_user_by_email ( email. clone ( ) ) . await ?. is_some ( ) {
61+ if self
62+ . meta
63+ . fetch_user_by_email ( email. clone ( ) )
64+ . await
65+ . into_diagnostic ( )
66+ . context ( "failed to check for conflicting user by email" )
67+ . map_err ( CreateUserError :: InternalError ) ?
68+ . is_some ( )
69+ {
10370 return Err ( errors:: CreateUserError :: EmailAlreadyUsed ( email) ) ;
10471 }
10572
@@ -113,8 +80,8 @@ impl AuthDomainService {
11380 argon
11481 . hash_password ( password. as_bytes ( ) , & salt)
11582 . map_err ( |e| {
116- errors :: CreateUserError :: PasswordHashing ( miette ! (
117- "failed to hash password: {e}"
83+ CreateUserError :: InternalError ( miette ! (
84+ "failed to parse password hash : {e}"
11885 ) )
11986 } ) ?
12087 . to_string ( ) ,
@@ -143,29 +110,40 @@ impl AuthDomainService {
143110 } ;
144111
145112 self
146- . org_repo
147- . create_model ( org)
113+ . mutate
114+ . create_org ( org)
148115 . await
149116 . into_diagnostic ( )
150- . map_err ( errors:: CreateUserError :: CreateError ) ?;
117+ . context ( "failed to create personal org for user" )
118+ . map_err ( errors:: CreateUserError :: InternalError ) ?;
151119
152120 self
153- . user_repo
154- . create_model ( user)
121+ . mutate
122+ . create_user ( user. clone ( ) )
155123 . await
156124 . into_diagnostic ( )
157- . map_err ( errors:: CreateUserError :: CreateError )
125+ . context ( "failed to create user" )
126+ . map_err ( errors:: CreateUserError :: InternalError ) ?;
127+
128+ Ok ( user)
158129 }
159130
160131 /// Authenticate a [`User`].
161132 pub async fn user_authenticate (
162133 & self ,
163134 email : EmailAddress ,
164135 creds : UserSubmittedAuthCredentials ,
165- ) -> Result < Option < User > , errors :: AuthenticationError > {
136+ ) -> Result < Option < User > , AuthenticationError > {
166137 use argon2:: PasswordVerifier ;
167138
168- let Some ( user) = self . fetch_user_by_email ( email) . await ? else {
139+ let Some ( user) = self
140+ . meta
141+ . fetch_user_by_email ( email)
142+ . await
143+ . into_diagnostic ( )
144+ . context ( "failed to fetch user by email" )
145+ . map_err ( AuthenticationError ) ?
146+ else {
169147 return Ok ( None ) ;
170148 } ;
171149
@@ -176,9 +154,7 @@ impl AuthDomainService {
176154 ) => {
177155 let password_hash = argon2:: PasswordHash :: new ( & password_hash. 0 )
178156 . map_err ( |e| {
179- errors:: AuthenticationError :: PasswordHashing ( miette ! (
180- "failed to parse password hash: {e}"
181- ) )
157+ AuthenticationError ( miette ! ( "failed to parse password hash: {e}" ) )
182158 } ) ?;
183159
184160 let argon = argon2:: Argon2 :: default ( ) ;
@@ -189,7 +165,7 @@ impl AuthDomainService {
189165 Err ( e) => Err ( e) ,
190166 } )
191167 . map_err ( |e| {
192- errors :: AuthenticationError :: PasswordHashing ( miette ! (
168+ AuthenticationError ( miette ! (
193169 "failed to verify password against hash: {e}"
194170 ) )
195171 } ) ?;
@@ -220,9 +196,11 @@ impl AuthnBackend for AuthDomainService {
220196 id : & <Self :: User as AxumLoginAuthUser >:: Id ,
221197 ) -> Result < Option < Self :: User > , Self :: Error > {
222198 self
199+ . meta
223200 . fetch_user_by_id ( * id)
224201 . await
202+ . into_diagnostic ( )
225203 . map ( |u| u. map ( Into :: into) )
226- . map_err ( Into :: into )
204+ . map_err ( AuthenticationError )
227205 }
228206}
0 commit comments