diff options
| author | Joris | 2022-03-19 22:03:58 +0100 | 
|---|---|---|
| committer | Joris | 2022-03-19 22:03:58 +0100 | 
| commit | 35cc74578e969bae4812afd2ff041eba3746142d (patch) | |
| tree | c0ef18d3c81554f0e70c91fcb1006d587470365c /src/model | |
| parent | 199624dc03ead28ddc7454147457512d9568c593 (diff) | |
Allow to repeat an event until a specific date
Also provide a shortcut to modify a repetead event from a specific
occurence. This set the end repetition date under the hood and create a
new repeated event.
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/event.rs | 52 | ||||
| -rw-r--r-- | src/model/mod.rs | 1 | ||||
| -rw-r--r-- | src/model/repetition.rs | 21 | ||||
| -rw-r--r-- | src/model/time.rs | 22 | 
4 files changed, 51 insertions, 45 deletions
| diff --git a/src/model/event.rs b/src/model/event.rs index 5e92692..e556f6e 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -1,9 +1,10 @@ -use chrono::Timelike;  use chrono::{NaiveDate, NaiveTime};  use std::collections::HashMap;  use uuid::Uuid;  use crate::model::repetition::Repetition; +use crate::model::time; +use crate::validation;  pub static DATE_FORMAT: &str = "%d/%m/%Y"; @@ -19,10 +20,10 @@ pub struct Event {  impl Event {      pub fn pprint(&self) -> String { -        let start = self.start.map(pprint_time).unwrap_or_default(); +        let start = self.start.map(time::pprint).unwrap_or_default();          let end = self              .end -            .map(|t| format!("-{}", pprint_time(t))) +            .map(|t| format!("-{}", time::pprint(t)))              .unwrap_or_default();          let space = if self.start.is_some() || self.end.is_some() {              " " @@ -52,27 +53,6 @@ pub fn repetitions_between(      res  } -pub fn pprint_time(t: NaiveTime) -> String { -    if t.minute() == 0 { -        format!("{}h", t.hour()) -    } else { -        format!("{}h{}", t.hour(), t.minute()) -    } -} - -fn parse_time(t: &str) -> Option<NaiveTime> { -    match t.split('h').collect::<Vec<&str>>()[..] { -        [hours, minutes] => { -            if minutes.trim().is_empty() { -                NaiveTime::from_hms_opt(hours.parse().ok()?, 0, 0) -            } else { -                NaiveTime::from_hms_opt(hours.parse().ok()?, minutes.parse().ok()?, 0) -            } -        } -        _ => None, -    } -} -  // Validation  pub fn validate( @@ -83,8 +63,8 @@ pub fn validate(      end: String,      repetition: Option<Repetition>,  ) -> Option<Event> { -    let start = validate_time(start)?; -    let end = validate_time(end)?; +    let start = validation::time(start)?; +    let end = validation::time(end)?;      match (start, end) {          (Some(s), Some(e)) if s > e => None?, @@ -94,27 +74,9 @@ pub fn validate(      Some(Event {          id,          date: NaiveDate::parse_from_str(&date, DATE_FORMAT).ok()?, -        name: validate_name(name)?, +        name: validation::non_empty(name)?,          start,          end,          repetition,      })  } - -fn validate_time(time: String) -> Option<Option<NaiveTime>> { -    let time = time.trim(); -    if time.is_empty() { -        Some(None) -    } else { -        parse_time(time).map(Some) -    } -} - -fn validate_name(name: String) -> Option<String> { -    let name = name.trim(); -    if name.is_empty() { -        None -    } else { -        Some(name.to_string()) -    } -} diff --git a/src/model/mod.rs b/src/model/mod.rs index c1beb62..0aefbc6 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -1,2 +1,3 @@  pub mod event;  pub mod repetition; +pub mod time; diff --git a/src/model/repetition.rs b/src/model/repetition.rs index 872944a..eb8cb6d 100644 --- a/src/model/repetition.rs +++ b/src/model/repetition.rs @@ -6,6 +6,7 @@ use std::collections::HashSet;  pub struct Repetition {      pub frequency: Frequency,      pub removed_occurences: HashSet<usize>, +    pub until: Option<NaiveDate>,  }  #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -48,6 +49,7 @@ impl Repetition {          let repeat = |mut date, next: Box<dyn Fn(NaiveDate) -> NaiveDate>| {              let mut repetitions = vec![];              let mut iteration: usize = 0; +            let end = self.until.unwrap_or(end);              while date <= end {                  if date >= event {                      if date >= start && !self.removed_occurences.contains(&iteration) { @@ -195,6 +197,7 @@ mod tests {          let repetition = Repetition {              frequency: Frequency::Daily { period: 2 },              removed_occurences: HashSet::from([0, 2, 3]), +            until: None,          };          assert_eq!(              repetition.between(d(2020, 7, 1), d(2020, 7, 1), d(2020, 7, 9)), @@ -209,6 +212,7 @@ mod tests {                  day: DayOfMonth::Day { day: 8 },              },              removed_occurences: HashSet::from([1, 3]), +            until: None,          };          assert_eq!(              repetition.between(d(2020, 1, 8), d(2020, 1, 8), d(2020, 4, 8)), @@ -225,6 +229,7 @@ mod tests {                  },              },              removed_occurences: HashSet::from([1, 2, 3]), +            until: None,          };          assert_eq!(              repetition.between(d(2020, 2, 1), d(2020, 2, 1), d(2020, 7, 1)), @@ -237,6 +242,7 @@ mod tests {          let repetition = Repetition {              frequency: Frequency::Yearly,              removed_occurences: HashSet::from([3]), +            until: None,          };          assert_eq!(              repetition.between(d(2018, 5, 5), d(2019, 8, 1), d(2022, 5, 5)), @@ -249,6 +255,7 @@ mod tests {          let repetition = Repetition {              frequency: Frequency::Yearly,              removed_occurences: HashSet::from([1]), +            until: None,          };          assert_eq!(              repetition.occurence_index(d(2020, 1, 1), d(2022, 1, 1)), @@ -256,6 +263,19 @@ mod tests {          )      } +    #[test] +    fn repetition_stops_after_until() { +        let repetition = Repetition { +            frequency: Frequency::Yearly, +            removed_occurences: HashSet::new(), +            until: Some(d(2022, 1, 1)), +        }; +        assert_eq!( +            repetition.between(d(2020, 1, 1), d(2020, 1, 1), d(2024, 1, 1)), +            vec!(d(2020, 1, 1), d(2021, 1, 1), d(2022, 1, 1)) +        ) +    } +      fn d(y: i32, m: u32, d: u32) -> NaiveDate {          NaiveDate::from_ymd(y, m, d)      } @@ -264,6 +284,7 @@ mod tests {          Repetition {              frequency,              removed_occurences: HashSet::new(), +            until: None,          }      }  } diff --git a/src/model/time.rs b/src/model/time.rs new file mode 100644 index 0000000..10cf6d3 --- /dev/null +++ b/src/model/time.rs @@ -0,0 +1,22 @@ +use chrono::{NaiveTime, Timelike}; + +pub fn pprint(t: NaiveTime) -> String { +    if t.minute() == 0 { +        format!("{}h", t.hour()) +    } else { +        format!("{}h{}", t.hour(), t.minute()) +    } +} + +pub fn parse(t: &str) -> Option<NaiveTime> { +    match t.split('h').collect::<Vec<&str>>()[..] { +        [hours, minutes] => { +            if minutes.trim().is_empty() { +                NaiveTime::from_hms_opt(hours.parse().ok()?, 0, 0) +            } else { +                NaiveTime::from_hms_opt(hours.parse().ok()?, minutes.parse().ok()?, 0) +            } +        } +        _ => None, +    } +} | 
