use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TaskState {
Submitted,
Working,
InputRequired,
Completed,
Failed,
Cancelled,
}
impl TaskState {
pub fn is_terminal(self) -> bool {
matches!(
self,
TaskState::Completed | TaskState::Failed | TaskState::Cancelled
)
}
pub fn can_transition(from: TaskState, to: TaskState) -> bool {
use TaskState::*;
if from == to {
return false;
}
if from.is_terminal() {
return false;
}
if matches!(to, Failed | Cancelled) {
return true;
}
matches!(
(from, to),
(Submitted, Working)
| (Working, InputRequired)
| (Working, Completed)
| (InputRequired, Working)
)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Task {
pub id: Uuid,
pub team_id: String,
pub title: String,
pub state: TaskState,
pub owner: String,
pub parent_task_id: Option<Uuid>,
pub requirement_id: Option<String>,
pub epic_id: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl Task {
pub fn new(
team_id: impl Into<String>,
title: impl Into<String>,
owner: impl Into<String>,
) -> Self {
let now = Utc::now();
Task {
id: Uuid::new_v4(),
team_id: team_id.into(),
title: title.into(),
state: TaskState::Submitted,
owner: owner.into(),
parent_task_id: None,
requirement_id: None,
epic_id: None,
created_at: now,
updated_at: now,
}
}
}