iCalendar import: parse_ical + API + MCP tool (#16)
This commit is contained in:
@@ -14,7 +14,7 @@ use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::tools::{channels, library, schedule};
|
||||
use crate::tools::{channels, ical, library, schedule};
|
||||
|
||||
const SERVER_NAME: &str = "k-tv-mcp";
|
||||
|
||||
@@ -151,6 +151,12 @@ pub struct SetGapFillerParams {
|
||||
pub filter_json: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, JsonSchema)]
|
||||
pub struct ImportIcalParams {
|
||||
pub channel_id: String,
|
||||
pub ical_string: String,
|
||||
}
|
||||
|
||||
fn parse_uuid(s: &str) -> Result<Uuid, String> {
|
||||
s.parse::<Uuid>()
|
||||
.map_err(|_| serde_json::json!({"error": format!("invalid UUID: {s}")}).to_string())
|
||||
@@ -423,6 +429,29 @@ impl KTvMcpServer {
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Export a channel's ScheduleConfig as an iCalendar (.ics) string per RFC 5545."
|
||||
)]
|
||||
async fn export_schedule_ical(&self, #[tool(aggr)] p: ChannelIdParam) -> String {
|
||||
match parse_uuid(&p.channel_id) {
|
||||
Ok(id) => ical::export_schedule_ical(&self.channel_query, id).await,
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
#[tool(
|
||||
description = "Import an iCalendar (.ics) string to replace a channel's ScheduleConfig. VEVENTs map to ProgrammingBlocks."
|
||||
)]
|
||||
async fn import_schedule_ical(&self, #[tool(aggr)] p: ImportIcalParams) -> String {
|
||||
match parse_uuid(&p.channel_id) {
|
||||
Ok(id) => {
|
||||
ical::import_schedule_ical(&self.channel_cmd_deps, id, self.owner_id, &p.ical_string)
|
||||
.await
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tool(tool_box)]
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use application::channels::{ChannelCommandDeps, UpdateChannelCommand};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::error::domain_err;
|
||||
use crate::error::{domain_err, ok_json};
|
||||
|
||||
pub async fn export_schedule_ical(
|
||||
channel_query: &Arc<dyn domain::ports::ChannelQuery>,
|
||||
@@ -18,3 +19,30 @@ pub async fn export_schedule_ical(
|
||||
Err(e) => domain_err(e),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn import_schedule_ical(
|
||||
cmd_deps: &Arc<ChannelCommandDeps>,
|
||||
channel_id: Uuid,
|
||||
owner_id: Uuid,
|
||||
ical_str: &str,
|
||||
) -> String {
|
||||
let config = match domain::parse_ical(ical_str) {
|
||||
Ok(c) => c,
|
||||
Err(e) => return domain_err(e),
|
||||
};
|
||||
let cmd = UpdateChannelCommand {
|
||||
channel_id: channel_id.into(),
|
||||
owner_id: owner_id.into(),
|
||||
name: None,
|
||||
description: None,
|
||||
timezone: None,
|
||||
schedule_config: Some(config),
|
||||
rotation_policy: None,
|
||||
auto_schedule: None,
|
||||
gap_filler: None,
|
||||
};
|
||||
match application::channels::update::execute(cmd_deps, cmd).await {
|
||||
Ok(channel) => ok_json(&channel),
|
||||
Err(e) => domain_err(e),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user