primitives.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. use std::{fmt, str::FromStr};
  2. use darkfi::{util::time::Timestamp, Error, Result};
  3. use crate::due_as_timestamp;
  4. pub enum State {
  5. Open,
  6. Start,
  7. Pause,
  8. Stop,
  9. }
  10. impl State {
  11. pub const fn is_start(&self) -> bool {
  12. matches!(*self, Self::Start)
  13. }
  14. pub const fn is_pause(&self) -> bool {
  15. matches!(*self, Self::Pause)
  16. }
  17. pub const fn is_stop(&self) -> bool {
  18. matches!(*self, Self::Stop)
  19. }
  20. }
  21. impl fmt::Display for State {
  22. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  23. match self {
  24. State::Open => write!(f, "open"),
  25. State::Start => write!(f, "start"),
  26. State::Stop => write!(f, "stop"),
  27. State::Pause => write!(f, "pause"),
  28. }
  29. }
  30. }
  31. impl FromStr for State {
  32. type Err = Error;
  33. fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
  34. let result = match s.to_lowercase().as_str() {
  35. "open" => State::Open,
  36. "stop" => State::Stop,
  37. "start" => State::Start,
  38. "pause" => State::Pause,
  39. _ => return Err(Error::ParseFailed("unable to parse state")),
  40. };
  41. Ok(result)
  42. }
  43. }
  44. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
  45. pub struct BaseTask {
  46. pub title: String,
  47. pub tags: Vec<String>,
  48. pub desc: Option<String>,
  49. pub assign: Vec<String>,
  50. pub project: Vec<String>,
  51. pub due: Option<i64>,
  52. pub rank: Option<f32>,
  53. }
  54. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
  55. pub struct TaskInfo {
  56. pub ref_id: String,
  57. pub workspace: String,
  58. pub id: u32,
  59. pub title: String,
  60. pub tags: Vec<String>,
  61. pub desc: String,
  62. pub owner: String,
  63. pub assign: Vec<String>,
  64. pub project: Vec<String>,
  65. pub due: Option<i64>,
  66. pub rank: Option<f32>,
  67. pub created_at: i64,
  68. pub state: String,
  69. pub events: Vec<TaskEvent>,
  70. pub comments: Vec<Comment>,
  71. }
  72. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
  73. pub struct TaskEvent {
  74. pub action: String,
  75. pub author: String,
  76. pub content: String,
  77. pub timestamp: Timestamp,
  78. }
  79. impl std::fmt::Display for TaskEvent {
  80. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  81. write!(f, "action: {}, timestamp: {}", self.action, self.timestamp)
  82. }
  83. }
  84. impl Default for TaskEvent {
  85. fn default() -> Self {
  86. Self {
  87. action: State::Open.to_string(),
  88. author: "".to_string(),
  89. content: "".to_string(),
  90. timestamp: Timestamp::current_time(),
  91. }
  92. }
  93. }
  94. #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
  95. pub struct Comment {
  96. content: String,
  97. author: String,
  98. timestamp: Timestamp,
  99. }
  100. impl std::fmt::Display for Comment {
  101. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  102. write!(f, "{} author: {}, content: {} ", self.timestamp, self.author, self.content)
  103. }
  104. }
  105. pub fn task_from_cli(values: Vec<String>) -> Result<BaseTask> {
  106. let mut title = String::new();
  107. let mut tags = vec![];
  108. let mut desc = None;
  109. let mut project = vec![];
  110. let mut assign = vec![];
  111. let mut due = None;
  112. let mut rank = None;
  113. for val in values {
  114. let field: Vec<&str> = val.split(':').collect();
  115. if field.len() == 1 {
  116. if field[0].starts_with('+') || field[0].starts_with('-') {
  117. tags.push(field[0].into());
  118. continue
  119. }
  120. title.push_str(field[0]);
  121. title.push(' ');
  122. continue
  123. }
  124. if field.len() != 2 {
  125. continue
  126. }
  127. if field[0] == "project" {
  128. project = field[1].split(',').map(|s| s.into()).collect();
  129. }
  130. if field[0] == "desc" {
  131. desc = Some(field[1].into());
  132. }
  133. if field[0] == "assign" {
  134. assign = field[1].split(',').map(|s| s.into()).collect();
  135. }
  136. if field[0] == "due" {
  137. due = due_as_timestamp(field[1])
  138. }
  139. if field[0] == "rank" {
  140. rank = Some(field[1].parse::<f32>()?);
  141. }
  142. }
  143. let title = title.trim().into();
  144. Ok(BaseTask { title, tags, desc, project, assign, due, rank })
  145. }