roblox_api/api/toolbox_service/
v1.rs

1use serde::Deserialize;
2
3use crate::{AssetTypeId, DateTime, Error, Paging, client::Client};
4
5pub const URL: &str = "https://apis.roblox.com/toolbox-service/v1";
6
7#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
8pub struct CreationObject {
9    pub id: u64,
10    pub name: String,
11}
12
13#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
14pub struct Creations {
15    #[serde(rename = "totalResults")]
16    pub results: u16,
17    #[serde(rename = "filteredKeyword")]
18    pub filtered_keyword: String,
19    #[serde(rename = "data")]
20    pub objects: Vec<CreationObject>,
21}
22
23#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
24pub struct ItemDetailAsset {
25    pub id: u64,
26    pub name: String,
27    pub description: String,
28    #[serde(rename = "typeId")]
29    pub type_id: u32,
30    pub duration: u32,
31    #[serde(rename = "visibilityStatus")]
32    pub visibility: u32,
33    #[serde(rename = "isEndorsed")]
34    pub is_endorsed: bool,
35    #[serde(rename = "hasScripts")]
36    pub has_scripts: bool,
37    #[serde(rename = "isAssetHashApproved")]
38    pub is_asset_hash_approved: bool,
39    #[serde(rename = "createdUtc")]
40    pub creation_date: DateTime,
41    #[serde(rename = "updatedUtc")]
42    pub last_updated_date: DateTime,
43    //#[serde(rename = "assetSubTypes")]
44    //pub sub_types: Vec<String?>,
45    //#[serde(rename = "socialLinks")]
46    //pub social_links: Vec<String?>,
47    // pub model_technical_details: ModelTechnicalDetails?
48    #[serde(rename = "assetGenres")]
49    pub genres: Vec<String>,
50}
51
52#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
53pub struct ItemDetailCreator {
54    pub id: u64,
55    pub name: String,
56    #[serde(rename = "type")]
57    pub kind: u64,
58    #[serde(rename = "isVerifiedCreator")]
59    pub is_verified: bool,
60}
61
62#[derive(Clone, Debug, Deserialize, PartialEq)]
63pub struct ItemDetailVotes {
64    #[serde(rename = "upVotes")]
65    pub likes: u32,
66    #[serde(rename = "downVotes")]
67    pub dislikes: u32,
68    #[serde(rename = "voteCount")]
69    pub votes: u32,
70    #[serde(rename = "votePercent")]
71    pub like_ratio: f32,
72    #[serde(rename = "showVotes")]
73    pub show_votes: bool,
74    #[serde(rename = "canVote")]
75    pub can_vote: bool,
76    #[serde(rename = "hasVoted")]
77    pub has_voted: bool,
78}
79
80#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
81pub struct FiatProductPriceQuantity {
82    pub significand: u32,
83    pub exponent: u32,
84}
85
86#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
87pub struct FiatProductPrice {
88    #[serde(rename = "currencyCode")]
89    pub currency_code: String,
90    pub quantity: FiatProductPriceQuantity,
91}
92
93#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
94pub struct FiatProduct {
95    #[serde(rename = "purchasePrice")]
96    pub price: FiatProductPrice,
97    pub published: bool,
98    pub purchasable: bool,
99}
100
101#[derive(Clone, Debug, Deserialize, PartialEq)]
102pub struct ItemDetail {
103    pub asset: ItemDetailAsset,
104    pub creator: ItemDetailCreator,
105    pub votes: ItemDetailVotes,
106    #[serde(rename = "fiatProduct")]
107    pub fiat_product: FiatProduct,
108}
109
110pub async fn item_details(client: &mut Client, ids: &[u64]) -> Result<Vec<ItemDetail>, Error> {
111    let ids = ids
112        .iter()
113        .map(|x| x.to_string())
114        .collect::<Vec<String>>()
115        .join(",");
116
117    let result = client
118        .requestor
119        .client
120        .get(format!("{URL}/items/details?assetIds={ids}"))
121        .headers(client.requestor.default_headers.clone())
122        .send()
123        .await;
124
125    #[derive(Clone, Debug, Deserialize, PartialEq)]
126    struct Response {
127        #[serde(rename = "data")]
128        objects: Vec<ItemDetail>,
129    }
130
131    let response = client.validate_response(result).await?;
132    Ok(client
133        .requestor
134        .parse_json::<Response>(response)
135        .await?
136        .objects)
137}
138
139pub async fn creations(
140    client: &mut Client,
141    id: u64,
142    asset_type: AssetTypeId,
143    paging: Paging<'_>,
144) -> Result<Creations, Error> {
145    let limit = paging.limit.unwrap_or(30);
146    let cursor = match paging.cursor {
147        Some(cursor) => format!("&cursor={cursor}"),
148        None => String::new(),
149    };
150
151    let result = client
152        .requestor
153        .client
154        .get(format!(
155            "{URL}/creations/user/{id}/{}?limit={limit}{cursor}",
156            asset_type as u8
157        ))
158        .headers(client.requestor.default_headers.clone())
159        .send()
160        .await;
161
162    let response = client.validate_response(result).await?;
163    client.requestor.parse_json::<Creations>(response).await
164}