feat: implement content retrieval for REST API endpoints

Co-authored-by: aider (openai/andrew/openrouter/anthropic/claude-sonnet-4) <aider@aider.chat>
This commit is contained in:
Andrew Phillips
2025-08-10 21:46:27 -03:00
parent 08f3c3e9e5
commit 35ae5776c0

View File

@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{Result, anyhow};
use axum::{
extract::{ConnectInfo, Path, Query, State},
http::{HeaderMap, StatusCode},
@@ -11,6 +11,7 @@ use log::{debug, info, warn};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::HashMap;
use std::io::Read;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::str::FromStr;
@@ -20,6 +21,7 @@ use tower_http::cors::CorsLayer;
use tower::ServiceBuilder;
use tower_http::trace::TraceLayer;
use crate::compression_engine::{CompressionType, get_compression_engine};
use crate::db;
use crate::Args;
@@ -441,15 +443,26 @@ async fn handle_get_content_latest(
})?
};
if let Some(_item) = item {
// Get the actual content - this would need to be implemented
// based on how content is stored and retrieved in your system
let response = ApiResponse::<String> {
success: false,
data: None,
error: Some("Content retrieval not yet implemented".to_string()),
};
Ok(Json(response))
if let Some(item) = item {
match get_item_content(&item, &state.data_dir).await {
Ok(content) => {
let response = ApiResponse {
success: true,
data: Some(content),
error: None,
};
Ok(Json(response))
}
Err(e) => {
warn!("Failed to get content for item {}: {}", item.id.unwrap_or(0), e);
let response = ApiResponse::<String> {
success: false,
data: None,
error: Some(format!("Failed to retrieve content: {}", e)),
};
Ok(Json(response))
}
}
} else {
Err(StatusCode::NOT_FOUND)
}
@@ -468,20 +481,37 @@ async fn handle_get_content(
}
if let Ok(id) = item_id.parse::<i64>() {
// Validate that item ID is positive to prevent path traversal issues
if id <= 0 {
warn!("Invalid item ID {} from {}", id, addr);
return Err(StatusCode::BAD_REQUEST);
}
let mut conn = state.db.lock().await;
if let Some(_item) = db::get_item(&mut *conn, id).map_err(|e| {
if let Some(item) = db::get_item(&mut *conn, id).map_err(|e| {
warn!("Failed to get item {} for content: {}", id, e);
StatusCode::INTERNAL_SERVER_ERROR
})? {
// Get the actual content - this would need to be implemented
// based on how content is stored and retrieved in your system
let response = ApiResponse::<String> {
success: false,
data: None,
error: Some("Content retrieval not yet implemented".to_string()),
};
Ok(Json(response))
match get_item_content(&item, &state.data_dir).await {
Ok(content) => {
let response = ApiResponse {
success: true,
data: Some(content),
error: None,
};
Ok(Json(response))
}
Err(e) => {
warn!("Failed to get content for item {}: {}", id, e);
let response = ApiResponse::<String> {
success: false,
data: None,
error: Some(format!("Failed to retrieve content: {}", e)),
};
Ok(Json(response))
}
}
} else {
Err(StatusCode::NOT_FOUND)
}
@@ -703,6 +733,28 @@ async fn handle_openapi() -> Json<serde_json::Value> {
Json(openapi_spec)
}
async fn get_item_content(item: &db::Item, data_dir: &PathBuf) -> Result<String> {
let item_id = item.id.ok_or_else(|| anyhow!("Item missing ID"))?;
// Validate that item ID is positive to prevent path traversal issues
if item_id <= 0 {
return Err(anyhow!("Invalid item ID: {}", item_id));
}
let mut item_path = data_dir.clone();
item_path.push(item_id.to_string());
let compression_type = CompressionType::from_str(&item.compression)?;
let compression_engine = get_compression_engine(compression_type)?;
// Read the content using the compression engine
let mut reader = compression_engine.open(item_path)?;
let mut content = String::new();
reader.read_to_string(&mut content)?;
Ok(content)
}
async fn handle_swagger_ui() -> Html<&'static str> {
let html = r#"<!DOCTYPE html>
<html>