1use reqwest::Method;
9use serde::de::{self, Deserializer};
10use serde::{Deserialize, Serialize};
11
12use crate::client::Client;
13use crate::error::BoxxkiteError;
14use crate::sandboxes::UsageSummary;
15
16#[derive(Debug, Clone, Deserialize)]
18pub struct Account {
19 pub id: String,
20 pub email: String,
21 pub created_at: String,
22}
23
24#[derive(Debug, Clone, Deserialize)]
27pub struct MessageResponse {
28 pub message: String,
29}
30
31#[derive(Debug, Clone, Deserialize)]
34pub struct TokenPair {
35 pub access_token: String,
36 pub token_type: String,
37 pub expires_in: i64,
38 pub refresh_token: Option<String>,
39 pub account: Account,
40}
41
42#[derive(Debug, Clone, Serialize)]
52pub struct AllowedCommandRule {
53 pub command: String,
54 #[serde(default, skip_serializing_if = "Vec::is_empty")]
55 pub args_allow: Vec<String>,
56 #[serde(default, skip_serializing_if = "Vec::is_empty")]
57 pub args_deny: Vec<String>,
58}
59
60impl AllowedCommandRule {
61 pub fn new(command: impl Into<String>) -> Self {
63 Self {
64 command: command.into(),
65 args_allow: Vec::new(),
66 args_deny: Vec::new(),
67 }
68 }
69
70 pub fn args_allow<I, S>(mut self, patterns: I) -> Self
71 where
72 I: IntoIterator<Item = S>,
73 S: Into<String>,
74 {
75 self.args_allow = patterns.into_iter().map(Into::into).collect();
76 self
77 }
78
79 pub fn args_deny<I, S>(mut self, patterns: I) -> Self
80 where
81 I: IntoIterator<Item = S>,
82 S: Into<String>,
83 {
84 self.args_deny = patterns.into_iter().map(Into::into).collect();
85 self
86 }
87}
88
89impl<'de> Deserialize<'de> for AllowedCommandRule {
90 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91 where
92 D: Deserializer<'de>,
93 {
94 #[derive(Deserialize)]
95 #[serde(untagged)]
96 enum Raw {
97 Bare(String),
98 Full {
99 command: String,
100 #[serde(default)]
101 args_allow: Vec<String>,
102 #[serde(default)]
103 args_deny: Vec<String>,
104 },
105 }
106 match Raw::deserialize(deserializer).map_err(de::Error::custom)? {
107 Raw::Bare(command) => Ok(Self::new(command)),
108 Raw::Full {
109 command,
110 args_allow,
111 args_deny,
112 } => Ok(Self {
113 command,
114 args_allow,
115 args_deny,
116 }),
117 }
118 }
119}
120
121#[derive(Debug, Clone, Default, Deserialize, Serialize)]
125pub struct AllowedCommandsResponse {
126 #[serde(default)]
127 pub rules: Vec<AllowedCommandRule>,
128}
129
130impl Client {
131 pub async fn account(&self) -> Result<Account, BoxxkiteError> {
133 let builder = self.request(Method::GET, "/v1/account");
134 self.send(builder).await
135 }
136
137 pub async fn usage(&self) -> Result<UsageSummary, BoxxkiteError> {
140 let builder = self.request(Method::GET, "/v1/usage");
141 self.send(builder).await
142 }
143
144 pub async fn request_password_reset(
150 &self,
151 email: &str,
152 ) -> Result<MessageResponse, BoxxkiteError> {
153 #[derive(Serialize)]
154 struct Body<'a> {
155 email: &'a str,
156 }
157 let builder = self
158 .request(Method::POST, "/v1/auth/password-reset/request")
159 .json(&Body { email });
160 self.send(builder).await
161 }
162
163 pub async fn confirm_password_reset(
168 &self,
169 token: &str,
170 new_password: &str,
171 ) -> Result<MessageResponse, BoxxkiteError> {
172 #[derive(Serialize)]
173 struct Body<'a> {
174 token: &'a str,
175 new_password: &'a str,
176 }
177 let builder = self
178 .request(Method::POST, "/v1/auth/password-reset/confirm")
179 .json(&Body {
180 token,
181 new_password,
182 });
183 self.send(builder).await
184 }
185
186 pub async fn verify_email(&self, token: &str) -> Result<MessageResponse, BoxxkiteError> {
189 #[derive(Serialize)]
190 struct Body<'a> {
191 token: &'a str,
192 }
193 let builder = self
194 .request(Method::POST, "/v1/auth/verify-email")
195 .json(&Body { token });
196 self.send(builder).await
197 }
198
199 pub async fn resend_verification(
206 &self,
207 access_token: &str,
208 ) -> Result<MessageResponse, BoxxkiteError> {
209 let builder =
210 self.request_with_auth(Method::POST, "/v1/auth/resend-verification", access_token);
211 self.send(builder).await
212 }
213
214 pub async fn refresh_token(&self, refresh_token: &str) -> Result<TokenPair, BoxxkiteError> {
220 #[derive(Serialize)]
221 struct Body<'a> {
222 refresh_token: &'a str,
223 }
224 let builder = self
225 .request(Method::POST, "/v1/auth/refresh")
226 .json(&Body { refresh_token });
227 self.send(builder).await
228 }
229
230 pub async fn logout(&self, refresh_token: &str) -> Result<(), BoxxkiteError> {
234 #[derive(Serialize)]
235 struct Body<'a> {
236 refresh_token: &'a str,
237 }
238 let builder = self
239 .request(Method::POST, "/v1/auth/logout")
240 .json(&Body { refresh_token });
241 self.send_no_content(builder).await
242 }
243
244 pub async fn get_allowed_commands(&self) -> Result<AllowedCommandsResponse, BoxxkiteError> {
248 let builder = self.request(Method::GET, "/v1/account/allowed-commands");
249 self.send(builder).await
250 }
251
252 pub async fn set_allowed_commands(
256 &self,
257 rules: Vec<AllowedCommandRule>,
258 ) -> Result<AllowedCommandsResponse, BoxxkiteError> {
259 let body = AllowedCommandsResponse { rules };
260 let builder = self
261 .request(Method::PUT, "/v1/account/allowed-commands")
262 .json(&body);
263 self.send(builder).await
264 }
265
266 pub async fn clear_allowed_commands(&self) -> Result<(), BoxxkiteError> {
269 let builder = self.request(Method::DELETE, "/v1/account/allowed-commands");
270 self.send_no_content(builder).await
271 }
272}