task_info.rs 7.5 KB

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