pub mod events; pub mod operations; pub mod values; use std::{fmt::Display, str::FromStr}; use events::IssueTimeline; use serde::{Deserialize, Serialize}; use crate::{object::GiteratedObject, repository::Repository, user::User}; /// An issue, defined by the [`Repository`] it is related to along with /// its id. /// /// # Textual Format /// An issue's textual reference is defined as: /// /// `#{id: u64}:{repository: Repository}` #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Issue { pub id: u64, /// The repository the issue is related to pub repository: Repository, } impl GiteratedObject for Issue { fn object_name() -> &'static str { "issue" } fn home_uri(&self) -> String { self.repository.home_uri() } fn from_object_str(object_str: &str) -> Result { Ok(Issue::from_str(object_str)?) } } impl Display for Issue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("#{}:{}", self.id, self.repository)) } } #[derive(Debug, thiserror::Error)] #[error("couldn't parse issue")] pub struct IssueParseError; impl FromStr for Issue { type Err = IssueParseError; fn from_str(s: &str) -> Result { // Remove the pound from the start let s = s .starts_with('#') .then(|| s.replace('#', "")) .ok_or(IssueParseError)?; // Split the id from the repository let (id, repository) = s.split_once(':').ok_or(IssueParseError)?; // Parse the id and the repository let id: u64 = id.parse().map_err(|_| IssueParseError)?; let repository = Repository::from_str(repository).map_err(|_| IssueParseError)?; Ok(Self { id, repository }) } } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueInfo { #[serde(flatten)] pub basic: IssueInfoBasic, pub body: String, pub timeline: IssueTimeline, } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueInfoBasic { pub id: u64, pub status: IssueStatus, pub title: String, pub tags: Vec, pub last_activity: chrono::DateTime, pub created: chrono::DateTime, pub creator: User, pub statistics: IssueStatistics, pub assignees: Vec, } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueStatistics { pub comments: u64, } /// Tag (sometimes referred to as label) to categorize issues. #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueTag { pub category: String, pub sub_category: Option, pub description: Option, } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum IssueStatus { Open, Closed, } impl Display for IssueStatus { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { IssueStatus::Open => f.write_str("Open"), IssueStatus::Closed => f.write_str("Closed"), } } } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueComment { /// Event id pub id: u64, /// Creation date pub created: chrono::DateTime, /// The user who created the comment pub creator: User, /// Body of the comment pub body: String, } #[derive(Hash, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct IssueCommentRevision { /// Event id pub id: u64, /// Creation date pub created: chrono::DateTime, /// Body of the comment pub body: String, }