use axum::{ Json, extract::{Path, Query, State}, http::{ HeaderValue, StatusCode, header::{CONTENT_DISPOSITION, CONTENT_TYPE}, }, response::{IntoResponse, Response}, }; use serde_json::{Value, json}; use crate::{ error::ApiError, routes::access::WorkspacePath, service::{ApprovalDecisionPayload, ApprovalsQuery, LogsQuery, UsageRequestQuery}, state::AppState, }; #[derive(serde::Deserialize)] pub struct WorkspaceLogPath { pub workspace_id: String, pub log_id: String, } #[derive(serde::Deserialize)] pub struct WorkspaceApprovalPath { pub workspace_id: String, pub approval_id: String, } #[derive(serde::Deserialize)] pub struct WorkspaceOperationUsagePath { pub workspace_id: String, pub operation_id: String, } #[derive(serde::Deserialize)] pub struct WorkspaceAgentUsagePath { pub workspace_id: String, pub agent_id: String, } pub async fn list_logs( Path(path): Path, Query(query): Query, State(state): State, ) -> Result, ApiError> { let items = state .service .list_logs(&path.workspace_id.as_str().into(), query) .await?; Ok(Json(json!(items))) } pub async fn export_logs_csv( Path(path): Path, Query(query): Query, State(state): State, ) -> Result { let csv = state .service .export_logs_csv(&path.workspace_id.as_str().into(), query) .await?; let mut response = (StatusCode::OK, csv).into_response(); response.headers_mut().insert( CONTENT_TYPE, HeaderValue::from_static("text/csv; charset=utf-8"), ); response.headers_mut().insert( CONTENT_DISPOSITION, HeaderValue::from_static("attachment; filename=\"crank-invocation-history.csv\""), ); Ok(response) } pub async fn export_usage_csv( Path(path): Path, Query(query): Query, State(state): State, ) -> Result { let csv = state .service .export_usage_csv(&path.workspace_id.as_str().into(), query) .await?; let mut response = (StatusCode::OK, csv).into_response(); response.headers_mut().insert( CONTENT_TYPE, HeaderValue::from_static("text/csv; charset=utf-8"), ); response.headers_mut().insert( CONTENT_DISPOSITION, HeaderValue::from_static("attachment; filename=\"crank-usage.csv\""), ); Ok(response) } pub async fn get_log( Path(path): Path, State(state): State, ) -> Result, ApiError> { let item = state .service .get_log( &path.workspace_id.as_str().into(), &path.log_id.as_str().into(), ) .await?; Ok(Json(json!(item))) } pub async fn list_approvals( Path(path): Path, Query(query): Query, State(state): State, ) -> Result, ApiError> { let items = state .service .list_approvals(&path.workspace_id.as_str().into(), query) .await?; Ok(Json(json!({ "items": items }))) } pub async fn get_approval( Path(path): Path, State(state): State, ) -> Result, ApiError> { let item = state .service .get_approval( &path.workspace_id.as_str().into(), &path.approval_id.as_str().into(), ) .await?; Ok(Json(json!(item))) } pub async fn approve_approval( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let item = state .service .approve_approval( &path.workspace_id.as_str().into(), &path.approval_id.as_str().into(), payload, ) .await?; Ok(Json(json!(item))) } pub async fn deny_approval( Path(path): Path, State(state): State, Json(payload): Json, ) -> Result, ApiError> { let item = state .service .deny_approval( &path.workspace_id.as_str().into(), &path.approval_id.as_str().into(), payload, ) .await?; Ok(Json(json!(item))) } pub async fn get_usage( Path(path): Path, Query(query): Query, State(state): State, ) -> Result, ApiError> { let usage = state .service .get_usage_overview(&path.workspace_id.as_str().into(), query) .await?; Ok(Json(json!(usage))) } pub async fn get_operation_usage( Path(path): Path, Query(query): Query, State(state): State, ) -> Result, ApiError> { let usage = state .service .get_operation_usage( &path.workspace_id.as_str().into(), &path.operation_id.as_str().into(), query, ) .await?; Ok(Json(json!(usage))) } pub async fn get_agent_usage( Path(path): Path, Query(query): Query, State(state): State, ) -> Result, ApiError> { let usage = state .service .get_agent_usage( &path.workspace_id.as_str().into(), &path.agent_id.as_str().into(), query, ) .await?; Ok(Json(json!(usage))) }