1use super::client::DiscourseClient;
2use super::error::http_error;
3use anyhow::{Context, Result};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7#[derive(Debug, Deserialize, Serialize, Clone)]
8pub struct TagInfo {
9 pub id: String,
10 #[serde(default)]
11 pub text: String,
12 #[serde(default)]
13 pub count: u64,
14 #[serde(default)]
15 pub pm_count: u64,
16}
17
18#[derive(Debug, Deserialize)]
19struct TagsResponse {
20 #[serde(default)]
21 tags: Vec<TagInfo>,
22}
23
24impl DiscourseClient {
25 pub fn list_tags(&self) -> Result<Vec<TagInfo>> {
27 let response = self.get("/tags.json")?;
28 let status = response.status();
29 let text = response.text().context("reading tags response body")?;
30 if !status.is_success() {
31 return Err(http_error("tags request", status, &text));
32 }
33 let body: TagsResponse =
34 serde_json::from_str(&text).context("parsing tags response json")?;
35 Ok(body.tags)
36 }
37
38 pub fn fetch_topic_tags(&self, topic_id: u64) -> Result<Vec<String>> {
40 let path = format!("/t/{}.json", topic_id);
41 let response = self.get(&path)?;
42 let status = response.status();
43 let text = response.text().context("reading topic response body")?;
44 if !status.is_success() {
45 return Err(http_error("topic request", status, &text));
46 }
47 let value: Value = serde_json::from_str(&text).context("parsing topic response json")?;
48 let tags = value
49 .get("tags")
50 .and_then(|v| v.as_array())
51 .map(|arr| {
52 arr.iter()
53 .filter_map(|v| v.as_str().map(|s| s.to_string()))
54 .collect()
55 })
56 .unwrap_or_default();
57 Ok(tags)
58 }
59
60 pub fn set_topic_tags(&self, topic_id: u64, tags: &[String]) -> Result<Vec<String>> {
62 let path = format!("/t/{}.json", topic_id);
63 let payload: Vec<(&str, &str)> = if tags.is_empty() {
64 vec![("tags[]", "")]
67 } else {
68 tags.iter().map(|t| ("tags[]", t.as_str())).collect()
69 };
70 let response = self.send_retrying(|| Ok(self.put(&path)?.form(&payload)))?;
71 let status = response.status();
72 let text = response.text().context("reading set-tags response body")?;
73 if !status.is_success() {
74 return Err(http_error("set tags request", status, &text));
75 }
76 self.fetch_topic_tags(topic_id)
79 }
80}