@@ -3,14 +3,16 @@ use axum::Json;
33use axum_extra:: json;
44use axum_extra:: response:: ErasedJson ;
55use diesel:: prelude:: * ;
6- use diesel_async:: { AsyncPgConnection , RunQueryDsl } ;
6+ use diesel_async:: scoped_futures:: ScopedFutureExt ;
7+ use diesel_async:: { AsyncConnection , AsyncPgConnection , RunQueryDsl } ;
78use http:: request:: Parts ;
89use oauth2:: { AuthorizationCode , CsrfToken , Scope , TokenResponse } ;
910
1011use crate :: app:: AppState ;
12+ use crate :: controllers:: user:: update:: UserConfirmEmail ;
1113use crate :: email:: Emails ;
1214use crate :: middleware:: log_request:: RequestLogExt ;
13- use crate :: models:: { NewUser , User } ;
15+ use crate :: models:: { NewEmail , NewUser , User } ;
1416use crate :: schema:: users;
1517use crate :: util:: diesel:: is_read_only_error;
1618use crate :: util:: errors:: { bad_request, server_error, AppResult } ;
@@ -148,10 +150,7 @@ pub async fn save_user_to_database(
148150 . gh_access_token ( access_token)
149151 . build ( ) ;
150152
151- match new_user
152- . create_or_update ( user. email . as_deref ( ) , emails, conn)
153- . await
154- {
153+ match create_or_update_user ( & new_user, user. email . as_deref ( ) , emails, conn) . await {
155154 Ok ( user) => Ok ( user) ,
156155 Err ( error) if is_read_only_error ( & error) => {
157156 // If we're in read only mode, we can't update their details
@@ -162,6 +161,45 @@ pub async fn save_user_to_database(
162161 }
163162}
164163
164+ /// Inserts the user into the database, or updates an existing one.
165+ ///
166+ /// This method also inserts the email address into the `emails` table
167+ /// and sends a confirmation email to the user.
168+ async fn create_or_update_user (
169+ new_user : & NewUser < ' _ > ,
170+ email : Option < & str > ,
171+ emails : & Emails ,
172+ conn : & mut AsyncPgConnection ,
173+ ) -> QueryResult < User > {
174+ conn. transaction ( |conn| {
175+ async move {
176+ let user = new_user. insert_or_update ( conn) . await ?;
177+
178+ // To send the user an account verification email
179+ if let Some ( user_email) = email {
180+ let new_email = NewEmail :: builder ( )
181+ . user_id ( user. id )
182+ . email ( user_email)
183+ . build ( ) ;
184+
185+ if let Some ( token) = new_email. insert_if_missing ( conn) . await ? {
186+ // Swallows any error. Some users might insert an invalid email address here.
187+ let email = UserConfirmEmail {
188+ user_name : & user. gh_login ,
189+ domain : & emails. domain ,
190+ token,
191+ } ;
192+ let _ = emails. send ( user_email, email) . await ;
193+ }
194+ }
195+
196+ Ok ( user)
197+ }
198+ . scope_boxed ( )
199+ } )
200+ . await
201+ }
202+
165203async fn find_user_by_gh_id ( conn : & mut AsyncPgConnection , gh_id : i32 ) -> QueryResult < Option < User > > {
166204 users:: table
167205 . filter ( users:: gh_id. eq ( gh_id) )
0 commit comments