bunny_api/
support.rs

1//! Types and API functions related to the Support APIs.
2
3use crate::{Client, APIResult, user::User, error::error_from_response, NoSpecificError};
4
5use reqwest::Method;
6use serde::{Deserialize, Serialize};
7
8/// Information about a support ticket.
9#[derive(Debug, Clone, Deserialize, Serialize)]
10#[serde(rename_all = "PascalCase")]
11pub struct Ticket {
12    /// The ticket id.
13    pub id: i64,
14    /// The current status of the ticket.
15    pub status: Option<String>,
16    /// The subject line of the ticket.
17    pub subject: Option<String>,
18    /// A list of comments on the ticket.
19    #[serde(default)]
20    pub comments: Vec<TicketComment>,
21}
22
23/// Information about a comment on a support ticket.
24#[derive(Debug, Clone, Deserialize, Serialize)]
25#[serde(rename_all = "PascalCase")]
26pub struct TicketComment {
27    /// The comment id.
28    id: i64,
29    /// The type of comment.
30    #[serde(rename = "type")]
31    typ: Option<String>,
32    /// The body of the comment as plain text.
33    body: Option<String>,
34    /// The body of the comment as HTML.
35    html_body: String,
36    /// Whether the comment is publicly visible.
37    public: bool,
38    /// The user id of the commenter.
39    author_id: i64,
40    /// When the comment was submitted.
41    created_at: time::OffsetDateTime,
42    /// The [`User`] that submitted the comment.
43    user: User,
44}
45
46/// The response returned by the [`list_tickets`] endpoint.
47#[derive(Debug, Clone, Deserialize, Serialize)]
48#[serde(rename_all = "PascalCase")]
49pub struct ListTickets {
50    /// All of the tickets on this page.
51    pub items: Vec<Ticket>,
52    /// Which page was returned, starting at 1.
53    pub current_page: i32,
54    total_items: i32,
55    /// Whether there are more tickets after this.
56    pub has_more_items: bool,
57}
58
59async fn inner_list_tickets(client: &Client, page: i32, per_page: i32) -> APIResult<ListTickets, NoSpecificError> {
60    let url = format!("{}/support/ticket/list?page={}&perPage={}", crate::API_BASE_URL, page, per_page);
61
62    let req = client
63        .get(&url)
64        .header("accept", "application/json")
65        .build()
66        .map_err(crate::Error::map_request_err(
67            Method::GET,
68            url.clone(),
69        ))?;
70
71    let resp = client
72        .send_logged(req)
73        .await
74        .map_err(crate::Error::map_request_err(
75            Method::GET,
76            url.clone(),
77        ))?;
78
79    let resp = error_from_response(resp)
80        .await
81        .map_err(crate::Error::map_response_err(
82            Method::GET,
83            url.clone(),
84        ))?;
85
86    resp.json()
87        .await
88        .map_err(crate::Error::map_json_err(
89            Method::GET,
90            url.clone(),
91        ))
92}
93
94/// List the tickets on a given `page`, with the given amount `per_page`.
95///
96/// # Defaults
97///
98/// - `page`: 1
99/// - `per_page`: 5 (the minimum)
100///
101/// # Errors
102///
103/// Any error that occurs during the API call.
104pub async fn list_tickets(client: &Client, page: Option<i32>, per_page: Option<i32>) -> APIResult<ListTickets, NoSpecificError> {
105    let page = page.unwrap_or(1);
106    let per_page = per_page.unwrap_or(5);
107    inner_list_tickets(client, page, per_page).await
108}
109
110/// List all tickets for the authenticated user.
111///
112/// Internally, this calls [`list_tickets`] repeatedly until there are no more tickets returned.
113///
114/// # Errors
115///
116/// See [`list_tickets`].
117pub async fn list_all_tickets(client: &Client) -> APIResult<Vec<Ticket>, NoSpecificError> {
118    let mut page = 1;
119    let per_page = 100;
120    let mut tickets = Vec::new();
121
122    loop {
123        let resp = inner_list_tickets(client, page, per_page).await?;
124        let ListTickets { items, has_more_items, .. } = resp;
125        tickets.extend(items);
126
127        if has_more_items {
128            page += 1;
129        } else {
130            break;
131        }
132    }
133
134    Ok(tickets)
135}