@@ -3,14 +3,16 @@ use axum::Json;
3
3
use axum_extra:: json;
4
4
use axum_extra:: response:: ErasedJson ;
5
5
use diesel:: prelude:: * ;
6
- use diesel_async:: { AsyncPgConnection , RunQueryDsl } ;
6
+ use diesel_async:: scoped_futures:: ScopedFutureExt ;
7
+ use diesel_async:: { AsyncConnection , AsyncPgConnection , RunQueryDsl } ;
7
8
use http:: request:: Parts ;
8
9
use oauth2:: { AuthorizationCode , CsrfToken , Scope , TokenResponse } ;
9
10
10
11
use crate :: app:: AppState ;
12
+ use crate :: controllers:: user:: update:: UserConfirmEmail ;
11
13
use crate :: email:: Emails ;
12
14
use crate :: middleware:: log_request:: RequestLogExt ;
13
- use crate :: models:: { NewUser , User } ;
15
+ use crate :: models:: { NewEmail , NewUser , User } ;
14
16
use crate :: schema:: users;
15
17
use crate :: util:: diesel:: is_read_only_error;
16
18
use crate :: util:: errors:: { bad_request, server_error, AppResult } ;
@@ -148,10 +150,7 @@ pub async fn save_user_to_database(
148
150
. gh_access_token ( access_token)
149
151
. build ( ) ;
150
152
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 {
155
154
Ok ( user) => Ok ( user) ,
156
155
Err ( error) if is_read_only_error ( & error) => {
157
156
// If we're in read only mode, we can't update their details
@@ -162,6 +161,45 @@ pub async fn save_user_to_database(
162
161
}
163
162
}
164
163
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
+
165
203
async fn find_user_by_gh_id ( conn : & mut AsyncPgConnection , gh_id : i32 ) -> QueryResult < Option < User > > {
166
204
users:: table
167
205
. filter ( users:: gh_id. eq ( gh_id) )
0 commit comments