PicoBot/src/command/handlers/list_todos.rs

83 lines
2.4 KiB
Rust

use crate::command::context::CommandContext;
use crate::command::handler::{CommandHandler, CommandMetadata};
use crate::command::response::{CommandError, CommandResponse};
use crate::command::Command;
use crate::protocol::TodoItemSummary;
use crate::storage::SessionStore;
use async_trait::async_trait;
use std::sync::Arc;
pub struct ListTodosCommandHandler {
store: Arc<SessionStore>,
}
impl ListTodosCommandHandler {
pub fn new(store: Arc<SessionStore>) -> Self {
Self { store }
}
}
#[async_trait]
impl CommandHandler for ListTodosCommandHandler {
fn can_handle(&self, cmd: &Command) -> bool {
matches!(cmd, Command::ListTodos)
}
fn metadata(&self) -> Option<CommandMetadata> {
Some(CommandMetadata {
name: "list_todos",
description: "列出当前 Todo 列表",
usage: "/list_todos",
})
}
async fn handle(
&self,
_cmd: Command,
ctx: CommandContext,
) -> Result<CommandResponse, CommandError> {
// scope_key = topic_id.unwrap_or(session_id)
let scope_key = ctx
.topic_id
.as_deref()
.filter(|t| !t.is_empty())
.or(ctx.session_id.as_deref())
.ok_or_else(|| {
CommandError::new(
"MISSING_CONTEXT",
"Cannot list todos: no session_id or topic_id in command context",
)
})?;
let records = self
.store
.list_todos(scope_key)
.map_err(|e| CommandError::new("LIST_TODOS_ERROR", e.to_string()))?;
tracing::info!(
scope_key = %scope_key,
record_count = records.len(),
"list_todos handler: reading from store"
);
let summaries: Vec<TodoItemSummary> = records
.into_iter()
.map(|r| TodoItemSummary {
id: r.id,
content: r.content,
status: r.status,
priority: r.priority,
created_at: r.created_at,
updated_at: r.updated_at,
})
.collect();
let todos_json = serde_json::to_string(&summaries)
.map_err(|e| CommandError::new("SERIALIZE_ERROR", e.to_string()))?;
Ok(CommandResponse::success(ctx.request_id)
.with_metadata("todos", &todos_json)
.with_metadata("todos_scope_key", scope_key))
}
}