Skip to main content

dsc/api/
topics.rs

1use super::client::DiscourseClient;
2use super::error::http_error;
3use super::models::{CreatePostResponse, TopicResponse};
4use anyhow::{Context, Result};
5use serde_json::Value;
6
7impl DiscourseClient {
8    /// Fetch a topic by ID.
9    pub fn fetch_topic(&self, topic_id: u64, include_raw: bool) -> Result<TopicResponse> {
10        let path = if include_raw {
11            format!("/t/{}.json?include_raw=1", topic_id)
12        } else {
13            format!("/t/{}.json", topic_id)
14        };
15        let response = self.get(&path)?;
16        let status = response.status();
17        let text = response.text().context("reading topic response body")?;
18        if !status.is_success() {
19            return Err(http_error("topic request", status, &text));
20        }
21        let body: TopicResponse = serde_json::from_str(&text).context("parsing topic json")?;
22        Ok(body)
23    }
24
25    /// Fetch a post by ID and return its raw content.
26    pub fn fetch_post_raw(&self, post_id: u64) -> Result<Option<String>> {
27        let path = format!("/posts/{}.json?include_raw=1", post_id);
28        let response = self.get(&path)?;
29        let status = response.status();
30        let text = response.text().context("reading post response body")?;
31        if !status.is_success() {
32            return Err(http_error("post request", status, &text));
33        }
34        let value: Value = serde_json::from_str(&text).context("parsing post response")?;
35        Ok(value
36            .get("raw")
37            .and_then(|raw| raw.as_str())
38            .map(|raw| raw.to_string()))
39    }
40
41    /// Update a post by ID.
42    pub fn update_post(&self, post_id: u64, raw: &str) -> Result<()> {
43        let path = format!("/posts/{}.json", post_id);
44        let payload = [("post[raw]", raw)];
45        let response = self.send_retrying(|| Ok(self.put(&path)?.form(&payload)))?;
46        let status = response.status();
47        if !status.is_success() {
48            let text = response
49                .text()
50                .unwrap_or_else(|_| "<failed to read response body>".to_string());
51            return Err(http_error("update post request", status, &text));
52        }
53        Ok(())
54    }
55
56    /// Create a new topic in a category.
57    pub fn create_topic(&self, category_id: u64, title: &str, raw: &str) -> Result<u64> {
58        let category = category_id.to_string();
59        let payload = [("title", title), ("raw", raw), ("category", &category)];
60        let response = self.send_retrying(|| Ok(self.post("/posts.json")?.form(&payload)))?;
61        let status = response.status();
62        let text = response.text().context("reading create response body")?;
63        if !status.is_success() {
64            return Err(http_error("create topic request", status, &text));
65        }
66        let body: CreatePostResponse =
67            serde_json::from_str(&text).context("parsing create topic response")?;
68        Ok(body.topic_id)
69    }
70
71    /// Create a reply post in a topic.
72    pub fn create_post(&self, topic_id: u64, raw: &str) -> Result<u64> {
73        let topic = topic_id.to_string();
74        let payload = [("topic_id", topic.as_str()), ("raw", raw)];
75        let response = self.send_retrying(|| Ok(self.post("/posts.json")?.form(&payload)))?;
76        let status = response.status();
77        let text = response.text().context("reading create response body")?;
78        if !status.is_success() {
79            return Err(http_error("create post request", status, &text));
80        }
81        let body: CreatePostResponse =
82            serde_json::from_str(&text).context("parsing create post response")?;
83        Ok(body.id)
84    }
85}