This commit is contained in:
2025-11-06 12:26:29 +01:00
parent 4027ac66cb
commit a6f79dbc75
12 changed files with 344 additions and 199 deletions
+27 -20
View File
@@ -18,6 +18,9 @@ use crate::state::AppState;
use crate::{
auth::TenantScopedConn,
error::{AppError, AppResult},
http::responders::{
created_json, no_content, ok_json, IntoAppResult, JsonResponse, RowsAffectedExt,
},
};
use super::documents::{hydrate_documents, DocumentResponse};
@@ -141,15 +144,15 @@ pub async fn get_folder(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<FolderResponse>> {
) -> AppResult<JsonResponse<FolderResponse>> {
let folder: Folder = folders::table
.find(folder_id)
.filter(folders::tenant_id.eq(tenant_id))
.first(&mut conn)?;
Ok(Json(FolderResponse {
ok_json(FolderResponse {
folder: folder_to_info(folder),
}))
})
}
#[utoipa::path(
@@ -166,7 +169,7 @@ pub async fn ensure_folder_path(
..
}: TenantScopedConn,
Json(payload): Json<EnsureFolderPathRequest>,
) -> AppResult<Json<FolderResponse>> {
) -> AppResult<JsonResponse<FolderResponse>> {
if payload.segments.is_empty() {
return Err(AppError::bad_request("segments must not be empty"));
}
@@ -240,9 +243,9 @@ pub async fn ensure_folder_path(
last_folder.ok_or_else(|| AppError::internal("failed to resolve folder path"))
})?;
Ok(Json(FolderResponse {
ok_json(FolderResponse {
folder: folder_to_info(target_folder),
}))
})
}
#[utoipa::path(
@@ -262,7 +265,7 @@ pub async fn create_folder(
..
}: TenantScopedConn,
Json(payload): Json<CreateFolderRequest>,
) -> AppResult<(StatusCode, Json<FolderResponse>)> {
) -> AppResult<JsonResponse<FolderResponse>> {
if payload.name.trim().is_empty() {
return Err(AppError::bad_request("name must not be empty"));
}
@@ -331,14 +334,14 @@ pub async fn create_folder(
}
};
let response = Json(FolderResponse {
let response = FolderResponse {
folder: folder_to_info(folder),
});
};
if created {
Ok((StatusCode::CREATED, response))
created_json(response)
} else {
Ok((StatusCode::OK, response))
ok_json(response)
}
}
@@ -359,7 +362,7 @@ pub async fn list_folder_contents(
user_id,
..
}: TenantScopedConn,
) -> AppResult<Json<FolderContentsResponse>> {
) -> AppResult<JsonResponse<FolderContentsResponse>> {
let FolderContentsQuery {
include_documents,
sort,
@@ -427,11 +430,11 @@ pub async fn list_folder_contents(
Vec::new()
};
Ok(Json(FolderContentsResponse {
ok_json(FolderContentsResponse {
folder,
subfolders,
documents,
}))
})
}
#[utoipa::path(
@@ -446,7 +449,7 @@ pub async fn list_folder_tree(
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<Vec<FolderTreeNode>>> {
) -> AppResult<JsonResponse<Vec<FolderTreeNode>>> {
let folders: Vec<Folder> = folders::table
.filter(folders::tenant_id.eq(tenant_id))
.order(sql::<Text>("name COLLATE \"unicode_ci\" ASC"))
@@ -499,7 +502,7 @@ pub async fn list_folder_tree(
.map(|root_id| build_node(*root_id, &node_map, &children_map))
.collect();
Ok(Json(tree))
ok_json(tree)
}
#[utoipa::path(
@@ -555,12 +558,14 @@ pub async fn delete_folder(
.filter(folders::id.eq(folder_id))
.filter(folders::tenant_id.eq(tenant_id)),
)
.execute(conn)?;
.execute(conn)
.into_app_result()?
.or_not_found()?;
Ok(())
})?;
Ok(StatusCode::NO_CONTENT)
no_content()
}
#[utoipa::path(
@@ -677,12 +682,14 @@ pub async fn update_folder(
folders::parent_id.eq(next_parent),
folders::name.eq(&new_name),
))
.execute(conn)?;
.execute(conn)
.into_app_result()?
.or_not_found()?;
Ok(())
})?;
Ok(StatusCode::NO_CONTENT)
no_content()
}
fn folder_to_info(folder: Folder) -> FolderInfo {