diff --git a/src/controllers/crate_owner_invitation.rs b/src/controllers/crate_owner_invitation.rs index cffb8d7ad15..a882376479e 100644 --- a/src/controllers/crate_owner_invitation.rs +++ b/src/controllers/crate_owner_invitation.rs @@ -284,24 +284,22 @@ pub async fn handle_invite(state: AppState, req: BytesRequest) -> AppResult = &mut conn.into(); + let user_id = AuthCheck::default() + .check(&parts, &mut conn) + .await? + .user_id(); + let invitation = + CrateOwnerInvitation::find_by_id(user_id, crate_invite.crate_id, &mut conn).await?; - let user_id = auth.user_id(); - - let config = &state.config; + 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 { - 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. @@ -309,22 +307,18 @@ pub async fn handle_invite_with_token( state: AppState, Path(token): Path, ) -> AppResult> { - let conn = state.db_write().await?; - spawn_blocking(move || { - let conn: &mut AsyncConnectionWrapper<_> = &mut conn.into(); + let mut conn = state.db_write().await?; + let invitation = CrateOwnerInvitation::find_by_token(&token, &mut conn).await?; - let config = &state.config; + let config = &state.config; - let invitation = CrateOwnerInvitation::find_by_token(&token, conn)?; - 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 07c753bacf2..17c0518b8ef 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,30 +88,42 @@ 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 { - 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<()> { - 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. \ @@ -121,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(()) }