task_info.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. use std::{
  2. io,
  3. path::{Path, PathBuf},
  4. };
  5. use log::debug;
  6. use serde::{Deserialize, Serialize};
  7. use darkfi::util::{
  8. serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt},
  9. Timestamp,
  10. };
  11. use crate::{
  12. error::{TaudError, TaudResult},
  13. month_tasks::MonthTasks,
  14. util::{find_free_id, load, random_ref_id, save},
  15. };
  16. #[derive(Clone, Debug, Serialize, Deserialize, SerialEncodable, SerialDecodable, PartialEq)]
  17. struct TaskEvent {
  18. action: String,
  19. timestamp: Timestamp,
  20. }
  21. impl TaskEvent {
  22. fn new(action: String) -> Self {
  23. Self { action, timestamp: Timestamp::current_time() }
  24. }
  25. }
  26. #[derive(Clone, Debug, Serialize, Deserialize, SerialDecodable, SerialEncodable, PartialEq)]
  27. pub struct Comment {
  28. content: String,
  29. author: String,
  30. timestamp: Timestamp,
  31. }
  32. impl Comment {
  33. pub fn new(content: &str, author: &str) -> Self {
  34. Self {
  35. content: content.into(),
  36. author: author.into(),
  37. timestamp: Timestamp::current_time(),
  38. }
  39. }
  40. }
  41. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
  42. pub struct TaskEvents(Vec<TaskEvent>);
  43. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
  44. pub struct TaskComments(Vec<Comment>);
  45. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
  46. pub struct TaskProjects(Vec<String>);
  47. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
  48. pub struct TaskAssigns(Vec<String>);
  49. #[derive(Clone, Debug, Serialize, Deserialize, SerialEncodable, SerialDecodable, PartialEq)]
  50. pub struct TaskInfo {
  51. pub(crate) ref_id: String,
  52. id: u32,
  53. title: String,
  54. desc: String,
  55. owner: String,
  56. assign: TaskAssigns,
  57. project: TaskProjects,
  58. due: Option<Timestamp>,
  59. rank: f32,
  60. created_at: Timestamp,
  61. events: TaskEvents,
  62. comments: TaskComments,
  63. }
  64. impl TaskInfo {
  65. pub fn new(
  66. title: &str,
  67. desc: &str,
  68. owner: &str,
  69. due: Option<Timestamp>,
  70. rank: f32,
  71. dataset_path: &Path,
  72. ) -> TaudResult<Self> {
  73. // generate ref_id
  74. let ref_id = random_ref_id();
  75. let created_at = Timestamp::current_time();
  76. let task_ids: Vec<u32> =
  77. MonthTasks::load_current_open_tasks(dataset_path)?.into_iter().map(|t| t.id).collect();
  78. let id: u32 = find_free_id(&task_ids);
  79. if let Some(d) = &due {
  80. if *d < Timestamp::current_time() {
  81. return Err(TaudError::InvalidDueTime)
  82. }
  83. }
  84. Ok(Self {
  85. ref_id,
  86. id,
  87. title: title.into(),
  88. desc: desc.into(),
  89. owner: owner.into(),
  90. assign: TaskAssigns(vec![]),
  91. project: TaskProjects(vec![]),
  92. due,
  93. rank,
  94. created_at,
  95. comments: TaskComments(vec![]),
  96. events: TaskEvents(vec![]),
  97. })
  98. }
  99. pub fn load(ref_id: &str, dataset_path: &Path) -> TaudResult<Self> {
  100. debug!(target: "tau", "TaskInfo::load()");
  101. let task = load::<Self>(&Self::get_path(ref_id, dataset_path))?;
  102. Ok(task)
  103. }
  104. pub fn save(&self, dataset_path: &Path) -> TaudResult<()> {
  105. debug!(target: "tau", "TaskInfo::save()");
  106. save::<Self>(&Self::get_path(&self.ref_id, dataset_path), self)
  107. .map_err(TaudError::Darkfi)?;
  108. if self.get_state() == "stop" {
  109. self.deactivate(dataset_path)?;
  110. } else {
  111. self.activate(dataset_path)?;
  112. }
  113. Ok(())
  114. }
  115. pub fn activate(&self, path: &Path) -> TaudResult<()> {
  116. debug!(target: "tau", "TaskInfo::activate()");
  117. let mut mt = MonthTasks::load_or_create(Some(&self.created_at), path)?;
  118. mt.add(&self.ref_id);
  119. mt.save(path)
  120. }
  121. pub fn deactivate(&self, path: &Path) -> TaudResult<()> {
  122. debug!(target: "tau", "TaskInfo::deactivate()");
  123. let mut mt = MonthTasks::load_or_create(Some(&self.created_at), path)?;
  124. mt.remove(&self.ref_id);
  125. mt.save(path)
  126. }
  127. pub fn get_state(&self) -> String {
  128. debug!(target: "tau", "TaskInfo::get_state()");
  129. if let Some(ev) = self.events.0.last() {
  130. ev.action.clone()
  131. } else {
  132. "open".into()
  133. }
  134. }
  135. fn get_path(ref_id: &str, dataset_path: &Path) -> PathBuf {
  136. debug!(target: "tau", "TaskInfo::get_path()");
  137. dataset_path.join("task").join(ref_id)
  138. }
  139. pub fn get_id(&self) -> u32 {
  140. debug!(target: "tau", "TaskInfo::get_id()");
  141. self.id
  142. }
  143. pub fn set_title(&mut self, title: &str) {
  144. debug!(target: "tau", "TaskInfo::set_title()");
  145. self.title = title.into();
  146. }
  147. pub fn set_desc(&mut self, desc: &str) {
  148. debug!(target: "tau", "TaskInfo::set_desc()");
  149. self.desc = desc.into();
  150. }
  151. pub fn set_assign(&mut self, assign: &[String]) {
  152. debug!(target: "tau", "TaskInfo::set_assign()");
  153. self.assign = TaskAssigns(assign.to_owned());
  154. }
  155. pub fn set_project(&mut self, project: &[String]) {
  156. debug!(target: "tau", "TaskInfo::set_project()");
  157. self.project = TaskProjects(project.to_owned());
  158. }
  159. pub fn set_comment(&mut self, c: Comment) {
  160. debug!(target: "tau", "TaskInfo::set_comment()");
  161. self.comments.0.push(c);
  162. }
  163. pub fn set_rank(&mut self, r: f32) {
  164. debug!(target: "tau", "TaskInfo::set_rank()");
  165. self.rank = r;
  166. }
  167. pub fn set_due(&mut self, d: Option<Timestamp>) {
  168. debug!(target: "tau", "TaskInfo::set_due()");
  169. self.due = d;
  170. }
  171. pub fn set_state(&mut self, action: &str) {
  172. debug!(target: "tau", "TaskInfo::set_state()");
  173. if self.get_state() == action {
  174. return
  175. }
  176. self.events.0.push(TaskEvent::new(action.into()));
  177. }
  178. }
  179. impl Encodable for TaskEvents {
  180. fn encode<S: io::Write>(&self, s: S) -> darkfi::Result<usize> {
  181. encode_vec(&self.0, s)
  182. }
  183. }
  184. impl Decodable for TaskEvents {
  185. fn decode<D: io::Read>(d: D) -> darkfi::Result<Self> {
  186. Ok(Self(decode_vec(d)?))
  187. }
  188. }
  189. impl Encodable for TaskComments {
  190. fn encode<S: io::Write>(&self, s: S) -> darkfi::Result<usize> {
  191. encode_vec(&self.0, s)
  192. }
  193. }
  194. impl Decodable for TaskComments {
  195. fn decode<D: io::Read>(d: D) -> darkfi::Result<Self> {
  196. Ok(Self(decode_vec(d)?))
  197. }
  198. }
  199. impl Encodable for TaskProjects {
  200. fn encode<S: io::Write>(&self, s: S) -> darkfi::Result<usize> {
  201. encode_vec(&self.0, s)
  202. }
  203. }
  204. impl Decodable for TaskProjects {
  205. fn decode<D: io::Read>(d: D) -> darkfi::Result<Self> {
  206. Ok(Self(decode_vec(d)?))
  207. }
  208. }
  209. impl Encodable for TaskAssigns {
  210. fn encode<S: io::Write>(&self, s: S) -> darkfi::Result<usize> {
  211. encode_vec(&self.0, s)
  212. }
  213. }
  214. impl Decodable for TaskAssigns {
  215. fn decode<D: io::Read>(d: D) -> darkfi::Result<Self> {
  216. Ok(Self(decode_vec(d)?))
  217. }
  218. }
  219. fn encode_vec<T: Encodable, S: io::Write>(vec: &[T], mut s: S) -> darkfi::Result<usize> {
  220. let mut len = 0;
  221. len += VarInt(vec.len() as u64).encode(&mut s)?;
  222. for c in vec.iter() {
  223. len += c.encode(&mut s)?;
  224. }
  225. Ok(len)
  226. }
  227. fn decode_vec<T: Decodable, D: io::Read>(mut d: D) -> darkfi::Result<Vec<T>> {
  228. let len = VarInt::decode(&mut d)?.0;
  229. let mut ret = Vec::with_capacity(len as usize);
  230. for _ in 0..len {
  231. ret.push(Decodable::decode(&mut d)?);
  232. }
  233. Ok(ret)
  234. }