haystack_server/ops/
nav.rs1use actix_web::{HttpRequest, HttpResponse, web};
30
31use haystack_core::data::{HCol, HDict, HGrid};
32use haystack_core::kinds::Kind;
33
34use crate::content;
35use crate::error::HaystackError;
36use crate::state::AppState;
37
38pub async fn handle(
45 req: HttpRequest,
46 body: String,
47 state: web::Data<AppState>,
48) -> Result<HttpResponse, HaystackError> {
49 let content_type = req
50 .headers()
51 .get("Content-Type")
52 .and_then(|v| v.to_str().ok())
53 .unwrap_or("");
54 let accept = req
55 .headers()
56 .get("Accept")
57 .and_then(|v| v.to_str().ok())
58 .unwrap_or("");
59
60 let nav_id: Option<String> = if body.trim().is_empty() {
62 None
63 } else {
64 let request_grid = content::decode_request_grid(&body, content_type)
65 .map_err(|e| HaystackError::bad_request(format!("failed to decode request: {e}")))?;
66
67 request_grid.row(0).and_then(|row| match row.get("navId") {
68 Some(Kind::Str(s)) if !s.is_empty() => Some(s.clone()),
69 Some(Kind::Ref(r)) => Some(r.val.clone()),
70 _ => None,
71 })
72 };
73
74 let result_grid = match nav_id {
75 None => {
76 let sites = state
78 .graph
79 .read_all("site", 0)
80 .map_err(|e| HaystackError::internal(format!("graph error: {e}")))?;
81
82 build_nav_grid(sites)
83 }
84 Some(ref parent_id) => {
85 let parent = state.graph.get(parent_id);
87 if parent.is_none() {
88 return Err(HaystackError::not_found(format!(
89 "entity not found: {parent_id}"
90 )));
91 }
92
93 let child_refs = state.graph.refs_to(parent_id, None);
95 let mut children = Vec::new();
96 for ref_val in child_refs {
97 if let Some(entity) = state.graph.get(&ref_val) {
98 children.push(entity);
99 }
100 }
101 build_nav_grid(children)
102 }
103 };
104
105 let (encoded, ct) = content::encode_response_grid(&result_grid, accept)
106 .map_err(|e| HaystackError::internal(format!("encoding error: {e}")))?;
107
108 Ok(HttpResponse::Ok().content_type(ct).body(encoded))
109}
110
111fn build_nav_grid(entities: Vec<HDict>) -> HGrid {
113 if entities.is_empty() {
114 return HGrid::new();
115 }
116
117 let cols = vec![HCol::new("id"), HCol::new("dis"), HCol::new("navId")];
118 let rows: Vec<HDict> = entities
119 .into_iter()
120 .map(|entity| {
121 let mut row = HDict::new();
122 if let Some(id_ref) = entity.id() {
123 row.set("id", Kind::Ref(id_ref.clone()));
124 row.set("navId", Kind::Str(id_ref.val.clone()));
125 }
126 if let Some(dis) = entity.dis() {
127 row.set("dis", Kind::Str(dis.to_string()));
128 }
129 row
130 })
131 .collect();
132
133 HGrid::from_parts(HDict::new(), cols, rows)
134}