bybit_rust_api/rest/user/
user_client.rs1use crate::rest::client::{RestClient, SecType, ServerResponse};
2use anyhow::Result;
3use serde_json::json;
4
5pub struct UserClient {
6 client: RestClient,
7}
8
9impl UserClient {
10 pub fn new(client: RestClient) -> Self {
11 UserClient { client }
12 }
13
14 pub async fn create_sub_member(
19 &self,
20 username: &str,
21 member_type: i32, password: Option<&str>,
23 note: Option<&str>,
24 switch_option: Option<i32>,
25 is_uta: Option<bool>,
26 ) -> Result<ServerResponse<serde_json::Value>> {
27 let endpoint = "v5/user/create-sub-member";
28 let mut body = json!({
29 "username": username,
30 "memberType": member_type,
31 });
32
33 if let Some(password) = password {
34 body["password"] = json!(password);
35 }
36 if let Some(note) = note {
37 body["note"] = json!(note);
38 }
39 if let Some(switch_option) = switch_option {
40 body["switch"] = json!(switch_option);
41 }
42 if let Some(is_uta) = is_uta {
43 body["isUta"] = json!(is_uta);
44 }
45
46 let response = self.client.post(endpoint, body, SecType::Signed).await?;
47 Ok(response)
48 }
49
50 pub async fn create_sub_api(
55 &self,
56 sub_uid: i64,
57 note: Option<&str>,
58 read_only: i32,
59 permissions: serde_json::Value,
60 ips: Option<Vec<String>>,
61 ) -> Result<ServerResponse<serde_json::Value>> {
62 let endpoint = "v5/user/create-sub-api";
63 let mut body = json!({
64 "subuid": sub_uid,
65 "readOnly": read_only,
66 "permissions": permissions,
67 });
68
69 if let Some(note) = note {
70 body["note"] = json!(note);
71 }
72 if let Some(ips) = ips {
73 body["ips"] = json!(ips);
74 }
75
76 let response = self.client.post(endpoint, body, SecType::Signed).await?;
77 Ok(response)
78 }
79
80 pub async fn query_sub_members(
85 &self,
86 page_size: Option<i32>,
87 page: Option<i32>,
88 ) -> Result<ServerResponse<serde_json::Value>> {
89 let endpoint = "v5/user/query-sub-members";
90 let mut params = json!({});
91
92 if let Some(page_size) = page_size {
93 params["pageSize"] = json!(page_size);
94 }
95 if let Some(page) = page {
96 params["page"] = json!(page);
97 }
98
99 let response = self.client.get(endpoint, params, SecType::Signed).await?;
100 Ok(response)
101 }
102
103 pub async fn get_sub_members(
108 &self,
109 uid: Option<&str>,
110 ) -> Result<ServerResponse<serde_json::Value>> {
111 let endpoint = "v5/user/submembers";
112 let mut params = json!({});
113
114 if let Some(uid) = uid {
115 params["uid"] = json!(uid);
116 }
117
118 let response = self.client.get(endpoint, params, SecType::Signed).await?;
119 Ok(response)
120 }
121
122 pub async fn query_api(&self) -> Result<ServerResponse<serde_json::Value>> {
127 let endpoint = "v5/user/query-api";
128 let response = self
129 .client
130 .get(endpoint, json!({}), SecType::Signed)
131 .await?;
132 Ok(response)
133 }
134
135 pub async fn get_sub_api_keys(
140 &self,
141 sub_member_id: &str,
142 limit: Option<i32>,
143 cursor: Option<&str>,
144 ) -> Result<ServerResponse<serde_json::Value>> {
145 let endpoint = "v5/user/sub-apikeys";
146 let mut params = json!({
147 "subMemberId": sub_member_id,
148 });
149
150 if let Some(limit) = limit {
151 params["limit"] = json!(limit);
152 }
153 if let Some(cursor) = cursor {
154 params["cursor"] = json!(cursor);
155 }
156
157 let response = self.client.get(endpoint, params, SecType::Signed).await?;
158 Ok(response)
159 }
160
161 pub async fn get_member_type(&self) -> Result<ServerResponse<serde_json::Value>> {
166 let endpoint = "v5/user/get-member-type";
167 let response = self
168 .client
169 .get(endpoint, json!({}), SecType::Signed)
170 .await?;
171 Ok(response)
172 }
173
174 pub async fn get_affiliate_customer_info(
179 &self,
180 uid: &str,
181 ) -> Result<ServerResponse<serde_json::Value>> {
182 let endpoint = "v5/user/aff-customer-info";
183 let params = json!({
184 "uid": uid,
185 });
186
187 let response = self.client.get(endpoint, params, SecType::Signed).await?;
188 Ok(response)
189 }
190
191 pub async fn freeze_sub_member(
196 &self,
197 sub_uid: i64,
198 frozen: i32, ) -> Result<ServerResponse<serde_json::Value>> {
200 let endpoint = "v5/user/frozen-sub-member";
201 let body = json!({
202 "subuid": sub_uid,
203 "frozen": frozen,
204 });
205
206 let response = self.client.post(endpoint, body, SecType::Signed).await?;
207 Ok(response)
208 }
209
210 pub async fn delete_sub_member(
215 &self,
216 sub_member_id: &str,
217 ) -> Result<ServerResponse<serde_json::Value>> {
218 let endpoint = "v5/user/del-submember";
219 let body = json!({
220 "subMemberId": sub_member_id,
221 });
222
223 let response = self.client.post(endpoint, body, SecType::Signed).await?;
224 Ok(response)
225 }
226
227 pub async fn update_api(
232 &self,
233 read_only: Option<i32>,
234 ips: Option<Vec<String>>,
235 permissions: Option<serde_json::Value>,
236 ) -> Result<ServerResponse<serde_json::Value>> {
237 let endpoint = "v5/user/update-api";
238 let mut body = json!({});
239
240 if let Some(read_only) = read_only {
241 body["readOnly"] = json!(read_only);
242 }
243 if let Some(ips) = ips {
244 body["ips"] = json!(ips);
245 }
246 if let Some(permissions) = permissions {
247 body["permissions"] = json!(permissions);
248 }
249
250 let response = self.client.post(endpoint, body, SecType::Signed).await?;
251 Ok(response)
252 }
253
254 pub async fn delete_api(&self) -> Result<ServerResponse<serde_json::Value>> {
259 let endpoint = "v5/user/delete-api";
260 let body = json!({});
261
262 let response = self.client.post(endpoint, body, SecType::Signed).await?;
263 Ok(response)
264 }
265
266 pub async fn update_sub_api(
271 &self,
272 api_key: &str,
273 read_only: Option<i32>,
274 ips: Option<Vec<String>>,
275 permissions: Option<serde_json::Value>,
276 ) -> Result<ServerResponse<serde_json::Value>> {
277 let endpoint = "v5/user/update-sub-api";
278 let mut body = json!({
279 "apikey": api_key,
280 });
281
282 if let Some(read_only) = read_only {
283 body["readOnly"] = json!(read_only);
284 }
285 if let Some(ips) = ips {
286 body["ips"] = json!(ips);
287 }
288 if let Some(permissions) = permissions {
289 body["permissions"] = json!(permissions);
290 }
291
292 let response = self.client.post(endpoint, body, SecType::Signed).await?;
293 Ok(response)
294 }
295
296 pub async fn delete_sub_api(&self, api_key: &str) -> Result<ServerResponse<serde_json::Value>> {
301 let endpoint = "v5/user/delete-sub-api";
302 let body = json!({
303 "apikey": api_key,
304 });
305
306 let response = self.client.post(endpoint, body, SecType::Signed).await?;
307 Ok(response)
308 }
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314 use crate::rest::ApiKeyPair;
315
316 fn create_test_client() -> UserClient {
317 let api_key_pair = ApiKeyPair::new(
318 "test".to_string(),
319 "test_key".to_string(),
320 "test_secret".to_string(),
321 );
322 let rest_client = RestClient::new(
323 api_key_pair,
324 "https://api-testnet.bybit.com".to_string(),
325 false,
326 );
327 UserClient::new(rest_client)
328 }
329
330 #[test]
331 fn test_user_client_creation() {
332 let _client = create_test_client();
333 }
334
335 #[tokio::test]
336 async fn test_create_sub_member_params() {
337 let username = "test_sub_user";
338 let member_type = 1;
339 let password = Some("secure_password");
340 let note = Some("Test sub account");
341 let switch_option = Some(1);
342 let is_uta = Some(true);
343
344 assert_eq!(username, "test_sub_user");
345 assert_eq!(member_type, 1);
346 assert_eq!(password, Some("secure_password"));
347 assert_eq!(note, Some("Test sub account"));
348 assert_eq!(switch_option, Some(1));
349 assert_eq!(is_uta, Some(true));
350 }
351
352 #[tokio::test]
353 async fn test_create_sub_api_params() {
354 let sub_uid = 12345678i64;
355 let note = Some("API for trading");
356 let read_only = 0;
357 let permissions = json!({
358 "ContractTrade": ["Order", "Position"],
359 "Spot": ["SpotTrade"]
360 });
361 let ips = Some(vec!["192.168.1.1".to_string(), "10.0.0.1".to_string()]);
362
363 assert_eq!(sub_uid, 12345678);
364 assert_eq!(note, Some("API for trading"));
365 assert_eq!(read_only, 0);
366 assert!(permissions.is_object());
367 assert_eq!(ips.as_ref().unwrap().len(), 2);
368 }
369
370 #[tokio::test]
371 async fn test_freeze_sub_member_params() {
372 let sub_uid = 87654321i64;
373 let frozen_freeze = 1;
374 let frozen_unfreeze = 0;
375
376 assert_eq!(sub_uid, 87654321);
377 assert_eq!(frozen_freeze, 1);
378 assert_eq!(frozen_unfreeze, 0);
379 }
380
381 #[tokio::test]
382 async fn test_query_sub_members_params() {
383 let page_size = Some(20);
384 let page = Some(1);
385
386 assert_eq!(page_size, Some(20));
387 assert_eq!(page, Some(1));
388 }
389
390 #[tokio::test]
391 async fn test_get_sub_api_keys_params() {
392 let sub_member_id = "sub_member_123";
393 let limit = Some(50);
394 let cursor = Some("next_page_cursor");
395
396 assert_eq!(sub_member_id, "sub_member_123");
397 assert_eq!(limit, Some(50));
398 assert_eq!(cursor, Some("next_page_cursor"));
399 }
400
401 #[tokio::test]
402 async fn test_update_api_params() {
403 let read_only = Some(1);
404 let ips = Some(vec!["10.0.0.1".to_string()]);
405 let permissions = Some(json!({
406 "Spot": ["SpotTrade"]
407 }));
408
409 assert_eq!(read_only, Some(1));
410 assert_eq!(ips.as_ref().unwrap().len(), 1);
411 assert!(permissions.as_ref().unwrap().is_object());
412 }
413
414 #[tokio::test]
415 async fn test_delete_sub_api_params() {
416 let api_key = "test_api_key_123";
417
418 assert_eq!(api_key, "test_api_key_123");
419 }
420}