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)]
9pub struct ApiKeySummary {
10 pub id: u64,
11 #[serde(default)]
12 pub description: Option<String>,
13 #[serde(default, alias = "user_username")]
14 pub username: Option<String>,
15 #[serde(default)]
16 pub last_used_at: Option<String>,
17 #[serde(default)]
18 pub created_at: Option<String>,
19 #[serde(default)]
20 pub revoked_at: Option<String>,
21 #[serde(default)]
22 pub truncated_key: Option<String>,
23}
24
25#[derive(Debug, Deserialize, Serialize, Clone)]
27pub struct CreatedApiKey {
28 pub id: u64,
29 pub key: String,
30 #[serde(default)]
31 pub description: Option<String>,
32 #[serde(default, alias = "user_username")]
33 pub username: Option<String>,
34 #[serde(default)]
35 pub created_at: Option<String>,
36}
37
38impl DiscourseClient {
39 pub fn list_api_keys(&self) -> Result<Vec<ApiKeySummary>> {
40 let response = self.get("/admin/api/keys.json")?;
41 let status = response.status();
42 let text = response.text().context("reading api keys response")?;
43 if !status.is_success() {
44 return Err(http_error("api keys list request", status, &text));
45 }
46 let value: Value = serde_json::from_str(&text).context("parsing api keys response json")?;
47 let keys_value = value
48 .get("keys")
49 .cloned()
50 .unwrap_or(Value::Array(Vec::new()));
51 let keys: Vec<ApiKeySummary> =
52 serde_json::from_value(keys_value).context("deserialising api keys")?;
53 Ok(keys)
54 }
55
56 pub fn create_api_key(
58 &self,
59 description: &str,
60 username: Option<&str>,
61 ) -> Result<CreatedApiKey> {
62 let mut payload: Vec<(&str, &str)> = vec![("key[description]", description)];
63 if let Some(u) = username {
64 payload.push(("key[username]", u));
65 }
66 let response =
67 self.send_retrying(|| Ok(self.post("/admin/api/keys.json")?.form(&payload)))?;
68 let status = response.status();
69 let text = response.text().context("reading api key create response")?;
70 if !status.is_success() {
71 return Err(http_error("api key create request", status, &text));
72 }
73 let value: Value =
74 serde_json::from_str(&text).context("parsing api key create response")?;
75 let key_obj = value.get("key").unwrap_or(&value);
76 let created: CreatedApiKey =
77 serde_json::from_value(key_obj.clone()).context("deserialising created api key")?;
78 Ok(created)
79 }
80
81 pub fn revoke_api_key(&self, key_id: u64) -> Result<()> {
82 let path = format!("/admin/api/keys/{}.json", key_id);
83 let response = self.send_retrying(|| self.delete_builder(&path))?;
84 let status = response.status();
85 if !status.is_success() {
86 let text = response
87 .text()
88 .unwrap_or_else(|_| "<failed to read response body>".to_string());
89 return Err(http_error("api key revoke request", status, &text));
90 }
91 Ok(())
92 }
93}