zammad-api 0.4.0

Async, idiomatic Rust client for the Zammad Service Platform
Documentation
use reqwest::Method;
use serde::Serialize;

use crate::client::Client;
use crate::error::Result;
use crate::models::{Article, NewArticle};

const PATH: &str = "api/v1/ticket_articles";

/// Ticket-article endpoints (replies, notes, emails, ...).
#[derive(Debug)]
pub struct ArticlesApi<'a> {
    client: &'a Client,
}

impl<'a> ArticlesApi<'a> {
    pub(crate) fn new(client: &'a Client) -> Self {
        Self { client }
    }

    /// `GET /api/v1/ticket_articles/by_ticket/:ticket_id` - every article on
    /// the ticket.
    pub async fn by_ticket(&self, ticket_id: u64) -> Result<Vec<Article>> {
        let req = self
            .client
            .request(Method::GET, &format!("{PATH}/by_ticket/{ticket_id}"));
        self.client.send_json(req).await
    }

    /// `GET /api/v1/ticket_articles/:id`.
    pub async fn get(&self, id: u64) -> Result<Article> {
        let req = self.client.request(Method::GET, &format!("{PATH}/{id}"));
        self.client.send_json(req).await
    }

    /// `POST /api/v1/ticket_articles` - add an article (reply, note, ...) to
    /// a ticket via the returned builder.
    pub fn create(&self, ticket_id: u64) -> CreateArticle<'a> {
        CreateArticle {
            client: self.client,
            ticket_id,
            article: NewArticle::default(),
        }
    }

    /// `PUT /api/v1/ticket_articles/:id` - accepts any [`Serialize`] patch.
    pub async fn update<P: Serialize + ?Sized>(&self, id: u64, patch: &P) -> Result<Article> {
        let req = self
            .client
            .request(Method::PUT, &format!("{PATH}/{id}"))
            .json(patch);
        self.client.send_json(req).await
    }

    /// `DELETE /api/v1/ticket_articles/:id`.
    pub async fn delete(&self, id: u64) -> Result<()> {
        let req = self.client.request(Method::DELETE, &format!("{PATH}/{id}"));
        self.client.send_unit(req).await
    }

    /// Download an attachment's raw bytes.
    ///
    /// `GET /api/v1/ticket_attachment/:ticket_id/:article_id/:attachment_id`.
    pub async fn download_attachment(
        &self,
        ticket_id: u64,
        article_id: u64,
        attachment_id: u64,
    ) -> Result<bytes::Bytes> {
        let req = self.client.request(
            Method::GET,
            &format!("api/v1/ticket_attachment/{ticket_id}/{article_id}/{attachment_id}"),
        );
        self.client.send_bytes(req).await
    }
}

/// Builder for `POST /api/v1/ticket_articles`.
#[derive(Debug)]
pub struct CreateArticle<'a> {
    client: &'a Client,
    ticket_id: u64,
    article: NewArticle,
}

impl<'a> CreateArticle<'a> {
    /// Replace the underlying article payload outright.
    pub fn article(mut self, a: NewArticle) -> Self {
        self.article = a;
        self
    }
    /// Set the article body.
    pub fn body(mut self, s: impl Into<String>) -> Self {
        self.article.body = s.into();
        self
    }
    /// Set the article subject line.
    pub fn subject(mut self, s: impl Into<String>) -> Self {
        self.article.subject = Some(s.into());
        self
    }
    /// Set the article type (`note`, `email`, `phone`, ...).
    pub fn article_type(mut self, s: impl Into<String>) -> Self {
        self.article.article_type = Some(s.into());
        self
    }
    /// Mark the article as internal (hidden from customers).
    pub fn internal(mut self, b: bool) -> Self {
        self.article.internal = Some(b);
        self
    }
    /// Set the MIME content type (`text/plain` or `text/html`).
    pub fn content_type(mut self, s: impl Into<String>) -> Self {
        self.article.content_type = Some(s.into());
        self
    }
    /// Override the sender role (`Agent`, `Customer`, `System`).
    pub fn sender(mut self, s: impl Into<String>) -> Self {
        self.article.sender = Some(s.into());
        self
    }
    /// Set the From address.
    pub fn from(mut self, s: impl Into<String>) -> Self {
        self.article.from = Some(s.into());
        self
    }
    /// Set the To address.
    pub fn to(mut self, s: impl Into<String>) -> Self {
        self.article.to = Some(s.into());
        self
    }
    /// Set the CC addresses.
    pub fn cc(mut self, s: impl Into<String>) -> Self {
        self.article.cc = Some(s.into());
        self
    }

    /// Submit the request.
    pub async fn send(mut self) -> Result<Article> {
        self.article.ticket_id = Some(self.ticket_id);
        let req = self.client.request(Method::POST, PATH).json(&self.article);
        self.client.send_json(req).await
    }
}