1use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5use chrono::{DateTime, Utc};
6use ical::property::Property;
7use url::Url;
8
9use crate::item::SyncStatus;
10use crate::utils::random_url;
11
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
19pub enum CompletionStatus {
20 Completed(Option<DateTime<Utc>>),
21 Uncompleted,
22}
23impl CompletionStatus {
24 pub fn is_completed(&self) -> bool {
25 match self {
26 CompletionStatus::Completed(_) => true,
27 _ => false,
28 }
29 }
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize)]
34pub struct Task {
35 url: Url,
37
38 uid: String,
42
43 sync_status: SyncStatus,
45 creation_date: Option<DateTime<Utc>>,
48 last_modified: DateTime<Utc>,
50 completion_status: CompletionStatus,
52
53 name: String,
55
56
57 ical_prod_id: String,
59
60 extra_parameters: Vec<Property>,
63}
64
65
66impl Task {
67 pub fn new(name: String, completed: bool, parent_calendar_url: &Url) -> Self {
70 let new_url = random_url(parent_calendar_url);
71 let new_sync_status = SyncStatus::NotSynced;
72 let new_uid = Uuid::new_v4().to_hyphenated().to_string();
73 let new_creation_date = Some(Utc::now());
74 let new_last_modified = Utc::now();
75 let new_completion_status = if completed {
76 CompletionStatus::Completed(Some(Utc::now()))
77 } else { CompletionStatus::Uncompleted };
78 let ical_prod_id = crate::ical::default_prod_id();
79 let extra_parameters = Vec::new();
80 Self::new_with_parameters(name, new_uid, new_url, new_completion_status, new_sync_status, new_creation_date, new_last_modified, ical_prod_id, extra_parameters)
81 }
82
83 pub fn new_with_parameters(name: String, uid: String, new_url: Url,
85 completion_status: CompletionStatus,
86 sync_status: SyncStatus, creation_date: Option<DateTime<Utc>>, last_modified: DateTime<Utc>,
87 ical_prod_id: String, extra_parameters: Vec<Property>,
88 ) -> Self
89 {
90 Self {
91 url: new_url,
92 uid,
93 name,
94 completion_status,
95 sync_status,
96 creation_date,
97 last_modified,
98 ical_prod_id,
99 extra_parameters,
100 }
101 }
102
103 pub fn url(&self) -> &Url { &self.url }
104 pub fn uid(&self) -> &str { &self.uid }
105 pub fn name(&self) -> &str { &self.name }
106 pub fn completed(&self) -> bool { self.completion_status.is_completed() }
107 pub fn ical_prod_id(&self) -> &str { &self.ical_prod_id }
108 pub fn sync_status(&self) -> &SyncStatus { &self.sync_status }
109 pub fn last_modified(&self) -> &DateTime<Utc> { &self.last_modified }
110 pub fn creation_date(&self) -> Option<&DateTime<Utc>> { self.creation_date.as_ref() }
111 pub fn completion_status(&self) -> &CompletionStatus { &self.completion_status }
112 pub fn extra_parameters(&self) -> &[Property] { &self.extra_parameters }
113
114 #[cfg(any(test, feature = "integration_tests"))]
115 pub fn has_same_observable_content_as(&self, other: &Task) -> bool {
116 self.url == other.url
117 && self.uid == other.uid
118 && self.name == other.name
119 && std::mem::discriminant(&self.sync_status) == std::mem::discriminant(&other.sync_status)
121 && std::mem::discriminant(&self.completion_status) == std::mem::discriminant(&other.completion_status)
123 }
125
126 pub fn set_sync_status(&mut self, new_status: SyncStatus) {
127 self.sync_status = new_status;
128 }
129
130 fn update_sync_status(&mut self) {
131 match &self.sync_status {
132 SyncStatus::NotSynced => return,
133 SyncStatus::LocallyModified(_) => return,
134 SyncStatus::Synced(prev_vt) => {
135 self.sync_status = SyncStatus::LocallyModified(prev_vt.clone());
136 }
137 SyncStatus::LocallyDeleted(_) => {
138 log::warn!("Trying to update an item that has previously been deleted. These changes will probably be ignored at next sync.");
139 return;
140 },
141 }
142 }
143
144 fn update_last_modified(&mut self) {
145 self.last_modified = Utc::now();
146 }
147
148
149 pub fn set_name(&mut self, new_name: String) {
152 self.update_sync_status();
153 self.update_last_modified();
154 self.name = new_name;
155 }
156 #[cfg(feature = "local_calendar_mocks_remote_calendars")]
157 pub fn mock_remote_calendar_set_name(&mut self, new_name: String) {
159 self.sync_status = SyncStatus::random_synced();
160 self.update_last_modified();
161 self.name = new_name;
162 }
163
164 pub fn set_completion_status(&mut self, new_completion_status: CompletionStatus) {
166 self.update_sync_status();
167 self.update_last_modified();
168 self.completion_status = new_completion_status;
169 }
170 #[cfg(feature = "local_calendar_mocks_remote_calendars")]
171 pub fn mock_remote_calendar_set_completion_status(&mut self, new_completion_status: CompletionStatus) {
173 self.sync_status = SyncStatus::random_synced();
174 self.completion_status = new_completion_status;
175 }
176}