Implement create Icalendar endpoint
This commit is contained in:
70
src/main.rs
70
src/main.rs
@ -1,10 +1,12 @@
|
|||||||
use axum::extract::Query;
|
use axum::extract::Query;
|
||||||
use axum::response::IntoResponse;
|
use axum::http::header::CONTENT_TYPE;
|
||||||
|
use axum::response::{IntoResponse, Response};
|
||||||
use axum::routing::get;
|
use axum::routing::get;
|
||||||
use axum::{Json, Router};
|
use axum::{Json, Router};
|
||||||
use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, TimeDelta, Weekday};
|
use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, TimeDelta, Weekday};
|
||||||
use serde::{Deserialize, Serialize};
|
use icalendar::{Calendar, Class, Component, Event, EventLike};
|
||||||
use std::ops::{Add, Sub};
|
use serde::Deserialize;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
enum Recurring {
|
enum Recurring {
|
||||||
@ -68,24 +70,66 @@ struct EventBody {
|
|||||||
/// TODO what if start_date is weekend
|
/// TODO what if start_date is weekend
|
||||||
async fn get_calendar(Query(query): Query<EventQuery>) -> impl IntoResponse {
|
async fn get_calendar(Query(query): Query<EventQuery>) -> impl IntoResponse {
|
||||||
let start = query.start_date_time;
|
let start = query.start_date_time;
|
||||||
let start_day = start.day();
|
|
||||||
let end = query
|
let end = query
|
||||||
.end_date
|
.end_date
|
||||||
.unwrap_or_else(|| (start + TimeDelta::days(365)).date());
|
.unwrap_or_else(|| (start + TimeDelta::days(365)).date());
|
||||||
|
Json(get_dates(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
query.recurring,
|
||||||
|
query.avoid_weekends.unwrap_or(false),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEXT_CALENDAR: &'static str = "text/calendar";
|
||||||
|
|
||||||
|
async fn get_ics(Query(query): Query<EventQuery>) -> impl IntoResponse {
|
||||||
|
let start = query.start_date_time;
|
||||||
|
let end = query
|
||||||
|
.end_date
|
||||||
|
.unwrap_or_else(|| (start + TimeDelta::days(365)).date());
|
||||||
|
let mut calendar = Calendar::new();
|
||||||
|
calendar.name(&query.title);
|
||||||
|
get_dates(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
query.recurring,
|
||||||
|
query.avoid_weekends.unwrap_or(false),
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|date| {
|
||||||
|
calendar.push(
|
||||||
|
Event::new()
|
||||||
|
.summary(&query.title)
|
||||||
|
.starts(date)
|
||||||
|
.class(Class::Confidential),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Response::builder()
|
||||||
|
.header(CONTENT_TYPE, TEXT_CALENDAR)
|
||||||
|
.body(calendar.done().to_string())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_dates(
|
||||||
|
start: NaiveDateTime,
|
||||||
|
end: NaiveDate,
|
||||||
|
recurring: Recurring,
|
||||||
|
avoid_weekends: bool,
|
||||||
|
) -> Vec<NaiveDateTime> {
|
||||||
let mut events = vec![start];
|
let mut events = vec![start];
|
||||||
let mut previous_date_time = start;
|
let mut previous_date_time = start;
|
||||||
|
let mut baseline = start;
|
||||||
while previous_date_time.date() < end {
|
while previous_date_time.date() < end {
|
||||||
previous_date_time = previous_date_time.with_day(start_day).unwrap();
|
let next = match recurring {
|
||||||
let next = match query.recurring {
|
|
||||||
Recurring::Daily => todo!(),
|
Recurring::Daily => todo!(),
|
||||||
Recurring::Weeky => todo!(),
|
Recurring::Weeky => todo!(),
|
||||||
Recurring::BiWeekly => todo!(),
|
Recurring::BiWeekly => todo!(),
|
||||||
Recurring::Monthly => {
|
Recurring::Monthly => {
|
||||||
let new_date = previous_date_time
|
let new_date = baseline.checked_add_months(Months::new(1)).unwrap();
|
||||||
.checked_add_months(Months::new(1))
|
baseline = new_date;
|
||||||
.unwrap();
|
if let true = avoid_weekends {
|
||||||
if let Some(true) = query.avoid_weekends {
|
|
||||||
match new_date.weekday() {
|
match new_date.weekday() {
|
||||||
Weekday::Sat => new_date.sub(TimeDelta::days(1)),
|
Weekday::Sat => new_date.sub(TimeDelta::days(1)),
|
||||||
Weekday::Sun => new_date.sub(TimeDelta::days(2)),
|
Weekday::Sun => new_date.sub(TimeDelta::days(2)),
|
||||||
@ -101,12 +145,14 @@ async fn get_calendar(Query(query): Query<EventQuery>) -> impl IntoResponse {
|
|||||||
events.push(next);
|
events.push(next);
|
||||||
previous_date_time = next;
|
previous_date_time = next;
|
||||||
}
|
}
|
||||||
Json(events)
|
events
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let app = Router::new().route("/", get(get_calendar));
|
let app = Router::new()
|
||||||
|
.route("/", get(get_calendar))
|
||||||
|
.route("/ics", get(get_ics));
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();
|
||||||
axum::serve(listener, app).await.unwrap();
|
axum::serve(listener, app).await.unwrap();
|
||||||
|
Reference in New Issue
Block a user