use bytes::Bytes;
use helix_core::effect::{DomainEventBytes, Effect};
use serde_json::{json, Value};
pub(crate) fn collect_about_me_ids(data: &Value) -> Vec<String> {
let channel = data.get("channel").unwrap_or(data);
let mut ids = Vec::new();
for key in ["mentionList", "urgentPostList"] {
if let Some(arr) = channel.get(key).and_then(Value::as_array) {
ids.extend(arr.iter().filter_map(|v| v.as_str().map(str::to_string)));
}
}
ids
}
pub(crate) fn query_todo_body(post_ids: &[String]) -> Value {
json!({ "postIds": post_ids })
}
pub(crate) fn emit_todo_updated(raw_body: &[u8]) -> Effect {
let items = parse_todo_items(raw_body);
emit_todo(json!({ "items": items }))
}
fn parse_todo_items(raw_body: &[u8]) -> Vec<Value> {
let Ok(resp) = serde_json::from_slice::<Value>(raw_body) else {
return Vec::new();
};
let ok = resp.get("status").and_then(Value::as_str) == Some("SUCCESS")
|| resp.get("status").and_then(Value::as_i64) == Some(200);
if !ok {
return Vec::new();
}
let channels = resp
.get("data")
.and_then(|d| d.get("channels"))
.and_then(Value::as_array)
.cloned()
.unwrap_or_default();
let mut items = Vec::new();
for channel in &channels {
let posts = channel
.get("posts")
.and_then(Value::as_array)
.cloned()
.unwrap_or_default();
for post in &posts {
let message_type = post
.get("messageType")
.and_then(Value::as_str)
.unwrap_or("");
let id = post.get("id").and_then(Value::as_str).unwrap_or("");
let assembled_id = format!("{id}_{message_type}");
items.push(json!({
"id": assembled_id,
"channel": channel,
"post": post,
"type": message_type,
"canDel": message_type == "mention",
"todoId": assembled_id,
"todoType": message_type,
}));
}
}
items
}
fn emit_todo(data: Value) -> Effect {
let payload = json!({ "event": "im:todo:updated", "data": data });
let bytes = Bytes::from(
serde_json::to_vec(&payload).expect("emit_todo: static JSON shape must serialize"),
);
Effect::Emit {
event: DomainEventBytes(bytes),
}
}
#[cfg(test)]
#[path = "core_tests.rs"]
mod tests;