Skip to main content

zammad_api/api/
articles.rs

1use reqwest::Method;
2use serde::Serialize;
3
4use crate::client::Client;
5use crate::error::Result;
6use crate::models::{Article, NewArticle};
7
8const PATH: &str = "api/v1/ticket_articles";
9
10/// Ticket-article endpoints (replies, notes, emails, ...).
11#[derive(Debug)]
12pub struct ArticlesApi<'a> {
13    client: &'a Client,
14}
15
16impl<'a> ArticlesApi<'a> {
17    pub(crate) fn new(client: &'a Client) -> Self {
18        Self { client }
19    }
20
21    /// `GET /api/v1/ticket_articles/by_ticket/:ticket_id` - every article on
22    /// the ticket.
23    pub async fn by_ticket(&self, ticket_id: u64) -> Result<Vec<Article>> {
24        let req = self
25            .client
26            .request(Method::GET, &format!("{PATH}/by_ticket/{ticket_id}"));
27        self.client.send_json(req).await
28    }
29
30    /// `GET /api/v1/ticket_articles/:id`.
31    pub async fn get(&self, id: u64) -> Result<Article> {
32        let req = self.client.request(Method::GET, &format!("{PATH}/{id}"));
33        self.client.send_json(req).await
34    }
35
36    /// `POST /api/v1/ticket_articles` - add an article (reply, note, ...) to
37    /// a ticket via the returned builder.
38    pub fn create(&self, ticket_id: u64) -> CreateArticle<'a> {
39        CreateArticle {
40            client: self.client,
41            ticket_id,
42            article: NewArticle::default(),
43        }
44    }
45
46    /// `PUT /api/v1/ticket_articles/:id` - accepts any [`Serialize`] patch.
47    pub async fn update<P: Serialize + ?Sized>(&self, id: u64, patch: &P) -> Result<Article> {
48        let req = self
49            .client
50            .request(Method::PUT, &format!("{PATH}/{id}"))
51            .json(patch);
52        self.client.send_json(req).await
53    }
54
55    /// `DELETE /api/v1/ticket_articles/:id`.
56    pub async fn delete(&self, id: u64) -> Result<()> {
57        let req = self.client.request(Method::DELETE, &format!("{PATH}/{id}"));
58        self.client.send_unit(req).await
59    }
60
61    /// Download an attachment's raw bytes.
62    ///
63    /// `GET /api/v1/ticket_attachment/:ticket_id/:article_id/:attachment_id`.
64    pub async fn download_attachment(
65        &self,
66        ticket_id: u64,
67        article_id: u64,
68        attachment_id: u64,
69    ) -> Result<bytes::Bytes> {
70        let req = self.client.request(
71            Method::GET,
72            &format!("api/v1/ticket_attachment/{ticket_id}/{article_id}/{attachment_id}"),
73        );
74        self.client.send_bytes(req).await
75    }
76}
77
78/// Builder for `POST /api/v1/ticket_articles`.
79#[derive(Debug)]
80pub struct CreateArticle<'a> {
81    client: &'a Client,
82    ticket_id: u64,
83    article: NewArticle,
84}
85
86impl<'a> CreateArticle<'a> {
87    /// Replace the underlying article payload outright.
88    pub fn article(mut self, a: NewArticle) -> Self {
89        self.article = a;
90        self
91    }
92    /// Set the article body.
93    pub fn body(mut self, s: impl Into<String>) -> Self {
94        self.article.body = s.into();
95        self
96    }
97    /// Set the article subject line.
98    pub fn subject(mut self, s: impl Into<String>) -> Self {
99        self.article.subject = Some(s.into());
100        self
101    }
102    /// Set the article type (`note`, `email`, `phone`, ...).
103    pub fn article_type(mut self, s: impl Into<String>) -> Self {
104        self.article.article_type = Some(s.into());
105        self
106    }
107    /// Mark the article as internal (hidden from customers).
108    pub fn internal(mut self, b: bool) -> Self {
109        self.article.internal = Some(b);
110        self
111    }
112    /// Set the MIME content type (`text/plain` or `text/html`).
113    pub fn content_type(mut self, s: impl Into<String>) -> Self {
114        self.article.content_type = Some(s.into());
115        self
116    }
117    /// Override the sender role (`Agent`, `Customer`, `System`).
118    pub fn sender(mut self, s: impl Into<String>) -> Self {
119        self.article.sender = Some(s.into());
120        self
121    }
122    /// Set the From address.
123    pub fn from(mut self, s: impl Into<String>) -> Self {
124        self.article.from = Some(s.into());
125        self
126    }
127    /// Set the To address.
128    pub fn to(mut self, s: impl Into<String>) -> Self {
129        self.article.to = Some(s.into());
130        self
131    }
132    /// Set the CC addresses.
133    pub fn cc(mut self, s: impl Into<String>) -> Self {
134        self.article.cc = Some(s.into());
135        self
136    }
137
138    /// Submit the request.
139    pub async fn send(mut self) -> Result<Article> {
140        self.article.ticket_id = Some(self.ticket_id);
141        let req = self.client.request(Method::POST, PATH).json(&self.article);
142        self.client.send_json(req).await
143    }
144}