server: Leave households in a transaction if deleting fails
This commit is contained in:
parent
c41b67b258
commit
b354741245
2 changed files with 41 additions and 15 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue