feat: add optional allow_binary parameter to item handlers
Co-authored-by: aider (openai/andrew/openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
@@ -13,7 +13,7 @@ use anyhow::{Result, anyhow};
|
|||||||
|
|
||||||
use crate::compression_engine::{CompressionType, get_compression_engine};
|
use crate::compression_engine::{CompressionType, get_compression_engine};
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::modes::server::common::{AppState, ApiResponse, ItemInfo, ItemContentInfo, TagsQuery, ListItemsQuery};
|
use crate::modes::server::common::{AppState, ApiResponse, ItemInfo, ItemContentInfo, TagsQuery, ListItemsQuery, ItemQuery};
|
||||||
use crate::common::is_binary::is_binary;
|
use crate::common::is_binary::is_binary;
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
@@ -211,7 +211,8 @@ pub async fn handle_delete_item(
|
|||||||
(status = 500, description = "Internal server error - Failed to retrieve item content")
|
(status = 500, description = "Internal server error - Failed to retrieve item content")
|
||||||
),
|
),
|
||||||
params(
|
params(
|
||||||
("tags" = Option<String>, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item matching ALL tags.")
|
("tags" = Option<String>, Query, description = "Comma-separated list of tags to filter by (e.g., 'important,work'). If specified, returns the latest item matching ALL tags."),
|
||||||
|
("allow_binary" = Option<bool>, Query, description = "Whether to include content for binary files (default: false). When false, binary files will only return metadata.")
|
||||||
),
|
),
|
||||||
security(
|
security(
|
||||||
("bearerAuth" = [])
|
("bearerAuth" = [])
|
||||||
@@ -240,7 +241,7 @@ pub async fn handle_get_item_latest(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(item) = item {
|
if let Some(item) = item {
|
||||||
match get_item_content_info(&item, &state.data_dir, &mut *conn).await {
|
match get_item_content_info(&item, &state.data_dir, &mut *conn, params.allow_binary).await {
|
||||||
Ok(content_info) => {
|
Ok(content_info) => {
|
||||||
let response = ApiResponse {
|
let response = ApiResponse {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -275,7 +276,8 @@ pub async fn handle_get_item_latest(
|
|||||||
(status = 500, description = "Internal server error - Failed to retrieve item content")
|
(status = 500, description = "Internal server error - Failed to retrieve item content")
|
||||||
),
|
),
|
||||||
params(
|
params(
|
||||||
("item_id" = i64, Path, description = "Unique identifier of the item to retrieve (must be positive)")
|
("item_id" = i64, Path, description = "Unique identifier of the item to retrieve (must be positive)"),
|
||||||
|
("allow_binary" = Option<bool>, Query, description = "Whether to include content for binary files (default: false). When false, binary files will only return metadata.")
|
||||||
),
|
),
|
||||||
security(
|
security(
|
||||||
("bearerAuth" = [])
|
("bearerAuth" = [])
|
||||||
@@ -285,6 +287,7 @@ pub async fn handle_get_item_latest(
|
|||||||
pub async fn handle_get_item(
|
pub async fn handle_get_item(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Path(item_id): Path<i64>,
|
Path(item_id): Path<i64>,
|
||||||
|
Query(params): Query<ItemQuery>,
|
||||||
) -> Result<Json<ApiResponse<ItemContentInfo>>, StatusCode> {
|
) -> Result<Json<ApiResponse<ItemContentInfo>>, StatusCode> {
|
||||||
// Validate that item ID is positive to prevent path traversal issues
|
// Validate that item ID is positive to prevent path traversal issues
|
||||||
if item_id <= 0 {
|
if item_id <= 0 {
|
||||||
@@ -297,7 +300,7 @@ pub async fn handle_get_item(
|
|||||||
warn!("Failed to get item {} for content: {}", item_id, e);
|
warn!("Failed to get item {} for content: {}", item_id, e);
|
||||||
StatusCode::INTERNAL_SERVER_ERROR
|
StatusCode::INTERNAL_SERVER_ERROR
|
||||||
})? {
|
})? {
|
||||||
match get_item_content_info(&item, &state.data_dir, &mut *conn).await {
|
match get_item_content_info(&item, &state.data_dir, &mut *conn, params.allow_binary).await {
|
||||||
Ok(content_info) => {
|
Ok(content_info) => {
|
||||||
let response = ApiResponse {
|
let response = ApiResponse {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -453,7 +456,7 @@ async fn get_item_content(item: &db::Item, data_dir: &PathBuf) -> Result<String>
|
|||||||
Ok(content)
|
Ok(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_item_content_info(item: &db::Item, data_dir: &PathBuf, conn: &mut rusqlite::Connection) -> Result<ItemContentInfo> {
|
async fn get_item_content_info(item: &db::Item, data_dir: &PathBuf, conn: &mut rusqlite::Connection, allow_binary: bool) -> Result<ItemContentInfo> {
|
||||||
let item_id = item.id.ok_or_else(|| anyhow!("Item missing ID"))?;
|
let item_id = item.id.ok_or_else(|| anyhow!("Item missing ID"))?;
|
||||||
|
|
||||||
// Validate that item ID is positive to prevent path traversal issues
|
// Validate that item ID is positive to prevent path traversal issues
|
||||||
@@ -487,8 +490,8 @@ async fn get_item_content_info(item: &db::Item, data_dir: &PathBuf, conn: &mut r
|
|||||||
is_binary(&buffer[..bytes_read])
|
is_binary(&buffer[..bytes_read])
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get content if not binary
|
// Get content if not binary or if binary is allowed
|
||||||
let content = if is_binary {
|
let content = if is_binary && !allow_binary {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
match get_item_content(item, data_dir).await {
|
match get_item_content(item, data_dir).await {
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ pub struct ItemContentInfo {
|
|||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct TagsQuery {
|
pub struct TagsQuery {
|
||||||
pub tags: Option<String>,
|
pub tags: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub allow_binary: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -79,6 +81,12 @@ pub struct ListItemsQuery {
|
|||||||
pub count: Option<u32>,
|
pub count: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct ItemQuery {
|
||||||
|
#[serde(default)]
|
||||||
|
pub allow_binary: bool,
|
||||||
|
}
|
||||||
|
|
||||||
fn check_bearer_auth(auth_str: &str, expected_password: &str) -> bool {
|
fn check_bearer_auth(auth_str: &str, expected_password: &str) -> bool {
|
||||||
auth_str.starts_with("Bearer ") && &auth_str[7..] == expected_password
|
auth_str.starts_with("Bearer ") && &auth_str[7..] == expected_password
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user