From 10140d879c25e87498f765ca841e79882fddc911 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Wed, 17 May 2023 12:17:41 +0200 Subject: [PATCH] feat: support weekday names & tomorrow --- src/commands/bib.rs | 35 +++++++++++++++++++------------- src/commands/mod.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/commands/bib.rs b/src/commands/bib.rs index 244c623..32fbbe2 100644 --- a/src/commands/bib.rs +++ b/src/commands/bib.rs @@ -1,4 +1,4 @@ -use crate::commands::EmbedField; +use crate::commands::{EmbedField, HumanNaiveDate}; use crate::db::users::User; use crate::{Context, Error}; @@ -46,22 +46,27 @@ fn resource_to_embed_field(resource: Resource) -> EmbedField { /// List available timeslots for day #[poise::command(prefix_command, slash_command)] -pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> { +pub async fn available(ctx: Context<'_>, date: HumanNaiveDate) -> Result<(), Error> { let client = &ctx.data().client; - let mut resources = client.available(STERRE_BIB_ID, date, 1).await?; + let mut resources = client + .available(STERRE_BIB_ID, date.clone().into(), 1) + .await?; // Cloning here isn't super efficient, but this list only consists of a handful of elements so // it's fine resources.sort_by_key(|k| k.resource_name.clone()); ctx.send(|f| { f.embed(|e| { - e.description(format!("Available booking dates for {}.", date)) - .fields( - resources - .into_iter() - .map(resource_to_embed_field) - .collect::>(), - ) + e.description(format!( + "Available booking dates for {}.", + Into::::into(date) + )) + .fields( + resources + .into_iter() + .map(resource_to_embed_field) + .collect::>(), + ) }) }) .await?; @@ -72,7 +77,7 @@ pub async fn available(ctx: Context<'_>, date: NaiveDate) -> Result<(), Error> { #[poise::command(prefix_command, slash_command)] pub async fn book( ctx: Context<'_>, - date: NaiveDate, + date: HumanNaiveDate, start_time: NaiveTime, end_time: NaiveTime, #[description = "Minimum seats the room should have."] capacity: Option, @@ -102,7 +107,9 @@ pub async fn book( let user = user.unwrap(); let client = &ctx.data().client; - let resources = client.available(STERRE_BIB_ID, date, 1).await?; + let resources = client + .available(STERRE_BIB_ID, date.clone().into(), 1) + .await?; let chosen_resource = resources .iter() .filter(|r| capacity.is_none() || capacity.unwrap() <= r.capacity) @@ -112,7 +119,7 @@ pub async fn book( let reservation = Reservation { auth_type: None, email: user.email.clone(), - date, + date: date.clone().into(), start_time, end_time, note: "coworking space".to_string(), @@ -129,7 +136,7 @@ pub async fn book( ctx.send(|f| { f.embed(|e| { e.description("A new reservation has been made.") - .field("when", format!("{} {} - {}", date, start_time.format(TIME_FORMAT), end_time.format(TIME_FORMAT)), false) + .field("when", format!("{} {} - {}", Into::::into(date), start_time.format(TIME_FORMAT), end_time.format(TIME_FORMAT)), false) .field("where", &chosen_resource.resource_name, false) .footer(|ft| ft.text( format!("A confirmation mail has been sent to {}. Please check your email and confirm your reservation within two hours.", user.email))) diff --git a/src/commands/mod.rs b/src/commands/mod.rs index d32fb16..f9c81ac 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -2,10 +2,59 @@ mod bib; mod minecraft; mod users; +use chrono::Datelike; +use core::str; + use crate::{Context, Data, Error}; type EmbedField = (String, String, bool); +const DAY_TERMS: [&str; 3] = ["today", "tomorrow", "overmorrow"]; + +#[derive(Clone)] +pub struct HumanNaiveDate(chrono::NaiveDate); + +impl str::FromStr for HumanNaiveDate { + type Err = chrono::format::ParseError; + + fn from_str(s: &str) -> chrono::format::ParseResult { + if let Some(days_to_add) = DAY_TERMS + .iter() + .position(|term| s.to_lowercase() == term.to_string()) + { + let now = chrono::Local::now().naive_local().date(); + + // days_to_add will never be greater than 2 + Ok(HumanNaiveDate( + now + chrono::Duration::days(days_to_add.try_into().unwrap()), + )) + } else if let Ok(weekday) = s.parse::() { + let now = chrono::Local::now().naive_local().date(); + let cur_day = now.weekday(); + let cur_day_index = cur_day.num_days_from_monday(); + let parsed_day_index = weekday.num_days_from_monday(); + + let days_to_add = if cur_day_index <= parsed_day_index { + parsed_day_index - cur_day_index + } else { + 7 - (cur_day_index - parsed_day_index) + }; + + Ok(HumanNaiveDate( + now + chrono::Duration::days(days_to_add.into()), + )) + } else { + chrono::NaiveDate::from_str(s).map(|d| HumanNaiveDate(d)) + } + } +} + +impl Into for HumanNaiveDate { + fn into(self) -> chrono::NaiveDate { + self.0 + } +} + pub fn commands() -> Vec> { vec![ help(),