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,
|
http::request::Parts,
|
||||||
Json,
|
Json,
|
||||||
};
|
};
|
||||||
use sea_orm::{prelude::*, ActiveValue};
|
use sea_orm::{prelude::*, ActiveValue, DatabaseTransaction, TransactionTrait};
|
||||||
use sea_query::OnConflict;
|
use sea_query::OnConflict;
|
||||||
|
|
||||||
use api::{
|
use api::{
|
||||||
|
|
@ -132,27 +132,44 @@ pub(super) async fn add_member(
|
||||||
Ok(Json(EmptyResponse {}))
|
Ok(Json(EmptyResponse {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn delete_household(
|
||||||
|
household: household::Model,
|
||||||
|
txn: &DatabaseTransaction,
|
||||||
|
) -> Result<(), RouteError> {
|
||||||
|
household.delete(txn).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn leave(
|
pub(super) async fn leave(
|
||||||
AuthorizedHousehold(household): AuthorizedHousehold,
|
AuthorizedHousehold(household): AuthorizedHousehold,
|
||||||
user: AuthenticatedUser,
|
user: AuthenticatedUser,
|
||||||
state: State<AppState>,
|
state: State<AppState>,
|
||||||
) -> super::JsonResult<EmptyResponse> {
|
) -> super::JsonResult<EmptyResponse> {
|
||||||
HouseholdMembers::delete_by_id((household.id, user.model.id))
|
state
|
||||||
.exec(&state.db)
|
.db
|
||||||
.await?;
|
.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)
|
let Some(household) = Household::find_by_id(household.id)
|
||||||
.one(&state.db)
|
.one(txn)
|
||||||
.await? else {
|
.await? else {
|
||||||
return Ok(Json(EmptyResponse {}));
|
return Ok(Json(EmptyResponse {}));
|
||||||
};
|
};
|
||||||
|
|
||||||
let member_count = household.find_related(User).count(&state.db).await?;
|
let member_count = household.find_related(User).count(txn).await?;
|
||||||
if member_count == 0 {
|
if member_count == 0 {
|
||||||
household.delete(&state.db).await?;
|
delete_household(household, txn).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Json(EmptyResponse {}))
|
Ok(Json(EmptyResponse {}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn rename(
|
pub(super) async fn rename(
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use axum::{
|
||||||
Json, Router, TypedHeader,
|
Json, Router, TypedHeader,
|
||||||
};
|
};
|
||||||
use jwt_simple::prelude::*;
|
use jwt_simple::prelude::*;
|
||||||
use sea_orm::prelude::*;
|
use sea_orm::{prelude::*, TransactionError};
|
||||||
use sha2::{Digest, Sha512};
|
use sha2::{Digest, Sha512};
|
||||||
use tower_http::cors::{self, AllowOrigin, CorsLayer};
|
use tower_http::cors::{self, AllowOrigin, CorsLayer};
|
||||||
|
|
||||||
|
|
@ -42,11 +42,20 @@ enum RouteError {
|
||||||
PathRejection(#[from] axum::extract::rejection::PathRejection),
|
PathRejection(#[from] axum::extract::rejection::PathRejection),
|
||||||
#[error("The supplied ressource does not exist")]
|
#[error("The supplied ressource does not exist")]
|
||||||
RessourceNotFound,
|
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 {
|
impl IntoResponse for RouteError {
|
||||||
fn into_response(self) -> axum::response::Response {
|
fn into_response(self) -> axum::response::Response {
|
||||||
match self {
|
match self {
|
||||||
|
RouteError::TxnError(TransactionError::Transaction(e)) => e.into_response(),
|
||||||
RouteError::UnknownAccount => {
|
RouteError::UnknownAccount => {
|
||||||
(StatusCode::NOT_FOUND, "Account not found").into_response()
|
(StatusCode::NOT_FOUND, "Account not found").into_response()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue