aboutsummaryrefslogtreecommitdiff
path: root/src/model/event.rs
blob: 98ce416685fddc600edad7deb2bc460a94ce62b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone};
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";

#[derive(Debug, Clone)]
pub struct Event {
    pub id: Uuid,
    pub date: NaiveDate,
    pub start: Option<NaiveTime>,
    pub end: Option<NaiveTime>,
    pub name: String,
    pub repetition: Option<Repetition>,
    pub category: Option<Uuid>,
}

impl Event {
    pub fn pprint(&self) -> String {
        let start = self.start.map(time::pprint).unwrap_or_default();
        let end = self
            .end
            .map(|t| format!("-{}", time::pprint(t)))
            .unwrap_or_default();
        let space = if self.start.is_some() || self.end.is_some() {
            " "
        } else {
            ""
        };
        format!("{}{}{}{}", start, end, space, self.name)
    }

    pub fn local_timestamp(&self) -> Option<i64> {
        let time = self.start.unwrap_or(NaiveTime::from_hms_opt(0, 0, 0)?);
        let naive_datetime = NaiveDateTime::new(self.date, time);
        let local_datetime = Local.from_local_datetime(&naive_datetime).single()?;
        Some(local_datetime.timestamp())
    }
}

/// Recurring events in an date range (inclusive)
pub fn repetitions_between(
    events: &[Event],
    start: NaiveDate,
    end: NaiveDate,
) -> HashMap<NaiveDate, Vec<Event>> {
    let mut res: HashMap<NaiveDate, Vec<Event>> = HashMap::new();

    for event in events {
        if let Some(repetition) = &event.repetition {
            for date in repetition.between(event.date, start, end) {
                res.entry(date).or_default().push(event.clone())
            }
        }
    }

    res
}

// Validation

pub fn validate(
    id: Uuid,
    date: String,
    name: String,
    start: String,
    end: String,
    repetition: Option<Repetition>,
    category: Option<Uuid>,
) -> Option<Event> {
    let start = validation::time(start)?;
    let end = validation::time(end)?;

    match (start, end) {
        (Some(s), Some(e)) if s > e => None?,
        _ => (),
    }

    Some(Event {
        id,
        date: NaiveDate::parse_from_str(&date, DATE_FORMAT).ok()?,
        name: validation::non_empty(name)?,
        start,
        end,
        repetition,
        category,
    })
}