use crate::output::{OutputFormat, print_output};
use anyhow::Result;
use clap::{Args, Subcommand};
use grr_calendar::{CalendarClient, Event, EventAttendee, EventDateTime, EventListOptions};
#[derive(Subcommand, Debug)]
pub enum CalendarCommands {
List(ListArgs),
Events(EventsArgs),
Get(GetArgs),
Create(CreateArgs),
Update(UpdateArgs),
Delete(DeleteArgs),
FreeBusy(FreeBusyArgs),
}
#[derive(Args, Debug)]
pub struct ListArgs {
#[arg(short, long)]
pub max: Option<usize>,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
#[derive(Args, Debug)]
pub struct EventsArgs {
#[arg(default_value = "primary")]
pub calendar_id: String,
#[arg(long)]
pub time_min: Option<String>,
#[arg(long)]
pub time_max: Option<String>,
#[arg(short, long)]
pub query: Option<String>,
#[arg(short, long, default_value = "25")]
pub max: usize,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
#[derive(Args, Debug)]
pub struct GetArgs {
#[arg(default_value = "primary")]
pub calendar_id: String,
pub event_id: String,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
#[derive(Args, Debug)]
pub struct CreateArgs {
#[arg(default_value = "primary")]
pub calendar_id: String,
#[arg(long)]
pub summary: String,
#[arg(long)]
pub start: String,
#[arg(long)]
pub end: String,
#[arg(long)]
pub location: Option<String>,
#[arg(long)]
pub description: Option<String>,
#[arg(long, value_delimiter = ',')]
pub attendees: Vec<String>,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
#[derive(Args, Debug)]
pub struct UpdateArgs {
#[arg(default_value = "primary")]
pub calendar_id: String,
pub event_id: String,
#[arg(long)]
pub summary: Option<String>,
#[arg(long)]
pub start: Option<String>,
#[arg(long)]
pub end: Option<String>,
#[arg(long)]
pub location: Option<String>,
#[arg(long)]
pub description: Option<String>,
#[arg(long, value_delimiter = ',')]
pub attendees: Vec<String>,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
#[derive(Args, Debug)]
pub struct DeleteArgs {
#[arg(default_value = "primary")]
pub calendar_id: String,
pub event_id: String,
}
#[derive(Args, Debug)]
pub struct FreeBusyArgs {
#[arg(long, value_delimiter = ',', default_value = "primary")]
pub calendars: Vec<String>,
#[arg(long)]
pub time_min: String,
#[arg(long)]
pub time_max: String,
#[arg(short, long, value_enum, default_value = "json")]
pub format: OutputFormat,
}
fn event_date_time(value: &str) -> EventDateTime {
if value.contains(':') || value.contains('T') {
EventDateTime {
date_time: Some(value.to_string()),
..Default::default()
}
} else {
EventDateTime {
date: Some(value.to_string()),
..Default::default()
}
}
}
fn attendees_from(emails: &[String]) -> Option<Vec<EventAttendee>> {
(!emails.is_empty()).then(|| {
emails
.iter()
.map(|email| EventAttendee {
email: Some(email.clone()),
..Default::default()
})
.collect()
})
}
pub async fn handle_calendar_cmd(client: &CalendarClient, cmd: CalendarCommands) -> Result<()> {
match cmd {
CalendarCommands::List(args) => {
let calendars = client.list_calendars(args.max).await?;
print_output(&calendars, args.format)?;
}
CalendarCommands::Events(args) => {
let opts = EventListOptions {
time_min: args.time_min,
time_max: args.time_max,
query: args.query,
max_results: Some(args.max),
};
let events = client.list_events(&args.calendar_id, opts).await?;
print_output(&events, args.format)?;
}
CalendarCommands::Get(args) => {
let event = client.get_event(&args.calendar_id, &args.event_id).await?;
print_output(&event, args.format)?;
}
CalendarCommands::Create(args) => {
let event = Event {
summary: Some(args.summary),
start: Some(event_date_time(&args.start)),
end: Some(event_date_time(&args.end)),
location: args.location,
description: args.description,
attendees: attendees_from(&args.attendees),
..Default::default()
};
let created = client.create_event(&args.calendar_id, event).await?;
print_output(&created, args.format)?;
}
CalendarCommands::Update(args) => {
let mut event = client.get_event(&args.calendar_id, &args.event_id).await?;
if let Some(summary) = args.summary {
event.summary = Some(summary);
}
if let Some(start) = args.start {
event.start = Some(event_date_time(&start));
}
if let Some(end) = args.end {
event.end = Some(event_date_time(&end));
}
if let Some(location) = args.location {
event.location = Some(location);
}
if let Some(description) = args.description {
event.description = Some(description);
}
if !args.attendees.is_empty() {
event.attendees = attendees_from(&args.attendees);
}
let updated = client
.update_event(&args.calendar_id, &args.event_id, event)
.await?;
print_output(&updated, args.format)?;
}
CalendarCommands::Delete(args) => {
client
.delete_event(&args.calendar_id, &args.event_id)
.await?;
println!("Event {} deleted", args.event_id);
}
CalendarCommands::FreeBusy(args) => {
let calendars: Vec<&str> = args.calendars.iter().map(String::as_str).collect();
let response = client
.freebusy(&calendars, &args.time_min, &args.time_max)
.await?;
print_output(&response, args.format)?;
}
}
Ok(())
}