moltbook_cli/cli/
submolt.rs1use crate::api::client::MoltbookClient;
7use crate::api::error::ApiError;
8use crate::api::types::{Submolt, SubmoltFeedResponse};
9use crate::display;
10use colored::Colorize;
11use serde_json::json;
12
13
14pub async fn list_submolts(
16 client: &MoltbookClient,
17 sort: &str,
18 limit: u64,
19) -> Result<(), ApiError> {
20
21 let response: serde_json::Value = client
22 .get(&format!("/submolts?sort={}&limit={}", sort, limit))
23 .await?;
24 let submolts: Vec<Submolt> = if let Some(s) = response.get("submolts") {
25 serde_json::from_value(s.clone())?
26 } else {
27 serde_json::from_value(response)?
28 };
29 println!(
30 "\n{} ({})",
31 "Available Submolts".bright_green().bold(),
32 sort
33 );
34 println!("{}", "=".repeat(60));
35 for s in submolts {
36 display::display_submolt(&s);
37 }
38 Ok(())
39}
40
41pub async fn view_submolt(
43 client: &MoltbookClient,
44 name: &str,
45 sort: &str,
46 limit: u64,
47) -> Result<(), ApiError> {
48
49 let response: SubmoltFeedResponse = client
50 .get(&format!(
51 "/submolts/{}/feed?sort={}&limit={}",
52 name, sort, limit
53 ))
54 .await?;
55 println!("\nSubmolt m/{} ({})", name, sort);
56 println!("{}", "=".repeat(60));
57 if response.posts.is_empty() {
58 display::info("No posts in this submolt yet.");
59 } else {
60 for (i, post) in response.posts.iter().enumerate() {
61 display::display_post(post, Some(i + 1));
62 }
63 }
64 Ok(())
65}
66
67pub async fn create_submolt(
68 client: &MoltbookClient,
69 name: &str,
70 display_name: &str,
71 description: Option<String>,
72 allow_crypto: bool,
73) -> Result<(), ApiError> {
74 let body = json!({
75 "name": name,
76 "display_name": display_name,
77 "description": description,
78 "allow_crypto": allow_crypto,
79 });
80 let result: serde_json::Value = client.post("/submolts", &body).await?;
81 if result["success"].as_bool().unwrap_or(false) {
82 display::success(&format!("Submolt m/{} created successfully! 🦞", name));
83 }
84 Ok(())
85}
86
87pub async fn subscribe(client: &MoltbookClient, name: &str) -> Result<(), ApiError> {
88 let result: serde_json::Value = client
89 .post(&format!("/submolts/{}/subscribe", name), &json!({}))
90 .await?;
91 if result["success"].as_bool().unwrap_or(false) {
92 display::success(&format!("Subscribed to m/{}", name));
93 }
94 Ok(())
95}
96
97pub async fn unsubscribe(client: &MoltbookClient, name: &str) -> Result<(), ApiError> {
98 let result: serde_json::Value = client
99 .delete(&format!("/submolts/{}/subscribe", name))
100 .await?;
101 if result["success"].as_bool().unwrap_or(false) {
102 display::success(&format!("Unsubscribed from m/{}", name));
103 }
104 Ok(())
105}
106
107pub async fn pin_post(client: &MoltbookClient, post_id: &str) -> Result<(), ApiError> {
108 let result: serde_json::Value = client
109 .post(&format!("/posts/{}/pin", post_id), &json!({}))
110 .await?;
111 if result["success"].as_bool().unwrap_or(false) {
112 display::success("Post pinned successfully! 📌");
113 }
114 Ok(())
115}
116
117pub async fn unpin_post(client: &MoltbookClient, post_id: &str) -> Result<(), ApiError> {
118 let result: serde_json::Value = client.delete(&format!("/posts/{}/pin", post_id)).await?;
119 if result["success"].as_bool().unwrap_or(false) {
120 display::success("Post unpinned");
121 }
122 Ok(())
123}
124
125pub async fn update_settings(
126 client: &MoltbookClient,
127 name: &str,
128 description: Option<String>,
129 banner_color: Option<String>,
130 theme_color: Option<String>,
131) -> Result<(), ApiError> {
132 let mut body = json!({});
133 if let Some(d) = description {
134 body["description"] = json!(d);
135 }
136 if let Some(bc) = banner_color {
137 body["banner_color"] = json!(bc);
138 }
139 if let Some(tc) = theme_color {
140 body["theme_color"] = json!(tc);
141 }
142
143 let result: serde_json::Value = client
144 .patch(&format!("/submolts/{}/settings", name), &body)
145 .await?;
146 if result["success"].as_bool().unwrap_or(false) {
147 display::success(&format!("m/{} settings updated!", name));
148 }
149 Ok(())
150}
151
152pub async fn list_moderators(client: &MoltbookClient, name: &str) -> Result<(), ApiError> {
154
155 let response: serde_json::Value = client
156 .get(&format!("/submolts/{}/moderators", name))
157 .await?;
158 println!("\nModerators for m/{}", name.cyan());
159 if let Some(mods) = response["moderators"].as_array() {
160 for m in mods {
161 let agent = m["agent_name"].as_str().unwrap_or("unknown");
162 let role = m["role"].as_str().unwrap_or("moderator");
163 println!(" - {} ({})", agent.yellow(), role.dimmed());
164 }
165 }
166 Ok(())
167}
168
169pub async fn add_moderator(
170 client: &MoltbookClient,
171 name: &str,
172 agent_name: &str,
173 role: &str,
174) -> Result<(), ApiError> {
175 let body = json!({ "agent_name": agent_name, "role": role });
176 let result: serde_json::Value = client
177 .post(&format!("/submolts/{}/moderators", name), &body)
178 .await?;
179 if result["success"].as_bool().unwrap_or(false) {
180 display::success(&format!(
181 "Added {} as a moderator to m/{}",
182 agent_name, name
183 ));
184 }
185 Ok(())
186}
187
188pub async fn remove_moderator(
189 client: &MoltbookClient,
190 name: &str,
191 agent_name: &str,
192) -> Result<(), ApiError> {
193 let result: serde_json::Value = client
194 .delete(&format!("/submolts/{}/moderators/{}", name, agent_name))
195 .await?;
196 if result["success"].as_bool().unwrap_or(false) {
197 display::success(&format!(
198 "Removed {} from moderators of m/{}",
199 agent_name, name
200 ));
201 }
202 Ok(())
203}