folder tree
This commit is contained in:
@@ -605,6 +605,81 @@ async fn upload_skips_existing_when_requested() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn filter_documents_without_tags() -> Result<()> {
|
||||
let _lock = acquire_db_lock().await;
|
||||
let app = TestApp::new().await?;
|
||||
|
||||
let password = "tagfilter";
|
||||
app.insert_user("tagfilter", password, "admin").await?;
|
||||
let token = app.login_token("tagfilter", password).await?;
|
||||
|
||||
// Create a tag and upload a document that uses it.
|
||||
let tag_payload = CreateTagPayload {
|
||||
label: "with-tag",
|
||||
color: None,
|
||||
};
|
||||
let tag_resp = app
|
||||
.post_json("/api/tags", &tag_payload, Some(&token))
|
||||
.await?;
|
||||
assert!(tag_resp.status().is_success());
|
||||
let tag_body = body_to_vec(tag_resp.into_body()).await?;
|
||||
let tag: TagResponse = serde_json::from_slice(&tag_body)?;
|
||||
|
||||
let tag_json = format!("[\"{}\"]", tag.id);
|
||||
let tagged_upload = app
|
||||
.upload_document_with_extras(
|
||||
"/api/documents",
|
||||
"with-tag.txt",
|
||||
"text/plain",
|
||||
b"tagged",
|
||||
None,
|
||||
UploadExtras {
|
||||
title: Some("With Tag"),
|
||||
metadata_json: None,
|
||||
tag_ids_json: Some(tag_json.as_str()),
|
||||
correspondents_json: None,
|
||||
issued_at: None,
|
||||
skip_existing: None,
|
||||
},
|
||||
&token,
|
||||
)
|
||||
.await?;
|
||||
assert!(tagged_upload.status().is_success());
|
||||
|
||||
let untagged_upload = app
|
||||
.upload_document(
|
||||
"/api/documents",
|
||||
"without-tag.txt",
|
||||
"text/plain",
|
||||
b"untagged",
|
||||
None,
|
||||
&token,
|
||||
)
|
||||
.await?;
|
||||
assert!(untagged_upload.status().is_success());
|
||||
let untagged_body = body_to_vec(untagged_upload.into_body()).await?;
|
||||
let untagged_detail: DocumentDetail = serde_json::from_slice(&untagged_body)?;
|
||||
|
||||
// Sanity: both documents appear in the default listing.
|
||||
let all_resp = app.get("/api/documents", Some(&token)).await?;
|
||||
assert_eq!(all_resp.status(), StatusCode::OK);
|
||||
let all_body = body_to_vec(all_resp.into_body()).await?;
|
||||
let all_docs: Vec<DocumentListItem> = serde_json::from_slice(&all_body)?;
|
||||
assert_eq!(all_docs.len(), 2);
|
||||
|
||||
// Filter for documents without tags.
|
||||
let none_resp = app.get("/api/documents?tags=none", Some(&token)).await?;
|
||||
assert_eq!(none_resp.status(), StatusCode::OK);
|
||||
let none_body = body_to_vec(none_resp.into_body()).await?;
|
||||
let none_docs: Vec<DocumentListItem> = serde_json::from_slice(&none_body)?;
|
||||
assert_eq!(none_docs.len(), 1);
|
||||
assert_eq!(none_docs[0].id, untagged_detail.document.id);
|
||||
|
||||
app.cleanup().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bulk_move_documents_to_folder() -> Result<()> {
|
||||
let _lock = acquire_db_lock().await;
|
||||
|
||||
@@ -32,6 +32,12 @@ struct DocSummary {
|
||||
id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct FolderTreeNodeResponse {
|
||||
name: String,
|
||||
children: Vec<FolderTreeNodeResponse>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct CreateFolder<'a> {
|
||||
name: &'a str,
|
||||
@@ -144,6 +150,71 @@ async fn folder_move_and_delete_flow() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn folder_tree_lists_hierarchy() -> Result<()> {
|
||||
let _lock = acquire_db_lock().await;
|
||||
let app = TestApp::new().await?;
|
||||
|
||||
let password = "folderpass";
|
||||
app.insert_user("folder-tree", password, "admin").await?;
|
||||
let token = app.login_token("folder-tree", password).await?;
|
||||
|
||||
let alpha_resp = app
|
||||
.post_json(
|
||||
"/api/folders",
|
||||
&CreateFolder {
|
||||
name: "Alpha",
|
||||
parent_id: None,
|
||||
},
|
||||
Some(&token),
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(alpha_resp.status(), StatusCode::CREATED);
|
||||
let alpha_body = body_to_vec(alpha_resp.into_body()).await?;
|
||||
let alpha: FolderResponse = serde_json::from_slice(&alpha_body)?;
|
||||
|
||||
let archive_resp = app
|
||||
.post_json(
|
||||
"/api/folders",
|
||||
&CreateFolder {
|
||||
name: "Archive",
|
||||
parent_id: Some(alpha.folder.id),
|
||||
},
|
||||
Some(&token),
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(archive_resp.status(), StatusCode::CREATED);
|
||||
|
||||
let beta_resp = app
|
||||
.post_json(
|
||||
"/api/folders",
|
||||
&CreateFolder {
|
||||
name: "Beta",
|
||||
parent_id: None,
|
||||
},
|
||||
Some(&token),
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(beta_resp.status(), StatusCode::CREATED);
|
||||
|
||||
let tree_resp = app.get("/api/folders/tree", Some(&token)).await?;
|
||||
assert_eq!(tree_resp.status(), StatusCode::OK);
|
||||
let tree_body = body_to_vec(tree_resp.into_body()).await?;
|
||||
let tree: Vec<FolderTreeNodeResponse> = serde_json::from_slice(&tree_body)?;
|
||||
|
||||
assert_eq!(tree.len(), 2);
|
||||
assert_eq!(tree[0].name, "Alpha");
|
||||
assert_eq!(tree[0].children.len(), 1);
|
||||
assert_eq!(tree[0].children[0].name, "Archive");
|
||||
assert!(tree[0].children[0].children.is_empty());
|
||||
|
||||
assert_eq!(tree[1].name, "Beta");
|
||||
assert!(tree[1].children.is_empty());
|
||||
|
||||
app.cleanup().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_folder_parent_to_root() -> Result<()> {
|
||||
let _lock = acquire_db_lock().await;
|
||||
|
||||
Reference in New Issue
Block a user