fix folder move to root

This commit is contained in:
2025-10-25 02:11:05 +02:00
parent 88b9375a4e
commit e972a8dddb
5 changed files with 153 additions and 48 deletions
+71 -30
View File
@@ -4,6 +4,7 @@ use axum::{
};
use diesel::{dsl::exists, prelude::*, PgConnection};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
use crate::models::{Document, Folder, NewFolder};
@@ -18,7 +19,10 @@ use super::documents::{
load_correspondents_for_documents, load_primary_assets, load_tags_for_documents,
to_document_response, DocumentResponse,
};
use crate::utils::time::to_iso;
use crate::utils::{
json::{classify_nullable, NullableValue},
time::to_iso,
};
#[derive(Deserialize)]
pub struct CreateFolderRequest {
@@ -32,13 +36,6 @@ pub struct EnsureFolderPathRequest {
pub segments: Vec<String>,
}
#[derive(Deserialize)]
pub struct UpdateFolderRequest {
#[serde(default)]
pub parent_id: Option<Option<Uuid>>,
pub name: Option<String>,
}
#[derive(Serialize)]
pub struct FolderResponse {
pub folder: FolderInfo,
@@ -70,6 +67,24 @@ pub struct FolderInfo {
pub updated_at: String,
}
pub async fn get_folder(
Path(folder_id): Path<Uuid>,
TenantScopedConn {
mut conn,
tenant_id,
..
}: TenantScopedConn,
) -> AppResult<Json<FolderResponse>> {
let folder: Folder = folders::table
.find(folder_id)
.filter(folders::tenant_id.eq(tenant_id))
.first(&mut conn)?;
Ok(Json(FolderResponse {
folder: folder_to_info(folder),
}))
}
pub async fn ensure_folder_path(
TenantScopedConn {
mut conn,
@@ -322,8 +337,15 @@ pub async fn update_folder(
tenant_id,
..
}: TenantScopedConn,
Json(payload): Json<UpdateFolderRequest>,
Json(body): Json<Value>,
) -> AppResult<StatusCode> {
if !body.is_object() {
return Err(AppError::bad_request("request body must be a JSON object"));
}
let parent_class = classify_nullable(body.get("parent_id")).map_err(AppError::bad_request)?;
let name_class = classify_nullable(body.get("name")).map_err(AppError::bad_request)?;
conn.transaction::<(), AppError, _>(|conn| {
let folder: Folder = folders::table
.find(folder_id)
@@ -332,42 +354,61 @@ pub async fn update_folder(
let mut next_parent = folder.parent_id;
let mut parent_changed = false;
if let Some(parent_request) = payload.parent_id {
if parent_request == Some(folder_id) {
return Err(AppError::bad_request("folder cannot be its own parent"));
match parent_class {
NullableValue::Omitted => {}
NullableValue::Null => {
if folder.parent_id.is_some() {
parent_changed = true;
}
next_parent = None;
}
NullableValue::String(value) => {
let trimmed = value.trim();
if trimmed.is_empty() {
return Err(AppError::bad_request("parent_id must not be empty"));
}
let parent_id = Uuid::parse_str(trimmed)
.map_err(|_| AppError::bad_request("parent_id must be a valid UUID or null"))?;
if parent_id == folder_id {
return Err(AppError::bad_request("folder cannot be its own parent"));
}
if let Some(parent_id) = parent_request {
let _parent: Folder = folders::table
.find(parent_id)
.filter(folders::tenant_id.eq(tenant_id))
.first(conn)?;
let descendant_ids = gather_descendant_folder_ids(conn, tenant_id, folder_id)?;
if descendant_ids.contains(&parent_id) {
return Err(AppError::bad_request(
"cannot move folder into itself or a descendant",
));
if folder.parent_id != Some(parent_id) {
let descendant_ids = gather_descendant_folder_ids(conn, tenant_id, folder_id)?;
if descendant_ids.contains(&parent_id) {
return Err(AppError::bad_request(
"cannot move folder into itself or a descendant",
));
}
parent_changed = true;
}
}
parent_changed = parent_request != folder.parent_id;
next_parent = parent_request;
next_parent = Some(parent_id);
}
}
let mut new_name = folder.name.clone();
let mut name_changed = false;
if let Some(name) = payload.name {
let trimmed = name.trim();
if trimmed.is_empty() {
return Err(AppError::bad_request("name must not be empty"));
match name_class {
NullableValue::Omitted => {}
NullableValue::Null => {
return Err(AppError::bad_request("name cannot be null"));
}
NullableValue::String(value) => {
let trimmed = value.trim();
if trimmed.is_empty() {
return Err(AppError::bad_request("name must not be empty"));
}
if trimmed != folder.name {
new_name = trimmed.to_string();
name_changed = true;
if trimmed != folder.name {
new_name = trimmed.to_string();
name_changed = true;
}
}
}
+3 -4
View File
@@ -97,10 +97,9 @@ pub fn create_router(state: AppState) -> Router<()> {
let folders_routes = Router::new()
.route("/", post(folders::create_folder))
.route("/path", post(folders::ensure_folder_path))
.route(
"/:id",
delete(folders::delete_folder).patch(folders::update_folder),
)
.route("/:id", get(folders::get_folder))
.route("/:id", delete(folders::delete_folder))
.route("/:id", patch(folders::update_folder))
.route("/:id/contents", get(folders::list_folder_contents));
let tags_routes = Router::new()