folders
This commit is contained in:
@@ -1304,7 +1304,6 @@ pub async fn update_document(
|
||||
}
|
||||
|
||||
pub async fn move_document(
|
||||
State(state): State<AppState>,
|
||||
Path(document_id): Path<Uuid>,
|
||||
TenantScopedConn {
|
||||
mut conn,
|
||||
@@ -1314,7 +1313,7 @@ pub async fn move_document(
|
||||
Json(payload): Json<MoveDocumentRequest>,
|
||||
) -> AppResult<impl IntoResponse> {
|
||||
if let Some(folder_id) = payload.folder_id {
|
||||
ensure_folder_exists(&state, tenant_id, folder_id)?;
|
||||
ensure_folder_exists_on_conn(&mut conn, tenant_id, folder_id)?;
|
||||
}
|
||||
|
||||
let now = Utc::now().naive_utc();
|
||||
@@ -1333,7 +1332,6 @@ pub async fn move_document(
|
||||
}
|
||||
|
||||
pub async fn bulk_move_documents(
|
||||
State(state): State<AppState>,
|
||||
TenantScopedConn {
|
||||
mut conn,
|
||||
tenant_id,
|
||||
@@ -1354,7 +1352,7 @@ pub async fn bulk_move_documents(
|
||||
document_ids.dedup();
|
||||
|
||||
if let Some(target_folder) = folder_id {
|
||||
ensure_folder_exists(&state, tenant_id, target_folder)?;
|
||||
ensure_folder_exists_on_conn(&mut conn, tenant_id, target_folder)?;
|
||||
}
|
||||
|
||||
let existing: Vec<(Uuid, Option<NaiveDateTime>)> = documents::table
|
||||
@@ -1374,7 +1372,7 @@ pub async fn bulk_move_documents(
|
||||
}
|
||||
|
||||
let now = Utc::now().naive_utc();
|
||||
let updated = diesel::update(
|
||||
let updated = match diesel::update(
|
||||
documents::table
|
||||
.filter(documents::id.eq_any(&document_ids))
|
||||
.filter(documents::tenant_id.eq(tenant_id)),
|
||||
@@ -1383,7 +1381,34 @@ pub async fn bulk_move_documents(
|
||||
documents::folder_id.eq(folder_id),
|
||||
documents::updated_at.eq(now),
|
||||
))
|
||||
.execute(&mut conn)?;
|
||||
.execute(&mut conn)
|
||||
{
|
||||
Ok(value) => value,
|
||||
Err(diesel::result::Error::DatabaseError(kind, info)) => {
|
||||
error!(
|
||||
?kind,
|
||||
detail = ?info.details(),
|
||||
constraint = info.constraint_name(),
|
||||
tenant_id = %tenant_id,
|
||||
target_folder = folder_id.map(|id| id.to_string()),
|
||||
"bulk move update failed"
|
||||
);
|
||||
let message = info
|
||||
.constraint_name()
|
||||
.map(|name| format!("constraint {name} prevented moving documents"))
|
||||
.unwrap_or_else(|| "unable to move documents due to a constraint".to_string());
|
||||
return Err(AppError::conflict(message));
|
||||
}
|
||||
Err(err) => {
|
||||
error!(
|
||||
?err,
|
||||
tenant_id = %tenant_id,
|
||||
target_folder = folder_id.map(|id| id.to_string()),
|
||||
"bulk move update failed"
|
||||
);
|
||||
return Err(AppError::from(err));
|
||||
}
|
||||
};
|
||||
|
||||
let body = BulkMoveResponse { updated };
|
||||
Ok((StatusCode::OK, body.into_json()?))
|
||||
@@ -1810,7 +1835,8 @@ async fn process_upload(
|
||||
} = request;
|
||||
|
||||
if let Some(folder) = folder_id {
|
||||
ensure_folder_exists(state, tenant_id, folder)?;
|
||||
let mut conn = state.db_for_tenant(tenant_id)?;
|
||||
ensure_folder_exists_on_conn(&mut conn, tenant_id, folder)?;
|
||||
}
|
||||
|
||||
let doc_id = Uuid::new_v4();
|
||||
@@ -2173,14 +2199,17 @@ fn insert_document_correspondents(
|
||||
Ok(inserted)
|
||||
}
|
||||
|
||||
fn ensure_folder_exists(state: &AppState, tenant_id: Uuid, folder_id: Uuid) -> AppResult<()> {
|
||||
let mut conn = state.db_for_tenant(tenant_id)?;
|
||||
fn ensure_folder_exists_on_conn(
|
||||
conn: &mut PgConnection,
|
||||
tenant_id: Uuid,
|
||||
folder_id: Uuid,
|
||||
) -> AppResult<()> {
|
||||
let exists: bool = diesel::select(exists(
|
||||
folders::table
|
||||
.filter(folders::id.eq(folder_id))
|
||||
.filter(folders::tenant_id.eq(tenant_id)),
|
||||
))
|
||||
.get_result(&mut conn)?;
|
||||
.get_result(conn)?;
|
||||
ensure_exists(exists, "folder")
|
||||
}
|
||||
|
||||
|
||||
@@ -109,16 +109,16 @@ pub async fn ensure_folder_path(
|
||||
|
||||
let existing: Option<Folder> = if let Some(parent_id) = current_parent {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.eq(Some(parent_id)))
|
||||
.filter(folders::name.eq(name))
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.first(conn)
|
||||
.optional()?
|
||||
} else {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.is_null())
|
||||
.filter(folders::name.eq(name))
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.first(conn)
|
||||
.optional()?
|
||||
};
|
||||
@@ -133,13 +133,32 @@ pub async fn ensure_folder_path(
|
||||
tenant_id,
|
||||
};
|
||||
|
||||
diesel::insert_into(folders::table)
|
||||
let inserted_id: Option<Uuid> = diesel::insert_into(folders::table)
|
||||
.values(&new_folder)
|
||||
.execute(conn)?;
|
||||
.on_conflict_do_nothing()
|
||||
.returning(folders::id)
|
||||
.get_result(conn)
|
||||
.optional()?;
|
||||
|
||||
folders::table.find(new_folder.id).first(conn)?
|
||||
if let Some(id) = inserted_id {
|
||||
folders::table
|
||||
.find(id)
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.first(conn)?
|
||||
} else if let Some(parent_id) = current_parent {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.eq(Some(parent_id)))
|
||||
.filter(folders::name.eq(name))
|
||||
.first(conn)?
|
||||
} else {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.is_null())
|
||||
.filter(folders::name.eq(name))
|
||||
.first(conn)?
|
||||
}
|
||||
};
|
||||
|
||||
current_parent = Some(folder.id);
|
||||
last_folder = Some(folder);
|
||||
}
|
||||
@@ -164,18 +183,61 @@ pub async fn create_folder(
|
||||
return Err(AppError::bad_request("name must not be empty"));
|
||||
}
|
||||
|
||||
let new_folder = NewFolder {
|
||||
id: Uuid::new_v4(),
|
||||
name: payload.name.trim().to_string(),
|
||||
parent_id: payload.parent_id,
|
||||
tenant_id,
|
||||
let name = payload.name.trim();
|
||||
|
||||
let existing: Option<Folder> = if let Some(parent_id) = payload.parent_id {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.eq(Some(parent_id)))
|
||||
.filter(folders::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
} else {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.is_null())
|
||||
.filter(folders::name.eq(name))
|
||||
.first(&mut conn)
|
||||
.optional()?
|
||||
};
|
||||
|
||||
diesel::insert_into(folders::table)
|
||||
.values(&new_folder)
|
||||
.execute(&mut conn)?;
|
||||
let folder: Folder = if let Some(folder) = existing {
|
||||
folder
|
||||
} else {
|
||||
let new_folder = NewFolder {
|
||||
id: Uuid::new_v4(),
|
||||
name: name.to_string(),
|
||||
parent_id: payload.parent_id,
|
||||
tenant_id,
|
||||
};
|
||||
|
||||
let inserted_id: Option<Uuid> = diesel::insert_into(folders::table)
|
||||
.values(&new_folder)
|
||||
.on_conflict_do_nothing()
|
||||
.returning(folders::id)
|
||||
.get_result(&mut conn)
|
||||
.optional()?;
|
||||
|
||||
if let Some(id) = inserted_id {
|
||||
folders::table
|
||||
.find(id)
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.first(&mut conn)?
|
||||
} else if let Some(parent_id) = payload.parent_id {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.eq(Some(parent_id)))
|
||||
.filter(folders::name.eq(name))
|
||||
.first(&mut conn)?
|
||||
} else {
|
||||
folders::table
|
||||
.filter(folders::tenant_id.eq(tenant_id))
|
||||
.filter(folders::parent_id.is_null())
|
||||
.filter(folders::name.eq(name))
|
||||
.first(&mut conn)?
|
||||
}
|
||||
};
|
||||
|
||||
let folder: Folder = folders::table.find(new_folder.id).first(&mut conn)?;
|
||||
Ok(Json(FolderResponse {
|
||||
folder: folder_to_info(folder),
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user