From 16d11a039816f75e17758de04e034e639f44ad00 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Sat, 9 Nov 2024 21:12:02 +0800 Subject: [PATCH 1/3] models/crate_owner_invitation: Convert `find_by_id()` to async fn --- src/controllers/crate_owner_invitation.rs | 10 ++++++---- src/models/crate_owner_invitation.rs | 10 ++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index cffb8d7ad15..e5f9889b378 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -284,15 +284,17 @@ pub async fn handle_invite(state: AppState, req: BytesRequest) -> AppResult = &mut conn.into(); - let user_id = auth.user_id(); - let config = &state.config; - let invitation = CrateOwnerInvitation::find_by_id(user_id, crate_invite.crate_id, conn)?; if crate_invite.accepted { invitation.accept(conn, config)?; } else { diff --git a/src/models/crate_owner_invitation.rs b/src/models/crate_owner_invitation.rs index 07c753bacf2..496c25c8fe3 100644 --- a/src/models/crate_owner_invitation.rs +++ b/src/models/crate_owner_invitation.rs @@ -1,4 +1,5 @@ use chrono::{NaiveDateTime, Utc}; +use diesel_async::AsyncPgConnection; use http::StatusCode; use secrecy::SecretString; @@ -87,12 +88,17 @@ impl CrateOwnerInvitation { }) } - pub fn find_by_id(user_id: i32, crate_id: i32, conn: &mut impl Conn) -> QueryResult { - use diesel::RunQueryDsl; + pub async fn find_by_id( + user_id: i32, + crate_id: i32, + conn: &mut AsyncPgConnection, + ) -> QueryResult { + use diesel_async::RunQueryDsl; crate_owner_invitations::table .find((user_id, crate_id)) .first::(conn) + .await } pub fn find_by_token(token: &str, conn: &mut impl Conn) -> QueryResult { From a8b6da2dae410e9b1a21f06c682aa85ea1d9bbe8 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Sat, 9 Nov 2024 21:14:56 +0800 Subject: [PATCH 2/3] models/crate_owner_invitation: Convert `find_by_token()` to async fn --- src/controllers/crate_owner_invitation.rs | 4 ++-- src/models/crate_owner_invitation.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index e5f9889b378..15922cb490c 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -311,13 +311,13 @@ pub async fn handle_invite_with_token( state: AppState, Path(token): Path, ) -> AppResult> { - let conn = state.db_write().await?; + let mut conn = state.db_write().await?; + let invitation = CrateOwnerInvitation::find_by_token(&token, &mut conn).await?; spawn_blocking(move || { let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); let config = &state.config; - let invitation = CrateOwnerInvitation::find_by_token(&token, conn)?; let crate_id = invitation.crate_id; invitation.accept(conn, config)?; diff --git a/src/models/crate_owner_invitation.rs b/src/models/crate_owner_invitation.rs index 496c25c8fe3..69ee297634b 100644 --- a/src/models/crate_owner_invitation.rs +++ b/src/models/crate_owner_invitation.rs @@ -101,12 +101,13 @@ impl CrateOwnerInvitation { .await } - pub fn find_by_token(token: &str, conn: &mut impl Conn) -> QueryResult { - use diesel::RunQueryDsl; + pub async fn find_by_token(token: &str, conn: &mut AsyncPgConnection) -> QueryResult { + use diesel_async::RunQueryDsl; crate_owner_invitations::table .filter(crate_owner_invitations::token.eq(token)) .first::(conn) + .await } pub fn accept(self, conn: &mut impl Conn, config: &config::Server) -> AppResult<()> { From 656a2334401b19515453dfd58512e48b8a24e709 Mon Sep 17 00:00:00 2001 From: eth3lbert Date: Sun, 10 Nov 2024 22:53:35 +0800 Subject: [PATCH 3/3] controllers/crate_owner_invitation: Remove `spawn_blocking()` usages Removes `spawn_blocking()` usage from `PUT /api/v1/me/crate_owner_invitations/:crate_id` and `PUT /api/v1/me/crate_owner_invitations/accept/:token` endpoints. Converts `CrateOwnerInvitation::accept()` and `CrateOwnerInvitation::decline()` to async fns. --- src/controllers/crate_owner_invitation.rs | 40 +++++++---------- src/models/crate_owner_invitation.rs | 55 ++++++++++++++--------- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index 15922cb490c..a882376479e 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -290,20 +290,16 @@ pub async fn handle_invite(state: AppState, req: BytesRequest) -> AppResult = &mut conn.into(); - let config = &state.config; + let config = &state.config; - if crate_invite.accepted { - invitation.accept(conn, config)?; - } else { - invitation.decline(conn)?; - } + if crate_invite.accepted { + invitation.accept(&mut conn, config).await?; + } else { + invitation.decline(&mut conn).await?; + } - Ok(Json(json!({ "crate_owner_invitation": crate_invite }))) - }) - .await + Ok(Json(json!({ "crate_owner_invitation": crate_invite }))) } /// Handles the `PUT /api/v1/me/crate_owner_invitations/accept/:token` route. @@ -313,20 +309,16 @@ pub async fn handle_invite_with_token( ) -> AppResult> { let mut conn = state.db_write().await?; let invitation = CrateOwnerInvitation::find_by_token(&token, &mut conn).await?; - spawn_blocking(move || { - let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); - let config = &state.config; + let config = &state.config; - let crate_id = invitation.crate_id; - invitation.accept(conn, config)?; + let crate_id = invitation.crate_id; + invitation.accept(&mut conn, config).await?; - Ok(Json(json!({ - "crate_owner_invitation": { - "crate_id": crate_id, - "accepted": true, - }, - }))) - }) - .await + Ok(Json(json!({ + "crate_owner_invitation": { + "crate_id": crate_id, + "accepted": true, + }, + }))) } diff --git a/src/models/crate_owner_invitation.rs b/src/models/crate_owner_invitation.rs index 69ee297634b..17c0518b8ef 100644 --- a/src/models/crate_owner_invitation.rs +++ b/src/models/crate_owner_invitation.rs @@ -110,14 +110,20 @@ impl CrateOwnerInvitation { .await } - pub fn accept(self, conn: &mut impl Conn, config: &config::Server) -> AppResult<()> { - use diesel::RunQueryDsl; + pub async fn accept( + self, + conn: &mut AsyncPgConnection, + config: &config::Server, + ) -> AppResult<()> { + use diesel_async::scoped_futures::ScopedFutureExt; + use diesel_async::{AsyncConnection, RunQueryDsl}; if self.is_expired(config) { let crate_name: String = crates::table .find(self.crate_id) .select(crates::name) - .first(conn)?; + .first(conn) + .await?; let detail = format!( "The invitation to become an owner of the {crate_name} crate expired. \ @@ -128,33 +134,38 @@ impl CrateOwnerInvitation { } conn.transaction(|conn| { - diesel::insert_into(crate_owners::table) - .values(&CrateOwner { - crate_id: self.crate_id, - owner_id: self.invited_user_id, - created_by: self.invited_by_user_id, - owner_kind: OwnerKind::User, - email_notifications: true, - }) - .on_conflict(crate_owners::table.primary_key()) - .do_update() - .set(crate_owners::deleted.eq(false)) - .execute(conn)?; - - diesel::delete(&self).execute(conn)?; - - Ok(()) + async move { + diesel::insert_into(crate_owners::table) + .values(&CrateOwner { + crate_id: self.crate_id, + owner_id: self.invited_user_id, + created_by: self.invited_by_user_id, + owner_kind: OwnerKind::User, + email_notifications: true, + }) + .on_conflict(crate_owners::table.primary_key()) + .do_update() + .set(crate_owners::deleted.eq(false)) + .execute(conn) + .await?; + + diesel::delete(&self).execute(conn).await?; + + Ok(()) + } + .scope_boxed() }) + .await } - pub fn decline(self, conn: &mut impl Conn) -> QueryResult<()> { - use diesel::RunQueryDsl; + pub async fn decline(self, conn: &mut AsyncPgConnection) -> QueryResult<()> { + use diesel_async::RunQueryDsl; // The check to prevent declining expired invitations is *explicitly* missing. We do not // care if an expired invitation is declined, as that just removes the invitation from the // database. - diesel::delete(&self).execute(conn)?; + diesel::delete(&self).execute(conn).await?; Ok(()) }