This commit is contained in:
2025-11-05 23:01:42 +01:00
parent c193b30c8e
commit 911051e75d
11 changed files with 275 additions and 68 deletions
+30 -41
View File
@@ -75,16 +75,11 @@ async fn api_token_crud_flow() -> Result<()> {
app.insert_user(username, password, "admin").await?;
let access_token = app.login_token(username, password).await?;
let legacy_set_id = ensure_capability_set_slug(
&app,
&access_token,
"legacy_webdav",
LEGACY_WEBDAV_CAPS,
)
.await?;
let legacy_set_id =
ensure_capability_set_slug(&app, &access_token, "legacy_webdav", LEGACY_WEBDAV_CAPS)
.await?;
let created =
create_token(&app, &access_token, Some("dav"), legacy_set_id, None).await?;
let created = create_token(&app, &access_token, Some("dav"), legacy_set_id, None).await?;
let token_id = created.info.id;
assert_eq!(created.info.label.as_deref(), Some("dav"));
assert!(created.info.last_used_at.is_none());
@@ -110,13 +105,8 @@ async fn api_token_crud_flow() -> Result<()> {
})
.await?;
let readonly_set_id = ensure_capability_set_slug(
&app,
&access_token,
"readonly",
READ_ONLY_CAPS,
)
.await?;
let readonly_set_id =
ensure_capability_set_slug(&app, &access_token, "readonly", READ_ONLY_CAPS).await?;
let readonly_token =
create_token(&app, &access_token, Some("readonly"), readonly_set_id, None).await?;
@@ -134,9 +124,11 @@ async fn api_token_crud_flow() -> Result<()> {
delete_token(&app, &access_token, token_id).await?;
let listed_after = list_tokens(&app, &access_token).await?;
assert_eq!(listed_after.len(), 1);
assert_eq!(listed_after[0].id, token_id);
assert!(listed_after[0].revoked_at.is_some());
let revoked_entry = listed_after
.iter()
.find(|entry| entry.id == token_id)
.expect("revoked token still listed");
assert!(revoked_entry.revoked_at.is_some());
app.cleanup().await?;
Ok(())
@@ -152,16 +144,11 @@ async fn webdav_basic_auth_uses_api_tokens() -> Result<()> {
app.insert_user(username, password, "admin").await?;
let access_token = app.login_token(username, password).await?;
let legacy_set_id = ensure_capability_set_slug(
&app,
&access_token,
"legacy_webdav",
LEGACY_WEBDAV_CAPS,
)
.await?;
let legacy_set_id =
ensure_capability_set_slug(&app, &access_token, "legacy_webdav", LEGACY_WEBDAV_CAPS)
.await?;
let created =
create_token(&app, &access_token, Some("webdav"), legacy_set_id, None).await?;
let created = create_token(&app, &access_token, Some("webdav"), legacy_set_id, None).await?;
let token_id = created.info.id;
let router = webdav::create_router().with_state(app.state.clone());
@@ -230,13 +217,8 @@ async fn webdav_basic_auth_uses_api_tokens() -> Result<()> {
assert_eq!(response.status(), StatusCode::MULTI_STATUS);
// Token without webdav_read cannot authenticate.
let read_only_set_id = ensure_capability_set_slug(
&app,
&access_token,
"documents_read",
READ_ONLY_CAPS,
)
.await?;
let read_only_set_id =
ensure_capability_set_slug(&app, &access_token, "documents_read", READ_ONLY_CAPS).await?;
let limited_token =
create_token(&app, &access_token, Some("limited"), read_only_set_id, None).await?;
@@ -264,8 +246,14 @@ async fn webdav_basic_auth_uses_api_tokens() -> Result<()> {
)
.await?;
let upgraded_token =
create_token(&app, &access_token, Some("limited-webdav"), limited_set_id, None).await?;
let upgraded_token = create_token(
&app,
&access_token,
Some("limited-webdav"),
limited_set_id,
None,
)
.await?;
assert_eq!(upgraded_token.info.capability_set_id, limited_set_id);
let upgraded_request = Request::builder()
@@ -394,16 +382,17 @@ async fn find_capability_set_slug(
slug: &str,
) -> Result<Option<Uuid>> {
let sets = list_capability_sets(app, access_token).await?;
Ok(sets.into_iter().find(|set| set.slug == slug).map(|set| set.id))
Ok(sets
.into_iter()
.find(|set| set.slug == slug)
.map(|set| set.id))
}
async fn list_capability_sets(
app: &TestApp,
access_token: &str,
) -> Result<Vec<CapabilitySetSummary>> {
let response = app
.get("/api/capability-sets", Some(access_token))
.await?;
let response = app.get("/api/capability-sets", Some(access_token)).await?;
assert_eq!(response.status(), StatusCode::OK);
let body = body_to_vec(response.into_body()).await?;
Ok(serde_json::from_slice(&body)?)
+4 -1
View File
@@ -46,7 +46,10 @@ async fn capability_set_crud_flow() -> Result<()> {
let capabilities: Vec<String> = serde_json::from_slice(&capabilities_body)?;
assert!(capabilities.contains(&"documents:read".to_string()));
assert!(capabilities.contains(&"capability_sets:write".to_string()));
assert_eq!(capabilities.len(), 18);
assert_eq!(
capabilities.len(),
papercrate::models::ApiCapability::variants().len()
);
// Create a new capability set.
let create = app
+79
View File
@@ -277,6 +277,85 @@ async fn upload_document_with_custom_title_sets_filename() -> Result<()> {
Ok(())
}
#[tokio::test]
async fn document_list_sorting_controls() -> Result<()> {
let _lock = acquire_db_lock().await;
let app = TestApp::new().await?;
let password = "passw0rd";
app.insert_user("sorting", password, "admin").await?;
let token = app.login_token("sorting", password).await?;
let first = app
.upload_document_with_options(
"/api/documents",
"alpha.txt",
"text/plain",
b"alpha",
None,
Some("Alpha"),
None,
&token,
)
.await?;
assert!(first.status().is_success());
let first_body = body_to_vec(first.into_body()).await?;
let first_doc: DocumentDetail = serde_json::from_slice(&first_body)?;
let second = app
.upload_document_with_options(
"/api/documents",
"zulu.txt",
"text/plain",
b"zulu",
None,
Some("Zulu"),
None,
&token,
)
.await?;
assert!(second.status().is_success());
let second_body = body_to_vec(second.into_body()).await?;
let second_doc: DocumentDetail = serde_json::from_slice(&second_body)?;
// Default sort should be title ASC => Alpha first.
let default_resp = app.get("/api/documents", Some(&token)).await?;
assert_eq!(default_resp.status(), StatusCode::OK);
let default_body = body_to_vec(default_resp.into_body()).await?;
let default_list: Vec<DocumentListItem> = serde_json::from_slice(&default_body)?;
assert_eq!(default_list.len(), 2);
assert_eq!(default_list[0].id, first_doc.document.id);
assert_eq!(default_list[1].id, second_doc.document.id);
// Sort by created_at DESC, expecting most recent (second) first.
let created_desc = app
.get("/api/documents?sort=created_at&dir=desc", Some(&token))
.await?;
assert_eq!(created_desc.status(), StatusCode::OK);
let created_body = body_to_vec(created_desc.into_body()).await?;
let created_list: Vec<DocumentListItem> = serde_json::from_slice(&created_body)?;
assert_eq!(created_list.len(), 2);
assert_eq!(created_list[0].id, second_doc.document.id);
assert_eq!(created_list[1].id, first_doc.document.id);
// Folder contents respects the same parameters.
let folder_resp = app
.get(
"/api/folders/root/contents?sort=created_at&dir=desc",
Some(&token),
)
.await?;
assert_eq!(folder_resp.status(), StatusCode::OK);
let folder_body = body_to_vec(folder_resp.into_body()).await?;
let folder_contents: FolderContents = serde_json::from_slice(&folder_body)?;
assert_eq!(folder_contents.documents.len(), 2);
assert_eq!(folder_contents.documents[0].id, second_doc.document.id);
assert_eq!(folder_contents.documents[1].id, first_doc.document.id);
app.cleanup().await?;
Ok(())
}
#[tokio::test]
async fn duplicate_and_restore_document() -> Result<()> {
let _lock = acquire_db_lock().await;