use serde::{Deserialize, Serialize};
use crate::user::User;
pub mod user;
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Issues {
list: Vec<Issue>,
labels: Vec<String>,
}
impl easy_storage::Storeable for Issues {}
impl Issues {
pub fn new() -> Self {
let now = chrono::Local::now();
let root_issue = Issue {
name: "root".to_string(),
status: Status::CloseAsCmp,
comment: Vec::new(),
created_by: User::new("root", "root"),
from: usize::MAX,
created_at: now,
updated_at: now,
labels: Vec::new(),
};
Self {
list: vec![root_issue],
labels: vec!["Bug".to_string(), "Enhance".to_string()],
}
}
pub fn add_new_issue(&mut self, i: Issue) -> usize {
let l = self.list.len();
self.list.push(i);
l
}
pub fn get_list(&self) -> &Vec<Issue> {
&self.list
}
pub fn find_from_title<T: AsRef<str>>(&mut self, s: T) -> Option<Vec<&mut Issue>> {
let res = self
.list
.iter_mut()
.filter(|f| f.name.contains(s.as_ref()))
.collect::<Vec<_>>();
if res.is_empty() { None } else { Some(res) }
}
pub fn find_from_updated_time(
&mut self,
st: chrono::DateTime<chrono::Local>,
ed: chrono::DateTime<chrono::Local>,
) -> Option<Vec<&mut Issue>> {
let res = self
.list
.iter_mut()
.filter(|f| (st..=ed).contains(&f.updated_at))
.collect::<Vec<_>>();
if res.is_empty() { None } else { Some(res) }
}
pub fn find_from_created_time(
&mut self,
st: chrono::DateTime<chrono::Local>,
ed: chrono::DateTime<chrono::Local>,
) -> Option<Vec<&mut Issue>> {
let res = self
.list
.iter_mut()
.filter(|f| (st..=ed).contains(&f.created_at))
.collect::<Vec<_>>();
if res.is_empty() { None } else { Some(res) }
}
pub fn find_from_comments<T: AsRef<str>>(&mut self, s: T) -> Option<Vec<&mut Issue>> {
let res = self
.list
.iter_mut()
.filter(|f| f.contains_comment(s.as_ref()))
.collect::<Vec<_>>();
if res.is_empty() { None } else { Some(res) }
}
pub fn get(&self, index: usize) -> Option<&Issue> {
self.list.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut Issue> {
self.list.get_mut(index)
}
pub fn fork(&mut self, from: usize) -> Option<usize> {
let mut forked = self.get(from)?.clone();
forked.from = from;
forked.status = Status::Open;
self.get_mut(from).unwrap().status = Status::CloseAsForked;
Some(self.add_new_issue(forked))
}
pub fn get_registered_labels(&self) -> Vec<String> {
self.labels.clone()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Issue {
name: String,
status: Status,
comment: Vec<Comment>,
created_by: User,
created_at: chrono::DateTime<chrono::Local>,
updated_at: chrono::DateTime<chrono::Local>,
labels: Vec<String>,
from: usize,
}
impl Issue {
pub fn new<T: AsRef<str>, U: AsRef<str>>(name: T, user: User, labels: Vec<U>) -> Self {
let now = chrono::Local::now();
let labels = labels
.iter()
.map(|f| f.as_ref().to_string())
.collect::<Vec<_>>();
Self {
name: name.as_ref().to_string(),
status: Status::default(),
comment: Vec::new(),
created_by: user,
from: 0,
created_at: now,
updated_at: now,
labels,
}
}
pub fn get_labels(&self) -> Vec<String> {
self.labels.clone()
}
pub fn update(&mut self) {
self.updated_at = chrono::Local::now();
}
pub fn close_as_cmp(&mut self) {
self.status = Status::CloseAsCmp;
self.update();
}
pub fn close_as_not_planed(&mut self) {
self.status = Status::CloseAsNotPlaned;
self.update();
}
pub fn close_as_forked(&mut self) {
self.status = Status::CloseAsForked;
self.update();
}
pub fn comment(&mut self, new_comment: Comment) {
self.comment.push(new_comment);
self.update();
}
pub fn contains_comment<T: AsRef<str>>(&self, s: T) -> bool {
let res = self
.comment
.iter()
.filter(|f| f.content.contains(s.as_ref()))
.collect::<Vec<_>>();
!res.is_empty()
}
pub fn name(&self) -> &str {
&self.name
}
pub fn status(&self) -> &Status {
&self.status
}
pub fn created_by(&self) -> &User {
&self.created_by
}
pub fn created_at(&self) -> &chrono::DateTime<chrono::Local> {
&self.created_at
}
pub fn updated_at(&self) -> &chrono::DateTime<chrono::Local> {
&self.updated_at
}
pub fn comments(&self) -> &Vec<Comment> {
&self.comment
}
pub fn from_index(&self) -> usize {
self.from
}
pub fn reopen(&mut self) {
self.status = Status::Open
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Status {
#[default]
Open,
CloseAsCmp,
CloseAsNotPlaned,
CloseAsForked,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Comment {
content: String,
date: chrono::DateTime<chrono::Local>,
user: user::User,
}
impl Comment {
pub fn new<T: AsRef<str>>(content: T, user: user::User) -> Self {
Self {
content: content.as_ref().to_string(),
date: chrono::Local::now(),
user,
}
}
pub fn author(&self) -> &User {
&self.user
}
pub fn text(&self) -> String {
self.content.clone()
}
pub fn date(&self) -> chrono::DateTime<chrono::Local> {
self.date
}
}