Skip to content

Commit 99f92f3

Browse files
committed
models/user: Move NewUser::create_or_update() fn into controller code
The database access code should not send emails...
1 parent 43acb28 commit 99f92f3

File tree

2 files changed

+47
-51
lines changed

2 files changed

+47
-51
lines changed

src/controllers/session.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ use axum::Json;
33
use axum_extra::json;
44
use axum_extra::response::ErasedJson;
55
use diesel::prelude::*;
6-
use diesel_async::{AsyncPgConnection, RunQueryDsl};
6+
use diesel_async::scoped_futures::ScopedFutureExt;
7+
use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
78
use http::request::Parts;
89
use oauth2::{AuthorizationCode, CsrfToken, Scope, TokenResponse};
910

1011
use crate::app::AppState;
12+
use crate::controllers::user::update::UserConfirmEmail;
1113
use crate::email::Emails;
1214
use crate::middleware::log_request::RequestLogExt;
13-
use crate::models::{NewUser, User};
15+
use crate::models::{NewEmail, NewUser, User};
1416
use crate::schema::users;
1517
use crate::util::diesel::is_read_only_error;
1618
use 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+
165203
async 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))

src/models/user.rs

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@ use diesel::dsl::sql;
44
use diesel::prelude::*;
55
use diesel::sql_types::Integer;
66
use diesel::upsert::excluded;
7-
use diesel_async::scoped_futures::ScopedFutureExt;
8-
use diesel_async::{AsyncConnection, AsyncPgConnection, RunQueryDsl};
7+
use diesel_async::{AsyncPgConnection, RunQueryDsl};
98

109
use crate::app::App;
11-
use crate::controllers::user::update::UserConfirmEmail;
12-
use crate::email::Emails;
1310
use crate::util::errors::AppResult;
1411

15-
use crate::models::{Crate, CrateOwner, Email, NewEmail, Owner, OwnerKind, Rights};
12+
use crate::models::{Crate, CrateOwner, Email, Owner, OwnerKind, Rights};
1613
use crate::schema::{crate_owners, emails, users};
1714
use crates_io_diesel_helpers::lower;
1815

@@ -120,7 +117,7 @@ pub struct NewUser<'a> {
120117
pub gh_access_token: &'a str,
121118
}
122119

123-
impl<'a> NewUser<'a> {
120+
impl NewUser<'_> {
124121
/// Inserts the user into the database, or fails if the user already exists.
125122
pub async fn insert(&self, conn: &mut AsyncPgConnection) -> QueryResult<User> {
126123
diesel::insert_into(users::table)
@@ -152,43 +149,4 @@ impl<'a> NewUser<'a> {
152149
.get_result(conn)
153150
.await
154151
}
155-
156-
/// Inserts the user into the database, or updates an existing one.
157-
///
158-
/// This method also inserts the email address into the `emails` table
159-
/// and sends a confirmation email to the user.
160-
pub async fn create_or_update(
161-
&self,
162-
email: Option<&'a str>,
163-
emails: &Emails,
164-
conn: &mut AsyncPgConnection,
165-
) -> QueryResult<User> {
166-
conn.transaction(|conn| {
167-
async move {
168-
let user = self.insert_or_update(conn).await?;
169-
170-
// To send the user an account verification email
171-
if let Some(user_email) = email {
172-
let new_email = NewEmail::builder()
173-
.user_id(user.id)
174-
.email(user_email)
175-
.build();
176-
177-
if let Some(token) = new_email.insert_if_missing(conn).await? {
178-
// Swallows any error. Some users might insert an invalid email address here.
179-
let email = UserConfirmEmail {
180-
user_name: &user.gh_login,
181-
domain: &emails.domain,
182-
token,
183-
};
184-
let _ = emails.send(user_email, email).await;
185-
}
186-
}
187-
188-
Ok(user)
189-
}
190-
.scope_boxed()
191-
})
192-
.await
193-
}
194152
}

0 commit comments

Comments
 (0)