Compare commits

..

No commits in common. "84e7a040063073f0b020f60a36fca5c27a2f7cd8" and "a3b419214acda46c480f336a6dd4af9bfa569c26" have entirely different histories.

View file

@ -1,37 +1,28 @@
use anyhow::Result; use warp::{
use icalendar::{Calendar, Component, EventLike}; Filter,
use serde::Serialize; Reply,
Rejection,
};
use std::collections::HashMap; use std::collections::HashMap;
use warp::{Filter, Rejection, Reply}; use anyhow::Result;
use icalendar::{Component, Calendar, EventLike};
use serde::Serialize;
async fn handler(params: HashMap<String, String>) -> Result<impl Reply, Rejection> { async fn handler(params: HashMap<String, String>) -> Result<impl Reply, Rejection> {
match params.get("url") { match params.get("url") {
Some(url) => Ok(warp::reply::json( Some(url) => Ok(warp::reply::json(&convert(&[url], params.get("days")).await.map_err(|_| warp::reject::reject())?.entries)),
&convert(&[url], params.get("days")) None => Err(warp::reject::reject())
.await
.map_err(|_| warp::reject::reject())?
.entries,
)),
None => Err(warp::reject::reject()),
} }
} }
async fn new_handler( async fn new_handler(url: String, params: HashMap<String, String>) -> Result<impl Reply, Rejection> {
url: String,
params: HashMap<String, String>,
) -> Result<impl Reply, Rejection> {
let urls: Vec<&str> = url.split(";").collect(); let urls: Vec<&str> = url.split(";").collect();
Ok(warp::reply::json( Ok(warp::reply::json(&convert(&urls, params.get("days")).await.map_err(|_| warp::reject::reject())?.entries))
&convert(&urls, params.get("days"))
.await
.map_err(|_| warp::reject::reject())?
.entries,
))
} }
#[derive(Serialize)] #[derive(Serialize)]
struct CustomCalendar { struct CustomCalendar {
entries: Vec<CustomCalendarEntry>, entries: Vec<CustomCalendarEntry>,
} }
#[derive(Serialize)] #[derive(Serialize)]
@ -50,19 +41,16 @@ async fn convert(urls: &[&str], days: Option<&String>) -> Result<CustomCalendar>
let mut calendar_index = 0; let mut calendar_index = 0;
for url in urls { for url in urls {
let url = urlencoding::decode(url)?.into_owned(); let url = urlencoding::decode(url)?.into_owned();
let ics_text = reqwest::get(url).await?.text().await?; let ics_text = reqwest::get(url)
.await?
.text()
.await?;
let calendar = ics_text.parse::<Calendar>().map_err(|e| anyhow::Error::msg(e))?;
let calendar = ics_text
.parse::<Calendar>() let filter_start = chrono::Utc::now().date_naive().and_hms_opt(0, 0, 0).unwrap().and_utc();
.map_err(|e| anyhow::Error::msg(e))?; let filter_end = filter_start + chrono::Duration::days(days.unwrap_or(&String::from("1")).parse().unwrap_or(1));
let filter_start = chrono::Utc::now()
.date_naive()
.and_hms_opt(0, 0, 0)
.unwrap()
.and_utc();
let filter_end =
filter_start + chrono::Duration::days(days.and_then(|x| x.parse().ok()).unwrap_or(1));
for event in calendar.components { for event in calendar.components {
if let Some(event) = event.as_event() { if let Some(event) = event.as_event() {
@ -72,7 +60,7 @@ async fn convert(urls: &[&str], days: Option<&String>) -> Result<CustomCalendar>
}; };
let start = match convert_time(start) { let start = match convert_time(start) {
Ok(t) => t, Ok(t) => { t },
Err(e) => { Err(e) => {
println!("Invalid start timestamp: {:?}", e); println!("Invalid start timestamp: {:?}", e);
continue; continue;
@ -80,11 +68,13 @@ async fn convert(urls: &[&str], days: Option<&String>) -> Result<CustomCalendar>
}; };
let end = match event.get_end() { let end = match event.get_end() {
Some(end) => match convert_time(end) { Some(end) => {
Ok(t) => t, match convert_time(end) {
Err(e) => { Ok(t) => { t },
println!("Invalid end timestamp: {:?}", e); Err(e) => {
continue; println!("Invalid end timestamp: {:?}", e);
continue;
}
} }
}, },
None => start + chrono::Duration::days(1), None => start + chrono::Duration::days(1),
@ -95,41 +85,35 @@ async fn convert(urls: &[&str], days: Option<&String>) -> Result<CustomCalendar>
let start_dates = if let Some(rrule) = event.properties().get("RRULE") { let start_dates = if let Some(rrule) = event.properties().get("RRULE") {
//let vector = Vec::new(); //let vector = Vec::new();
let rrule_str = rrule.value(); let rrule_str = rrule.value();
let string = format!( let string = format!("DTSTART:{}\n{}", event.properties().get("DTSTART").unwrap().value(), rrule_str);
"DTSTART:{}\n{}",
event.properties().get("DTSTART").unwrap().value(),
rrule_str
);
let rrule: rrule::RRuleSet = string.parse()?; let rrule: rrule::RRuleSet = string.parse()?;
let date_set = rrule let date_set = rrule.all(100).dates;
.into_iter() date_set.iter().map(|x| x.with_timezone(&chrono::Utc)).collect()
.skip_while(|x| x < &filter_start)
.take_while(|x| x <= &filter_end)
.map(|x| x.with_timezone(&chrono::Utc))
.collect();
date_set
} else { } else {
vec![start] vec!(start)
}; };
for start in start_dates let mut start = None;
.iter() for start_date in start_dates {
.skip_while(|x| x < &&filter_start) if start_date >= filter_start && start_date <= filter_end {
.take_while(|x| x <= &&filter_end) start = Some(start_date);
{ break;
let end = *start + length; }
}
entries.push(CustomCalendarEntry { if let Some(start) = start {
title: event.get_summary().unwrap_or("").to_string(), let end = start + length;
description: event.get_description().unwrap_or("").to_string(),
location: event.get_location().unwrap_or("").to_string(), entries.push(CustomCalendarEntry {
start: start.timestamp(), title: event.get_summary().unwrap_or("").to_string(),
end: end.timestamp(), description: event.get_description().unwrap_or("").to_string(),
calendar: calendar_index, location: event.get_location().unwrap_or("").to_string(),
isallday: start.time() == chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap() start: start.timestamp(),
&& end - *start == chrono::Duration::days(1), // the event has a length of 24 hours and end: end.timestamp(),
// starts at 00:00 calendar: calendar_index,
}); isallday: start.time() == chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap() && end - start == chrono::Duration::days(1) // the event has a length of 24 hours and
// starts at 00:00
});
} }
} }
} }
@ -139,30 +123,23 @@ async fn convert(urls: &[&str], days: Option<&String>) -> Result<CustomCalendar>
entries.sort_by(|a, b| a.start.cmp(&b.start)); entries.sort_by(|a, b| a.start.cmp(&b.start));
Ok(CustomCalendar { entries }) Ok(CustomCalendar{entries})
} }
fn convert_time(dt: icalendar::DatePerhapsTime) -> Result<chrono::DateTime<chrono::Utc>> { fn convert_time(dt: icalendar::DatePerhapsTime) -> Result<chrono::DateTime<chrono::Utc>> {
Ok(match dt { Ok(match dt {
icalendar::DatePerhapsTime::DateTime(cdt) => { icalendar::DatePerhapsTime::DateTime(cdt) => {
let cdt = match cdt { let cdt = match cdt {
icalendar::CalendarDateTime::WithTimezone { date_time, tzid } => { icalendar::CalendarDateTime::WithTimezone{date_time, tzid} => {
icalendar::CalendarDateTime::WithTimezone { icalendar::CalendarDateTime::WithTimezone{date_time, tzid: String::from(match tzid.as_str() {
date_time, "W. Europe Standard Time" => "Europe/Berlin",
tzid: String::from(match tzid.as_str() { _ => &tzid
"Turkey Standard Time" => "Europe/Istanbul", })}
"India Standard Time" => "Asia/Kolkata", },
"Pacific Standard Time" => "America/Los Angeles",
"W. Europe Standard Time" => "Europe/Berlin",
_ => &tzid,
}),
}
}
_ => cdt, _ => cdt,
}; };
cdt.try_into_utc() cdt.try_into_utc().ok_or(anyhow::Error::msg("failed to convert to utc"))?
.ok_or(anyhow::Error::msg("failed to convert to utc"))? },
}
icalendar::DatePerhapsTime::Date(nd) => nd.and_hms_opt(0, 0, 0).unwrap().and_utc(), icalendar::DatePerhapsTime::Date(nd) => nd.and_hms_opt(0, 0, 0).unwrap().and_utc(),
}) })
} }