meta: move public crates to packages/
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I928162008cb1ba02e1aa0e7aa971e8326a6a6964
This commit is contained in:
parent
70b0113d8a
commit
00bab69598
308 changed files with 53890 additions and 53889 deletions
150
packages/pinakes-server/src/routes/saved_searches.rs
Normal file
150
packages/pinakes-server/src/routes/saved_searches.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use axum::{
|
||||
Json,
|
||||
extract::{Path, State},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{error::ApiError, state::AppState};
|
||||
|
||||
#[derive(Debug, Deserialize, utoipa::ToSchema)]
|
||||
pub struct CreateSavedSearchRequest {
|
||||
pub name: String,
|
||||
pub query: String,
|
||||
pub sort_order: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, utoipa::ToSchema)]
|
||||
pub struct SavedSearchResponse {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub query: String,
|
||||
pub sort_order: Option<String>,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
}
|
||||
|
||||
const VALID_SORT_ORDERS: &[&str] = &[
|
||||
"date_asc",
|
||||
"date_desc",
|
||||
"name_asc",
|
||||
"name_desc",
|
||||
"size_asc",
|
||||
"size_desc",
|
||||
];
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/v1/searches",
|
||||
tag = "saved_searches",
|
||||
request_body = CreateSavedSearchRequest,
|
||||
responses(
|
||||
(status = 200, description = "Search saved", body = SavedSearchResponse),
|
||||
(status = 400, description = "Bad request"),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn create_saved_search(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<CreateSavedSearchRequest>,
|
||||
) -> Result<Json<SavedSearchResponse>, ApiError> {
|
||||
let name_len = req.name.chars().count();
|
||||
if name_len == 0 || name_len > 255 {
|
||||
return Err(ApiError(
|
||||
pinakes_core::error::PinakesError::InvalidOperation(
|
||||
"name must be 1-255 characters".into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
if req.query.is_empty() || req.query.len() > 2048 {
|
||||
return Err(ApiError(
|
||||
pinakes_core::error::PinakesError::InvalidOperation(
|
||||
"query must be 1-2048 bytes".into(),
|
||||
),
|
||||
));
|
||||
}
|
||||
if let Some(ref sort) = req.sort_order
|
||||
&& !VALID_SORT_ORDERS.contains(&sort.as_str())
|
||||
{
|
||||
return Err(ApiError(
|
||||
pinakes_core::error::PinakesError::InvalidOperation(format!(
|
||||
"sort_order must be one of: {}",
|
||||
VALID_SORT_ORDERS.join(", ")
|
||||
)),
|
||||
));
|
||||
}
|
||||
let id = uuid::Uuid::now_v7();
|
||||
state
|
||||
.storage
|
||||
.save_search(id, &req.name, &req.query, req.sort_order.as_deref())
|
||||
.await
|
||||
.map_err(ApiError)?;
|
||||
|
||||
Ok(Json(SavedSearchResponse {
|
||||
id: id.to_string(),
|
||||
name: req.name,
|
||||
query: req.query,
|
||||
sort_order: req.sort_order,
|
||||
created_at: chrono::Utc::now(),
|
||||
}))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/v1/searches",
|
||||
tag = "saved_searches",
|
||||
responses(
|
||||
(status = 200, description = "List of saved searches", body = Vec<SavedSearchResponse>),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn list_saved_searches(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<Json<Vec<SavedSearchResponse>>, ApiError> {
|
||||
let searches = state
|
||||
.storage
|
||||
.list_saved_searches()
|
||||
.await
|
||||
.map_err(ApiError)?;
|
||||
Ok(Json(
|
||||
searches
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
SavedSearchResponse {
|
||||
id: s.id.to_string(),
|
||||
name: s.name,
|
||||
query: s.query,
|
||||
sort_order: s.sort_order,
|
||||
created_at: s.created_at,
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/api/v1/searches/{id}",
|
||||
tag = "saved_searches",
|
||||
params(("id" = uuid::Uuid, Path, description = "Saved search ID")),
|
||||
responses(
|
||||
(status = 200, description = "Saved search deleted"),
|
||||
(status = 401, description = "Unauthorized"),
|
||||
(status = 404, description = "Not found"),
|
||||
(status = 500, description = "Internal server error"),
|
||||
),
|
||||
security(("bearer_auth" = []))
|
||||
)]
|
||||
pub async fn delete_saved_search(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||
state
|
||||
.storage
|
||||
.delete_saved_search(id)
|
||||
.await
|
||||
.map_err(ApiError)?;
|
||||
Ok(Json(serde_json::json!({ "deleted": true })))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue