feat: frontend-ready backend — pagination, auto-derivatives, list endpoints, bulk ops, OpenAPI
Pagination: count_by_owner + count_search on AssetRepository,
timeline/search return real total count (not page len).
Auto-derivatives: worker enqueues GenerateDerivative when
ExtractMetadata job completes, closing the upload→thumbnail gap.
List endpoints: GET /albums, GET /stacks with user scoping.
ListAlbumsHandler, ListStacksHandler, find_by_owner on AssetStackRepository.
Tag filtering: tag_name field on AssetFilters, JOIN asset_tags+tags
in postgres search/count queries.
Bulk operations: POST /assets/bulk-delete, POST /assets/bulk-tag.
Album update: PUT /albums/{id} with UpdateAlbumHandler (title, description).
OpenAPI: utoipa annotations on all 47 endpoints + all request/response
schemas registered. Scalar UI at /scalar covers full API.
This commit is contained in:
@@ -28,7 +28,7 @@ async fn returns_paginated_assets() {
|
||||
|
||||
let handler = GetTimelineHandler::new(asset_repo, meta_repo);
|
||||
|
||||
let page = handler
|
||||
let result = handler
|
||||
.execute(GetTimelineQuery {
|
||||
owner_id: owner,
|
||||
caller_id: None,
|
||||
@@ -38,7 +38,8 @@ async fn returns_paginated_assets() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(page.len(), 3);
|
||||
assert_eq!(result.items.len(), 3);
|
||||
assert_eq!(result.total, 5);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -48,7 +49,7 @@ async fn returns_empty_for_no_assets() {
|
||||
|
||||
let handler = GetTimelineHandler::new(asset_repo, meta_repo);
|
||||
|
||||
let page = handler
|
||||
let result = handler
|
||||
.execute(GetTimelineQuery {
|
||||
owner_id: SystemId::new(),
|
||||
caller_id: None,
|
||||
@@ -58,5 +59,6 @@ async fn returns_empty_for_no_assets() {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(page.is_empty());
|
||||
assert!(result.items.is_empty());
|
||||
assert_eq!(result.total, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user