server: Leave households in a transaction if deleting fails

This commit is contained in:
traxys 2023-06-17 18:15:17 +02:00
parent c41b67b258
commit b354741245
2 changed files with 41 additions and 15 deletions

View file

@ -6,7 +6,7 @@ use axum::{
http::request::Parts,
Json,
};
use sea_orm::{prelude::*, ActiveValue};
use sea_orm::{prelude::*, ActiveValue, DatabaseTransaction, TransactionTrait};
use sea_query::OnConflict;
use api::{
@ -132,27 +132,44 @@ pub(super) async fn add_member(
Ok(Json(EmptyResponse {}))
}
async fn delete_household(
household: household::Model,
txn: &DatabaseTransaction,
) -> Result<(), RouteError> {
household.delete(txn).await?;
Ok(())
}
pub(super) async fn leave(
AuthorizedHousehold(household): AuthorizedHousehold,
user: AuthenticatedUser,
state: State<AppState>,
) -> super::JsonResult<EmptyResponse> {
HouseholdMembers::delete_by_id((household.id, user.model.id))
.exec(&state.db)
.await?;
state
.db
.transaction(|txn| {
Box::pin(async move {
HouseholdMembers::delete_by_id((household.id, user.model.id))
.exec(txn)
.await?;
let Some(household) = Household::find_by_id(household.id)
.one(&state.db)
.await? else {
return Ok(Json(EmptyResponse {}));
};
let Some(household) = Household::find_by_id(household.id)
.one(txn)
.await? else {
return Ok(Json(EmptyResponse {}));
};
let member_count = household.find_related(User).count(&state.db).await?;
if member_count == 0 {
household.delete(&state.db).await?;
}
let member_count = household.find_related(User).count(txn).await?;
if member_count == 0 {
delete_household(household, txn).await?;
}
Ok(Json(EmptyResponse {}))
Ok(Json(EmptyResponse {}))
})
})
.await
.map_err(Into::into)
}
pub(super) async fn rename(

View file

@ -15,7 +15,7 @@ use axum::{
Json, Router, TypedHeader,
};
use jwt_simple::prelude::*;
use sea_orm::prelude::*;
use sea_orm::{prelude::*, TransactionError};
use sha2::{Digest, Sha512};
use tower_http::cors::{self, AllowOrigin, CorsLayer};
@ -42,11 +42,20 @@ enum RouteError {
PathRejection(#[from] axum::extract::rejection::PathRejection),
#[error("The supplied ressource does not exist")]
RessourceNotFound,
#[error("Error in DB transaction")]
TxnError(#[from] TransactionError<Box<RouteError>>),
}
impl From<DbErr> for Box<RouteError> {
fn from(value: DbErr) -> Self {
Box::new(value.into())
}
}
impl IntoResponse for RouteError {
fn into_response(self) -> axum::response::Response {
match self {
RouteError::TxnError(TransactionError::Transaction(e)) => e.into_response(),
RouteError::UnknownAccount => {
(StatusCode::NOT_FOUND, "Account not found").into_response()
}