roblox_api/api/toolbox_service/
v1.rs

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