Files
recurring-event-api/src/main.rs

114 lines
2.9 KiB
Rust
Raw Normal View History

2025-09-20 12:06:25 +02:00
use axum::extract::Query;
use axum::response::IntoResponse;
use axum::routing::get;
use axum::{Json, Router};
use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, TimeDelta, Weekday};
use serde::{Deserialize, Serialize};
use std::ops::{Add, Sub};
#[derive(Deserialize)]
enum Recurring {
Daily,
Weeky,
BiWeekly,
Monthly,
Quarterly,
Yearly,
}
#[derive(Deserialize)]
enum Move {
Before,
After,
}
#[derive(Deserialize)]
struct EventQuery {
/// Start date
start_date_time: NaiveDateTime,
/// Recurring date
recurring: Recurring,
// If set, will ignore time on start_date
all_day: bool,
/// Title of the event
title: String,
// Optionals
end_date: Option<NaiveDate>,
avoid_weekends: Option<bool>,
on_collition: Option<Move>,
}
#[derive(Deserialize)]
enum Time {
/// Specific time at day
DateTime {
start: NaiveDateTime,
end: NaiveDateTime,
},
/// All day
Date(NaiveDate),
}
#[derive(Deserialize)]
struct EventBody {
/// Start date
time: Time,
/// Recurring date
recurring: Recurring,
/// Title of the event
title: String,
// Optionals
end_date: Option<NaiveDate>,
ignore_weekdays: Vec<Weekday>,
on_collition: Option<Move>,
}
/// TODO create ical object
/// TODO implement Before / After
/// TODO what if start_date is weekend
async fn get_calendar(Query(query): Query<EventQuery>) -> impl IntoResponse {
let start = query.start_date_time;
let start_day = start.day();
let end = query
.end_date
.unwrap_or_else(|| (start + TimeDelta::days(365)).date());
let mut events = vec![start];
let mut previous_date_time = start;
while previous_date_time.date() < end {
previous_date_time = previous_date_time.with_day(start_day).unwrap();
let next = match query.recurring {
Recurring::Daily => todo!(),
Recurring::Weeky => todo!(),
Recurring::BiWeekly => todo!(),
Recurring::Monthly => {
let new_date = previous_date_time
.checked_add_months(Months::new(1))
.unwrap();
if let Some(true) = query.avoid_weekends {
match new_date.weekday() {
Weekday::Sat => new_date.sub(TimeDelta::days(1)),
Weekday::Sun => new_date.sub(TimeDelta::days(2)),
_ => new_date,
}
} else {
new_date
}
}
Recurring::Quarterly => todo!(),
Recurring::Yearly => todo!(),
};
events.push(next);
previous_date_time = next;
}
Json(events)
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(get_calendar));
let listener = tokio::net::TcpListener::bind("0.0.0.0:8000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}