issuecraft_core/
lib.rs

1use async_trait::async_trait;
2use facet::Facet;
3use facet_json::{DeserializeError, JsonError};
4use issuecraft_ql::{
5    CloseReason, ExecutionEngine, ExecutionResult, IqlQuery, IssueId, IssueKind, ProjectId, UserId,
6};
7
8#[derive(thiserror::Error, Debug)]
9pub enum ClientError {
10    #[error("Not implemented")]
11    NotImplemented,
12    #[error("This action is not supported by the chosen backend")]
13    NotSupported,
14    #[error("IQL error: {0}")]
15    IqlError(#[from] issuecraft_ql::IqlError),
16    #[error("Deserialization error: {0}")]
17    DeserializationError(#[from] DeserializeError<JsonError>),
18    #[error("Client specific: {0}")]
19    ClientSpecific(String),
20}
21
22#[derive(Debug, Clone, Facet)]
23pub struct UserInfo {
24    pub name: String,
25    #[facet( skip_serializing_if = Option::is_none)]
26    pub display: Option<String>,
27    pub email: String,
28}
29
30#[derive(Debug, Clone, Facet)]
31pub struct ProjectInfo {
32    #[facet(skip_serializing_if = Option::is_none)]
33    pub description: Option<String>,
34    pub owner: UserId,
35    #[facet(skip_serializing_if = Option::is_none)]
36    pub display: Option<String>,
37}
38
39#[derive(Debug, Clone, Facet)]
40#[repr(C)]
41pub enum IssueStatus {
42    Open,
43    Assigned,
44    Blocked,
45    Closed { reason: CloseReason },
46}
47
48#[derive(Debug, Clone, Facet)]
49#[repr(C)]
50pub enum Priority {
51    Low,
52    Medium,
53    High,
54    Critical,
55}
56
57#[derive(Debug, Clone, Facet)]
58pub struct IssueInfo {
59    pub title: String,
60    pub kind: IssueKind,
61    #[facet(skip_serializing_if = Option::is_none)]
62    pub description: Option<String>,
63    pub status: IssueStatus,
64    pub project: ProjectId,
65    #[facet(skip_serializing_if = Option::is_none)]
66    pub priority: Option<Priority>,
67    #[facet(skip_serializing_if = Option::is_none)]
68    pub assignee: Option<UserId>,
69}
70
71impl IssueInfo {
72    pub fn is_closed(&self) -> bool {
73        matches!(self.status, IssueStatus::Closed { .. })
74    }
75}
76
77#[derive(Debug, Clone, Facet)]
78pub struct CommentInfo {
79    pub issue: IssueId,
80    pub created_at: time::UtcDateTime,
81    pub content: String,
82    pub author: UserId,
83}
84
85#[derive(Debug, Clone)]
86pub enum AuthenticationInfo {
87    Password { password: String },
88    Token { token: String },
89    Certificate { path: Vec<u8> },
90}
91
92#[derive(Debug, Clone)]
93pub struct LoginInfo {
94    pub user: String,
95    pub auth: AuthenticationInfo,
96}
97
98#[async_trait]
99pub trait Client {
100    async fn login(&mut self, _login: LoginInfo) -> Result<(), ClientError> {
101        Err(ClientError::NotSupported)
102    }
103    async fn logout(&mut self) -> Result<(), ClientError> {
104        Err(ClientError::NotSupported)
105    }
106    async fn query(&mut self, query: &IqlQuery) -> Result<ExecutionResult, ClientError>;
107}
108
109#[async_trait]
110impl<E: ExecutionEngine + Send> Client for E {
111    async fn query(&mut self, query: &IqlQuery) -> Result<ExecutionResult, ClientError> {
112        let result = self.execute(query).await?;
113        Ok(result)
114    }
115}
116
117pub trait Backend {
118    fn init(&mut self) {}
119}