roblox_api/api/inventory/
v1.rs1use serde::{Deserialize, Serialize};
2
3use crate::{AssetTypeId, Error, Paging, client::Client};
4
5pub const URL: &str = "https://inventory.roblox.com/v1";
6
7#[repr(u8)]
8#[derive(Clone, Debug, Deserialize, Serialize)]
9pub enum ItemType {
10 Asset = 0,
11 Gamepass,
12 Badge,
13 Bundle,
14}
15
16#[derive(Clone, Debug, Deserialize)]
17pub struct AssetInfo {
18 pub id: u64,
19 #[serde(rename = "type")]
20 pub kind: String,
21 pub name: String,
22 #[serde(rename = "instanceId")]
23 pub instance_id: u64,
24}
25
26#[derive(Clone, Debug, Deserialize)]
27pub struct UserOwnedAssets {
28 #[serde(rename = "nextPageCursor")]
29 pub next_cursor: Option<String>,
30 #[serde(rename = "previousPageCursor")]
31 pub previous_cursor: Option<String>,
32 #[serde(rename = "data")]
33 pub assets: Vec<AssetInfo>,
34}
35
36#[derive(Clone, Debug, Deserialize)]
37pub struct CollectibleInfo {
38 #[serde(rename = "assetId")]
39 pub id: u64,
40 #[serde(rename = "originalPrice")]
41 pub original_price: u64,
42 #[serde(rename = "recentAveragePrice")]
43 pub recent_average_price: u64,
44 #[serde(rename = "assetStock")]
45 pub stock: u64,
46 #[serde(rename = "userAssetId")]
47 pub instance_id: u64,
48 pub name: String,
49 #[serde(rename = "buildersClubMembershipType")]
50 pub premium_membership_type: String,
51 #[serde(rename = "isOnHold")]
52 pub on_hold: bool,
53 #[serde(rename = "serialNumber")]
54 pub serial: Option<u64>,
55}
56
57#[derive(Clone, Debug, Deserialize)]
58pub struct UserOwnedCollectibles {
59 #[serde(rename = "nextPageCursor")]
60 pub next_cursor: Option<String>,
61 #[serde(rename = "previousPageCursor")]
62 pub previous_cursor: Option<String>,
63 #[serde(rename = "data")]
64 pub assets: Vec<CollectibleInfo>,
65}
66
67pub async fn can_view_inventory(client: &mut Client, user_id: u64) -> Result<bool, Error> {
68 let result = client
69 .requestor
70 .client
71 .get(format!("{URL}/users/{user_id}/can-view-inventory"))
72 .headers(client.requestor.default_headers.clone())
73 .send()
74 .await;
75
76 #[derive(Clone, Debug, Deserialize)]
77 struct Response {
78 #[serde(rename = "canView")]
79 can_view: bool,
80 }
81
82 let response = client.validate_response(result).await?;
83 Ok(client
84 .requestor
85 .parse_json::<Response>(response)
86 .await?
87 .can_view)
88}
89
90pub async fn user_owned_assets(
91 client: &mut Client,
92 user_id: u64,
93 id: u64,
94 item_type: ItemType,
95 paging: Paging<'_>,
96) -> Result<UserOwnedAssets, Error> {
97 let item_type = item_type as u8;
98
99 let cursor = match paging.cursor {
100 Some(cursor) => cursor.to_string(),
101 None => String::new(),
102 };
103
104 let result = client
105 .requestor
106 .client
107 .get(format!("{URL}/users/{user_id}/items/{item_type}/{id}"))
108 .query(&[("cursor", cursor)])
109 .headers(client.requestor.default_headers.clone())
110 .send()
111 .await;
112
113 let response = client.validate_response(result).await?;
114 client
115 .requestor
116 .parse_json::<UserOwnedAssets>(response)
117 .await
118}
119
120pub async fn user_owned_collectibles(
121 client: &mut Client,
122 user_id: u64,
123 asset_type_id: Option<AssetTypeId>,
124 paging: Paging<'_>,
125) -> Result<UserOwnedCollectibles, Error> {
126 let limit = paging.limit.unwrap_or(10).to_string();
127 let sort_order = paging.order.unwrap_or_default().to_string();
128 let cursor = match paging.cursor {
129 Some(cursor) => cursor.to_string(),
130 None => String::new(),
131 };
132
133 let asset_type = match asset_type_id {
134 Some(id) => {
135 let id = id as u8;
136 id.to_string()
137 }
138 None => String::new(),
139 };
140
141 let result = client
142 .requestor
143 .client
144 .get(format!("{URL}/users/{user_id}/assets/collectibles"))
145 .query(&[
146 ("assetType", asset_type),
147 ("limit", limit),
148 ("sortOrder", sort_order),
149 ("cursor", cursor),
150 ])
151 .headers(client.requestor.default_headers.clone())
152 .send()
153 .await;
154
155 let response = client.validate_response(result).await?;
156 client
157 .requestor
158 .parse_json::<UserOwnedCollectibles>(response)
159 .await
160}