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, anyhow};
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 payload = [("post[raw]", raw)];
44        let response = self
45            .put(&format!("/posts/{}.json", post_id))?
46            .form(&payload)
47            .send()
48            .context("updating post")?;
49        if !response.status().is_success() {
50            return Err(anyhow!("update post failed with {}", response.status()));
51        }
52        Ok(())
53    }
54
55    /// Create a new topic in a category.
56    pub fn create_topic(&self, category_id: u64, title: &str, raw: &str) -> Result<u64> {
57        let payload = [
58            ("title", title),
59            ("raw", raw),
60            ("category", &category_id.to_string()),
61        ];
62        let response = self
63            .post("/posts.json")?
64            .form(&payload)
65            .send()
66            .context("creating topic")?;
67        let status = response.status();
68        let text = response.text().context("reading create response body")?;
69        if !status.is_success() {
70            return Err(http_error("create topic request", status, &text));
71        }
72        let body: CreatePostResponse =
73            serde_json::from_str(&text).context("parsing create topic response")?;
74        Ok(body.topic_id)
75    }
76
77    /// Create a reply post in a topic.
78    pub fn create_post(&self, topic_id: u64, raw: &str) -> Result<u64> {
79        let payload = [("topic_id", topic_id.to_string()), ("raw", raw.to_string())];
80        let response = self
81            .post("/posts.json")?
82            .form(&payload)
83            .send()
84            .context("creating post")?;
85        let status = response.status();
86        let text = response.text().context("reading create response body")?;
87        if !status.is_success() {
88            return Err(http_error("create post request", status, &text));
89        }
90        let body: CreatePostResponse =
91            serde_json::from_str(&text).context("parsing create post response")?;
92        Ok(body.id)
93    }
94}