kitchen_fridge/
item.rs

1//! CalDAV items (todo, events, journals...)
2// TODO: move Event and Task to nest them in crate::items::calendar::Calendar?
3
4use serde::{Deserialize, Serialize};
5use url::Url;
6use chrono::{DateTime, Utc};
7
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
10pub enum Item {
11    Event(crate::event::Event),
12    Task(crate::task::Task),
13}
14
15/// Returns `task.$property_name` or `event.$property_name`, depending on whether self is a Task or an Event
16macro_rules! synthetise_common_getter {
17    ($property_name:ident, $return_type:ty) => {
18        pub fn $property_name(&self) -> $return_type {
19            match self {
20                Item::Event(e) => e.$property_name(),
21                Item::Task(t) => t.$property_name(),
22            }
23        }
24    }
25}
26
27impl Item {
28    synthetise_common_getter!(url, &Url);
29    synthetise_common_getter!(uid, &str);
30    synthetise_common_getter!(name, &str);
31    synthetise_common_getter!(creation_date, Option<&DateTime<Utc>>);
32    synthetise_common_getter!(last_modified, &DateTime<Utc>);
33    synthetise_common_getter!(sync_status, &SyncStatus);
34    synthetise_common_getter!(ical_prod_id, &str);
35
36    pub fn set_sync_status(&mut self, new_status: SyncStatus) {
37        match self {
38            Item::Event(e) => e.set_sync_status(new_status),
39            Item::Task(t) => t.set_sync_status(new_status),
40        }
41    }
42
43    pub fn is_event(&self) -> bool {
44        match &self {
45            Item::Event(_) => true,
46            _ => false,
47        }
48    }
49
50    pub fn is_task(&self) -> bool {
51        match &self {
52            Item::Task(_) => true,
53            _ => false,
54        }
55    }
56
57    /// Returns a mutable reference to the inner Task
58    ///
59    /// # Panics
60    /// Panics if the inner item is not a Task
61    pub fn unwrap_task_mut(&mut self) -> &mut crate::task::Task {
62        match self {
63            Item::Task(t) => t,
64            _ => panic!("Not a task"),
65        }
66    }
67
68    /// Returns a reference to the inner Task
69    ///
70    /// # Panics
71    /// Panics if the inner item is not a Task
72    pub fn unwrap_task(&self) -> &crate::task::Task {
73        match self {
74            Item::Task(t) => t,
75            _ => panic!("Not a task"),
76        }
77    }
78
79    #[cfg(any(test, feature = "integration_tests"))]
80    pub fn has_same_observable_content_as(&self, other: &Item) -> bool {
81        match (self, other) {
82            (Item::Event(s), Item::Event(o)) => s.has_same_observable_content_as(o),
83            (Item::Task(s),  Item::Task(o))  => s.has_same_observable_content_as(o),
84            _ => false,
85        }
86    }
87}
88
89
90
91
92/// A VersionTag is basically a CalDAV `ctag` or `etag`. Whenever it changes, this means the data has changed.
93#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
94pub struct VersionTag {
95    tag: String
96}
97
98impl From<String> for VersionTag {
99    fn from(tag: String) -> VersionTag {
100        Self { tag }
101    }
102}
103
104impl VersionTag {
105    /// Get the inner version tag (usually a WebDAV `ctag` or `etag`)
106    pub fn as_str(&self) -> &str {
107        &self.tag
108    }
109
110    /// Generate a random VersionTag
111    #[cfg(feature = "local_calendar_mocks_remote_calendars")]
112    pub fn random() -> Self {
113        let random = uuid::Uuid::new_v4().to_hyphenated().to_string();
114        Self { tag: random }
115    }
116}
117
118
119
120/// Describes whether this item has been synced already, or modified since the last time it was synced
121#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
122pub enum SyncStatus {
123    /// This item has ben locally created, and never synced yet
124    NotSynced,
125    /// At the time this item has ben synced, it has a given version tag, and has not been locally modified since then.
126    /// Note: in integration tests, in case we are mocking a remote calendar by a local calendar, this is the only valid variant (remote calendars make no distinction between all these variants)
127    Synced(VersionTag),
128    /// This item has been synced when it had a given version tag, and has been locally modified since then.
129    LocallyModified(VersionTag),
130    /// This item has been synced when it had a given version tag, and has been locally deleted since then.
131    LocallyDeleted(VersionTag),
132}
133impl SyncStatus {
134    /// Generate a random SyncStatus::Synced
135    #[cfg(feature = "local_calendar_mocks_remote_calendars")]
136    pub fn random_synced() -> Self {
137        Self::Synced(VersionTag::random())
138    }
139}