refactor(api): remove 5 deprecated list endpoints superseded by /resources
The normalized cursor-paginated /resources API is live and the bundled
frontend already uses it for favorites, recent, trash and grants. These five
deprecated old-format endpoints had no remaining frontend or protocol
consumers (the Nextcloud handlers call the service layer directly, not these
HTTP routes), so remove them for a uniform API and less duplicate listing
logic:
- GET /api/folders/{id}/contents → use /api/folders/{id}/resources
- GET /api/folders/{id}/contents/paginated → use /api/folders/{id}/resources
- GET /api/favorites → use /api/favorites/resources
- GET /api/recent → use /api/recent/resources
- GET /api/trash → use /api/trash/resources
Removes the HTTP handlers, their routes, OpenAPI path registrations, and the
now-dead list_folder_contents{,_paginated}_impl helpers + unused imports. The
underlying service methods (favorites_service.get_favorites,
trash_service.get_trash_items, etc.) are KEPT — the Nextcloud OCS/trashbin
handlers depend on them.
Deliberately NOT removed: GET /api/folders/{id}/listing. It is still the Files
view's primary data path and offers ETag/304 conditional caching plus
one-shot favorite/share badge sets that /resources does not yet provide;
migrating it needs a separate parity pass on /resources first.
Updates the OpenAPI structure test and the two docs that referenced the
removed paths. `cargo clippy -D warnings` clean; 443 lib tests pass; OpenAPI
regenerates with the 5 paths gone and the /resources replacements present.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -301,17 +301,17 @@ avoids a breaking API change when a second sort is added later.
|
|||||||
| `GET /api/photos` | ⚠️ `before` header | ❌ | Non-standard — migrate to body cursor |
|
| `GET /api/photos` | ⚠️ `before` header | ❌ | Non-standard — migrate to body cursor |
|
||||||
| `GET /api/search` | ❌ offset | ✅ | Migrate cursor |
|
| `GET /api/search` | ❌ offset | ✅ | Migrate cursor |
|
||||||
| `GET /api/folders/paginated` | ❌ page | ❌ | Migrate cursor |
|
| `GET /api/folders/paginated` | ❌ page | ❌ | Migrate cursor |
|
||||||
| `GET /api/folders/{id}/contents/paginated` | ❌ page | ❌ | Migrate cursor |
|
| `GET /api/folders/{id}/contents/paginated` | — | — | ✅ **Removed** — use `/api/folders/{id}/resources` |
|
||||||
| `GET /api/admin/users` | ❌ offset | ❌ | Migrate cursor |
|
| `GET /api/admin/users` | ❌ offset | ❌ | Migrate cursor |
|
||||||
| `GET /api/address-books/{id}/contacts` | ❌ offset | ❌ | Migrate cursor |
|
| `GET /api/address-books/{id}/contacts` | ❌ offset | ❌ | Migrate cursor |
|
||||||
| `GET /api/shares` | ❌ page | ❌ | Migrate cursor |
|
| `GET /api/shares` | ❌ page | ❌ | Migrate cursor |
|
||||||
| `GET /api/playlists` | ❌ offset | ❌ | Migrate cursor |
|
| `GET /api/playlists` | ❌ offset | ❌ | Migrate cursor |
|
||||||
| `GET /api/recent` | ❌ limit only | ❌ | Migrate cursor |
|
| `GET /api/recent` | — | — | ✅ **Removed** — use `/api/recent/resources` |
|
||||||
| `GET /api/files` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
| `GET /api/files` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
||||||
| `GET /api/folders` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
| `GET /api/folders` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
||||||
| `GET /api/folders/{id}/listing` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
| `GET /api/folders/{id}/listing` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
||||||
| `GET /api/favorites` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
| `GET /api/favorites` | — | — | ✅ **Removed** — use `/api/favorites/resources` |
|
||||||
| `GET /api/trash` | ❌ **none** | ❌ | Unbounded — **urgent** |
|
| `GET /api/trash` | — | — | ✅ **Removed** — use `/api/trash/resources` |
|
||||||
| `GET /api/grants/incoming` | ❌ **none** | ❌ | Unbounded |
|
| `GET /api/grants/incoming` | ❌ **none** | ❌ | Unbounded |
|
||||||
| `GET /api/grants/outgoing` | ❌ **none** | ❌ | Unbounded |
|
| `GET /api/grants/outgoing` | ❌ **none** | ❌ | Unbounded |
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ All scenarios load `baseline.json` at startup and set `thresholds` dynamically f
|
|||||||
|
|
||||||
**Endpoint contracts (confirmed by exploration):**
|
**Endpoint contracts (confirmed by exploration):**
|
||||||
- Login: `POST /api/auth/login` body `{username, password}` → `{access_token, ...}`.
|
- Login: `POST /api/auth/login` body `{username, password}` → `{access_token, ...}`.
|
||||||
- Folder ops: `POST /api/folders`, `GET /api/folders/{id}/contents` (or `/contents/paginated` at high depth), `PUT /api/folders/{id}/move`, `POST /api/batch/folders/copy`, `DELETE /api/folders/{id}`. Handlers in `src/interfaces/api/handlers/folder_handler.rs` and `batch_handler.rs`.
|
- Folder ops: `POST /api/folders`, `GET /api/folders/{id}/resources` (cursor-paginated; replaced the removed `/contents` + `/contents/paginated`), `PUT /api/folders/{id}/move`, `POST /api/batch/folders/copy`, `DELETE /api/folders/{id}`. Handlers in `src/interfaces/api/handlers/folder_handler.rs` and `batch_handler.rs`.
|
||||||
- Grants: `POST /api/grants` (subject `{type, id|email}`, resource `{type, id}`, `role` or `permissions[]`), `GET /api/grants?resource_type=folder&resource_id=…`. Handler `src/interfaces/api/handlers/grant_handler.rs`.
|
- Grants: `POST /api/grants` (subject `{type, id|email}`, resource `{type, id}`, `role` or `permissions[]`), `GET /api/grants?resource_type=folder&resource_id=…`. Handler `src/interfaces/api/handlers/grant_handler.rs`.
|
||||||
- Groups: `POST /api/groups` (admin), `POST /api/groups/{id}/members` body `{user_id}` or `{group_id}`. Handler `src/interfaces/api/handlers/subject_group_handler.rs`. Nesting limit is 8 — `--group-depth 3` is well inside.
|
- Groups: `POST /api/groups` (admin), `POST /api/groups/{id}/members` body `{user_id}` or `{group_id}`. Handler `src/interfaces/api/handlers/subject_group_handler.rs`. Nesting limit is 8 — `--group-depth 3` is well inside.
|
||||||
- Files: multipart `POST /api/files/upload` with fields `folder_id` + `file`.
|
- Files: multipart `POST /api/files/upload` with fields `folder_id` + `file`.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::application::dtos::display_helpers::{
|
use crate::application::dtos::display_helpers::{
|
||||||
@@ -37,52 +37,6 @@ pub struct BatchFavoritesRequest {
|
|||||||
pub items: Vec<BatchFavoriteItem>,
|
pub items: Vec<BatchFavoriteItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handler for favorite-related API endpoints
|
|
||||||
///
|
|
||||||
/// # Deprecated
|
|
||||||
/// Use `GET /api/favorites/resources` instead. This endpoint is kept for
|
|
||||||
/// backwards compatibility but will be removed in a future release.
|
|
||||||
#[deprecated = "Use GET /api/favorites/resources instead"]
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "/api/favorites",
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "List of favorites (deprecated — use /api/favorites/resources)", body = Vec<crate::application::dtos::favorites_dto::FavoriteItemDto>)
|
|
||||||
),
|
|
||||||
security(("bearerAuth" = [])),
|
|
||||||
tag = "favorites"
|
|
||||||
)]
|
|
||||||
pub async fn get_favorites(
|
|
||||||
State(favorites_service): State<Arc<FavoritesService>>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user_id = auth_user.id;
|
|
||||||
warn!(
|
|
||||||
"Deprecated endpoint called: GET /api/favorites — use GET /api/favorites/resources instead"
|
|
||||||
);
|
|
||||||
|
|
||||||
match favorites_service.get_favorites(user_id).await {
|
|
||||||
Ok(favorites) => {
|
|
||||||
info!(
|
|
||||||
"Retrieved {} favorites for user {}",
|
|
||||||
favorites.len(),
|
|
||||||
auth_user.id
|
|
||||||
);
|
|
||||||
(StatusCode::OK, Json(serde_json::json!(favorites))).into_response()
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("Error retrieving favorites: {}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json(serde_json::json!({
|
|
||||||
"error": "Failed to retrieve favorites"
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add an item to user's favorites
|
/// Add an item to user's favorites
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -111,16 +111,6 @@ impl FolderHandler {
|
|||||||
Self::list_folders_scoped(service, None, &auth_user).await
|
Self::list_folders_scoped(service, None, &auth_user).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lists contents of a specific folder by its ID.
|
|
||||||
/// Scoped to the authenticated user's folders.
|
|
||||||
pub(super) async fn list_folder_contents_impl(
|
|
||||||
State(service): State<AppState>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
Path(id): Path<String>,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
Self::list_folders_scoped(service, Some(&id), &auth_user).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lists root folders with pagination.
|
/// Lists root folders with pagination.
|
||||||
/// Scoped to the authenticated user — only returns folders owned by this user.
|
/// Scoped to the authenticated user — only returns folders owned by this user.
|
||||||
pub(super) async fn list_root_folders_paginated_impl(
|
pub(super) async fn list_root_folders_paginated_impl(
|
||||||
@@ -131,22 +121,6 @@ impl FolderHandler {
|
|||||||
Self::list_folders_scoped(service, None, &auth_user).await
|
Self::list_folders_scoped(service, None, &auth_user).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lists sub-folders inside a folder with pagination.
|
|
||||||
pub(super) async fn list_folder_contents_paginated_impl(
|
|
||||||
State(service): State<AppState>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
Path(id): Path<String>,
|
|
||||||
pagination: Query<PaginationRequestDto>,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
match service
|
|
||||||
.list_folders_paginated_with_perms(Some(&id), auth_user.id, &pagination)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(paginated_result) => (StatusCode::OK, Json(paginated_result)).into_response(),
|
|
||||||
Err(err) => AppError::from(err).into_response(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Internal helper: lists folders scoped to the authenticated user.
|
/// Internal helper: lists folders scoped to the authenticated user.
|
||||||
/// Uses `list_folders_for_owner` — the DB query filters by `user_id`,
|
/// Uses `list_folders_for_owner` — the DB query filters by `user_id`,
|
||||||
/// so no data from other users ever leaves the database.
|
/// so no data from other users ever leaves the database.
|
||||||
@@ -525,30 +499,6 @@ pub async fn list_root_folders(
|
|||||||
FolderHandler::list_root_folders_impl(state, auth_user).await
|
FolderHandler::list_root_folders_impl(state, auth_user).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated = "Use /api/folders/{id}/resources instead"]
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "/api/folders/{id}/contents",
|
|
||||||
params(("id" = String, Path, description = "Folder ID")),
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "List of sub-folders", body = Vec<FolderDto>),
|
|
||||||
(status = 404, description = "Folder not found"),
|
|
||||||
),
|
|
||||||
security(("bearerAuth" = [])),
|
|
||||||
tag = "folders"
|
|
||||||
)]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
pub async fn list_folder_contents(
|
|
||||||
state: State<AppState>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
path: Path<String>,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
tracing::warn!(
|
|
||||||
"Deprecated endpoint called: GET /api/folders/{{id}}/contents — use GET /api/folders/{{id}}/resources?resource_types=folder instead"
|
|
||||||
);
|
|
||||||
FolderHandler::list_folder_contents_impl(state, auth_user, path).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
path = "/api/folders/paginated",
|
path = "/api/folders/paginated",
|
||||||
@@ -567,34 +517,6 @@ pub async fn list_root_folders_paginated(
|
|||||||
FolderHandler::list_root_folders_paginated_impl(state, auth_user, pagination).await
|
FolderHandler::list_root_folders_paginated_impl(state, auth_user, pagination).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated = "Use /api/folders/{id}/resources instead"]
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "/api/folders/{id}/contents/paginated",
|
|
||||||
params(
|
|
||||||
("id" = String, Path, description = "Folder ID"),
|
|
||||||
PaginationRequestDto,
|
|
||||||
),
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "Paginated list of sub-folders"),
|
|
||||||
(status = 404, description = "Folder not found"),
|
|
||||||
),
|
|
||||||
security(("bearerAuth" = [])),
|
|
||||||
tag = "folders"
|
|
||||||
)]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
pub async fn list_folder_contents_paginated(
|
|
||||||
state: State<AppState>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
path: Path<String>,
|
|
||||||
pagination: Query<PaginationRequestDto>,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
tracing::warn!(
|
|
||||||
"Deprecated endpoint called: GET /api/folders/{{id}}/contents/paginated — use GET /api/folders/{{id}}/resources instead"
|
|
||||||
);
|
|
||||||
FolderHandler::list_folder_contents_paginated_impl(state, auth_user, path, pagination).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[deprecated = "Use /api/folders/{id}/resources instead"]
|
#[deprecated = "Use /api/folders/{id}/resources instead"]
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|||||||
@@ -4,9 +4,8 @@ use axum::{
|
|||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info};
|
||||||
|
|
||||||
use crate::application::dtos::display_helpers::{
|
use crate::application::dtos::display_helpers::{
|
||||||
category_for, format_file_size, icon_class_for, icon_special_class_for,
|
category_for, format_file_size, icon_class_for, icon_special_class_for,
|
||||||
@@ -24,50 +23,6 @@ use crate::interfaces::errors::AppError;
|
|||||||
use crate::interfaces::middleware::auth::AuthUser;
|
use crate::interfaces::middleware::auth::AuthUser;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
/// Query parameters for getting recent items
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct GetRecentParams {
|
|
||||||
#[serde(default)]
|
|
||||||
limit: Option<i32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get user's recent items (deprecated — use `GET /api/recent/resources` instead)
|
|
||||||
#[deprecated = "Use GET /api/recent/resources instead"]
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "/api/recent",
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "List of recent items", body = Vec<crate::application::dtos::recent_dto::RecentItemDto>)
|
|
||||||
),
|
|
||||||
security(("bearerAuth" = [])),
|
|
||||||
tag = "recent"
|
|
||||||
)]
|
|
||||||
pub async fn get_recent_items(
|
|
||||||
State(recent_service): State<Arc<RecentService>>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
Query(params): Query<GetRecentParams>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
let user_id = auth_user.id;
|
|
||||||
warn!("Deprecated endpoint called: GET /api/recent — use GET /api/recent/resources instead");
|
|
||||||
|
|
||||||
match recent_service.get_recent_items(user_id, params.limit).await {
|
|
||||||
Ok(items) => {
|
|
||||||
info!("Retrieved {} recent items for user", items.len());
|
|
||||||
(StatusCode::OK, Json(items)).into_response()
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
error!("Error retrieving recent items: {}", err);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json(serde_json::json!({
|
|
||||||
"error": "Failed to retrieve recent items"
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
.into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Record access to an item
|
/// Record access to an item
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
post,
|
post,
|
||||||
|
|||||||
@@ -12,69 +12,6 @@ use crate::interfaces::errors::AppError;
|
|||||||
use crate::interfaces::middleware::auth::AuthUser;
|
use crate::interfaces::middleware::auth::AuthUser;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Gets all items in the trash for the current user.
|
|
||||||
///
|
|
||||||
/// # Deprecated
|
|
||||||
/// Use `GET /api/trash/resources` instead. This endpoint is kept for
|
|
||||||
/// backwards compatibility but will be removed in a future release.
|
|
||||||
#[deprecated = "Use GET /api/trash/resources instead"]
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "/api/trash",
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "List of trashed items (deprecated — use /api/trash/resources)"),
|
|
||||||
(status = 501, description = "Trash feature not enabled")
|
|
||||||
),
|
|
||||||
security(("bearerAuth" = [])),
|
|
||||||
tag = "trash"
|
|
||||||
)]
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub async fn get_trash_items(
|
|
||||||
State(state): State<Arc<AppState>>,
|
|
||||||
auth_user: AuthUser,
|
|
||||||
) -> (StatusCode, Json<serde_json::Value>) {
|
|
||||||
// SECURITY: Always use the authenticated user's ID from the JWT token.
|
|
||||||
// Never allow user ID override via query parameters to prevent
|
|
||||||
// privilege escalation attacks.
|
|
||||||
let effective_user = auth_user.id;
|
|
||||||
|
|
||||||
warn!(
|
|
||||||
"Deprecated endpoint called: GET /api/trash — use GET /api/trash/resources instead (user {effective_user})"
|
|
||||||
);
|
|
||||||
|
|
||||||
debug!("Request to list trash items for user {}", effective_user);
|
|
||||||
|
|
||||||
let trash_service = match state.trash_service.as_ref() {
|
|
||||||
Some(service) => service,
|
|
||||||
None => {
|
|
||||||
return (
|
|
||||||
StatusCode::NOT_IMPLEMENTED,
|
|
||||||
Json(json!({
|
|
||||||
"error": "Trash feature is not enabled"
|
|
||||||
})),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = trash_service.get_trash_items(effective_user).await;
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(items) => {
|
|
||||||
debug!("Found {} items in trash", items.len());
|
|
||||||
(StatusCode::OK, Json(json!(items)))
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error retrieving trash items: {:?}", e);
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
Json(json!({
|
|
||||||
"error": "Error retrieving trash items"
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cursor-paginated list of a user's trashed resources.
|
/// Cursor-paginated list of a user's trashed resources.
|
||||||
///
|
///
|
||||||
/// Sorts by `deletion_date` (default — soonest expiry first), `trashed_at`
|
/// Sorts by `deletion_date` (default — soonest expiry first), `trashed_at`
|
||||||
|
|||||||
+10
-10
@@ -98,9 +98,7 @@ use crate::interfaces::api::handlers::file_handler::MoveFilePayload;
|
|||||||
handlers::folder_handler::create_folder,
|
handlers::folder_handler::create_folder,
|
||||||
handlers::folder_handler::get_folder,
|
handlers::folder_handler::get_folder,
|
||||||
handlers::folder_handler::list_root_folders,
|
handlers::folder_handler::list_root_folders,
|
||||||
handlers::folder_handler::list_folder_contents,
|
|
||||||
handlers::folder_handler::list_root_folders_paginated,
|
handlers::folder_handler::list_root_folders_paginated,
|
||||||
handlers::folder_handler::list_folder_contents_paginated,
|
|
||||||
handlers::folder_handler::list_folder_resources,
|
handlers::folder_handler::list_folder_resources,
|
||||||
handlers::folder_handler::list_folder_listing,
|
handlers::folder_handler::list_folder_listing,
|
||||||
handlers::folder_handler::rename_folder,
|
handlers::folder_handler::rename_folder,
|
||||||
@@ -130,7 +128,6 @@ use crate::interfaces::api::handlers::file_handler::MoveFilePayload;
|
|||||||
handlers::dedup_handler::get_blob,
|
handlers::dedup_handler::get_blob,
|
||||||
handlers::dedup_handler::recalculate_stats,
|
handlers::dedup_handler::recalculate_stats,
|
||||||
// Trash handlers (free functions)
|
// Trash handlers (free functions)
|
||||||
handlers::trash_handler::get_trash_items,
|
|
||||||
handlers::trash_handler::get_trash_resources,
|
handlers::trash_handler::get_trash_resources,
|
||||||
handlers::trash_handler::move_file_to_trash,
|
handlers::trash_handler::move_file_to_trash,
|
||||||
handlers::trash_handler::move_folder_to_trash,
|
handlers::trash_handler::move_folder_to_trash,
|
||||||
@@ -152,13 +149,11 @@ use crate::interfaces::api::handlers::file_handler::MoveFilePayload;
|
|||||||
handlers::share_handler::download_share_zip_root,
|
handlers::share_handler::download_share_zip_root,
|
||||||
handlers::share_handler::download_share_zip_subfolder,
|
handlers::share_handler::download_share_zip_subfolder,
|
||||||
// Favorites handlers (free functions)
|
// Favorites handlers (free functions)
|
||||||
handlers::favorites_handler::get_favorites,
|
|
||||||
handlers::favorites_handler::list_favorites_resources,
|
handlers::favorites_handler::list_favorites_resources,
|
||||||
handlers::favorites_handler::add_favorite,
|
handlers::favorites_handler::add_favorite,
|
||||||
handlers::favorites_handler::remove_favorite,
|
handlers::favorites_handler::remove_favorite,
|
||||||
handlers::favorites_handler::batch_add_favorites,
|
handlers::favorites_handler::batch_add_favorites,
|
||||||
// Recent handlers (free functions)
|
// Recent handlers (free functions)
|
||||||
handlers::recent_handler::get_recent_items,
|
|
||||||
handlers::recent_handler::list_recent_resources,
|
handlers::recent_handler::list_recent_resources,
|
||||||
handlers::recent_handler::record_item_access,
|
handlers::recent_handler::record_item_access,
|
||||||
handlers::recent_handler::remove_from_recent,
|
handlers::recent_handler::remove_from_recent,
|
||||||
@@ -433,18 +428,23 @@ mod tests {
|
|||||||
"expected at least 10 paths, got {}",
|
"expected at least 10 paths, got {}",
|
||||||
paths.paths.len()
|
paths.paths.len()
|
||||||
);
|
);
|
||||||
assert!(paths.paths.contains_key("/api/trash"), "missing /api/trash");
|
// The old grouped list endpoints (/api/trash, /api/favorites, /api/recent)
|
||||||
|
// were removed in favour of the normalized cursor-paginated /resources API.
|
||||||
|
assert!(
|
||||||
|
paths.paths.contains_key("/api/trash/resources"),
|
||||||
|
"missing /api/trash/resources"
|
||||||
|
);
|
||||||
assert!(
|
assert!(
|
||||||
paths.paths.contains_key("/api/shares"),
|
paths.paths.contains_key("/api/shares"),
|
||||||
"missing /api/shares"
|
"missing /api/shares"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
paths.paths.contains_key("/api/favorites"),
|
paths.paths.contains_key("/api/favorites/resources"),
|
||||||
"missing /api/favorites"
|
"missing /api/favorites/resources"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
paths.paths.contains_key("/api/recent"),
|
paths.paths.contains_key("/api/recent/resources"),
|
||||||
"missing /api/recent"
|
"missing /api/recent/resources"
|
||||||
);
|
);
|
||||||
|
|
||||||
let schemas = &spec
|
let schemas = &spec
|
||||||
|
|||||||
@@ -64,9 +64,9 @@ use crate::interfaces::api::handlers::file_handler::{
|
|||||||
};
|
};
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
use crate::interfaces::api::handlers::folder_handler::{
|
use crate::interfaces::api::handlers::folder_handler::{
|
||||||
create_folder, delete_folder_with_trash, download_folder_zip, get_folder, list_folder_contents,
|
create_folder, delete_folder_with_trash, download_folder_zip, get_folder, list_folder_listing,
|
||||||
list_folder_contents_paginated, list_folder_listing, list_folder_resources, list_root_folders,
|
list_folder_resources, list_root_folders, list_root_folders_paginated, move_folder,
|
||||||
list_root_folders_paginated, move_folder, rename_folder,
|
rename_folder,
|
||||||
};
|
};
|
||||||
use crate::interfaces::api::handlers::i18n_handler::{
|
use crate::interfaces::api::handlers::i18n_handler::{
|
||||||
get_locales, get_translations_by_locale, translate,
|
get_locales, get_translations_by_locale, translate,
|
||||||
@@ -198,11 +198,6 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
|||||||
.route("/", get(list_root_folders))
|
.route("/", get(list_root_folders))
|
||||||
.route("/paginated", get(list_root_folders_paginated))
|
.route("/paginated", get(list_root_folders_paginated))
|
||||||
.route("/{id}", get(get_folder))
|
.route("/{id}", get(get_folder))
|
||||||
.route("/{id}/contents", get(list_folder_contents))
|
|
||||||
.route(
|
|
||||||
"/{id}/contents/paginated",
|
|
||||||
get(list_folder_contents_paginated),
|
|
||||||
)
|
|
||||||
.route("/{id}/resources", get(list_folder_resources))
|
.route("/{id}/resources", get(list_folder_resources))
|
||||||
.route("/{id}/rename", put(rename_folder))
|
.route("/{id}/rename", put(rename_folder))
|
||||||
.route("/{id}/move", put(move_folder))
|
.route("/{id}/move", put(move_folder))
|
||||||
@@ -343,13 +338,9 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
|||||||
// Create a router without the i18n routes
|
// Create a router without the i18n routes
|
||||||
// Create routes for favorites if the service is available
|
// Create routes for favorites if the service is available
|
||||||
let favorites_router = if let Some(favorites_service) = favorites_service.clone() {
|
let favorites_router = if let Some(favorites_service) = favorites_service.clone() {
|
||||||
#[allow(deprecated)]
|
use crate::interfaces::api::handlers::favorites_handler::{self, list_favorites_resources};
|
||||||
use crate::interfaces::api::handlers::favorites_handler::{
|
|
||||||
self, get_favorites, list_favorites_resources,
|
|
||||||
};
|
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(get_favorites)) // deprecated — kept for external compat
|
|
||||||
.route("/resources", get(list_favorites_resources))
|
.route("/resources", get(list_favorites_resources))
|
||||||
.route("/batch", post(favorites_handler::batch_add_favorites))
|
.route("/batch", post(favorites_handler::batch_add_favorites))
|
||||||
.route(
|
.route(
|
||||||
@@ -367,11 +358,9 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
|||||||
|
|
||||||
// Create routes for recent items if the service is available
|
// Create routes for recent items if the service is available
|
||||||
let recent_router = if let Some(recent_service) = recent_service.clone() {
|
let recent_router = if let Some(recent_service) = recent_service.clone() {
|
||||||
#[allow(deprecated)]
|
|
||||||
use crate::interfaces::api::handlers::recent_handler;
|
use crate::interfaces::api::handlers::recent_handler;
|
||||||
|
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/", get(recent_handler::get_recent_items)) // deprecated — kept for external compat
|
|
||||||
.route("/resources", get(recent_handler::list_recent_resources))
|
.route("/resources", get(recent_handler::list_recent_resources))
|
||||||
.route(
|
.route(
|
||||||
"/{item_type}/{item_id}",
|
"/{item_type}/{item_id}",
|
||||||
@@ -475,11 +464,9 @@ pub fn create_api_routes(app_state: &Arc<AppState>) -> Router<Arc<AppState>> {
|
|||||||
if let Some(_trash_service_ref) = trash_service.clone() {
|
if let Some(_trash_service_ref) = trash_service.clone() {
|
||||||
tracing::info!("Setting up trash routes for trash view");
|
tracing::info!("Setting up trash routes for trash view");
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let trash_router = Router::new()
|
let trash_router = Router::new()
|
||||||
// Literal paths first — order matters for axum overlap handling
|
// Literal paths first — order matters for axum overlap handling
|
||||||
// when a wildcard like /{id} could otherwise capture them.
|
// when a wildcard like /{id} could otherwise capture them.
|
||||||
.route("/", get(trash_handler::get_trash_items)) // deprecated — kept for external compat
|
|
||||||
.route("/resources", get(trash_handler::get_trash_resources))
|
.route("/resources", get(trash_handler::get_trash_resources))
|
||||||
.route("/empty", delete(trash_handler::empty_trash))
|
.route("/empty", delete(trash_handler::empty_trash))
|
||||||
.route("/files/{id}", delete(trash_handler::move_file_to_trash))
|
.route("/files/{id}", delete(trash_handler::move_file_to_trash))
|
||||||
|
|||||||
Reference in New Issue
Block a user