409 on duplicate

This commit is contained in:
2025-10-26 02:33:30 +02:00
parent e51a59a829
commit 9b7ca3d692
2 changed files with 30 additions and 4 deletions
+14
View File
@@ -12,6 +12,7 @@ pub type AppResult<T> = Result<T, AppError>;
pub struct AppError { pub struct AppError {
status: StatusCode, status: StatusCode,
message: String, message: String,
code: Option<String>,
} }
impl AppError { impl AppError {
@@ -19,6 +20,7 @@ impl AppError {
Self { Self {
status, status,
message: message.into(), message: message.into(),
code: None,
} }
} }
@@ -26,6 +28,10 @@ impl AppError {
Self::new(StatusCode::BAD_REQUEST, message) Self::new(StatusCode::BAD_REQUEST, message)
} }
pub fn conflict(message: impl Into<String>) -> Self {
Self::new(StatusCode::CONFLICT, message)
}
pub fn unauthorized() -> Self { pub fn unauthorized() -> Self {
Self::new(StatusCode::UNAUTHORIZED, "unauthorized") Self::new(StatusCode::UNAUTHORIZED, "unauthorized")
} }
@@ -37,6 +43,11 @@ impl AppError {
pub fn internal<E: Display>(error: E) -> Self { pub fn internal<E: Display>(error: E) -> Self {
Self::new(StatusCode::INTERNAL_SERVER_ERROR, error.to_string()) Self::new(StatusCode::INTERNAL_SERVER_ERROR, error.to_string())
} }
pub fn with_code(mut self, code: impl Into<String>) -> Self {
self.code = Some(code.into());
self
}
} }
impl IntoResponse for AppError { impl IntoResponse for AppError {
@@ -44,6 +55,7 @@ impl IntoResponse for AppError {
let status = self.status; let status = self.status;
let body = Json(ErrorResponse { let body = Json(ErrorResponse {
error: self.message, error: self.message,
code: self.code,
}); });
(status, body).into_response() (status, body).into_response()
} }
@@ -52,6 +64,8 @@ impl IntoResponse for AppError {
#[derive(Serialize)] #[derive(Serialize)]
struct ErrorResponse { struct ErrorResponse {
error: String, error: String,
#[serde(skip_serializing_if = "Option::is_none")]
code: Option<String>,
} }
impl From<diesel::result::Error> for AppError { impl From<diesel::result::Error> for AppError {
+16 -4
View File
@@ -1151,9 +1151,10 @@ pub async fn update_document(
match update_result.execute(&mut conn) { match update_result.execute(&mut conn) {
Ok(_) => {} Ok(_) => {}
Err(diesel::result::Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) => { Err(diesel::result::Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) => {
return Err(AppError::bad_request( return Err(AppError::conflict(
"another document in this folder already uses that filename", "another document in this folder already uses that filename",
)); )
.with_code("duplicate_filename"));
} }
Err(err) => return Err(AppError::from(err)), Err(err) => return Err(AppError::from(err)),
} }
@@ -1822,7 +1823,7 @@ async fn process_upload(
let (document, version) = { let (document, version) = {
let mut conn = state.db_for_tenant(tenant_id)?; let mut conn = state.db_for_tenant(tenant_id)?;
conn.transaction(|conn| { let transaction_result = conn.transaction(|conn| {
let new_document = NewDocument { let new_document = NewDocument {
id: doc_id, id: doc_id,
filename: stored_filename.clone(), filename: stored_filename.clone(),
@@ -1859,7 +1860,18 @@ async fn process_upload(
let version: DocumentVersion = document_versions::table.find(version_id).first(conn)?; let version: DocumentVersion = document_versions::table.find(version_id).first(conn)?;
Ok::<_, diesel::result::Error>((document, version)) Ok::<_, diesel::result::Error>((document, version))
})? });
match transaction_result {
Ok(result) => result,
Err(diesel::result::Error::DatabaseError(DatabaseErrorKind::UniqueViolation, _)) => {
return Err(AppError::conflict(
"another document in this folder already uses that filename",
)
.with_code("duplicate_filename"))
}
Err(err) => return Err(AppError::from(err)),
}
}; };
let detail = { let detail = {