roblox_api/api/assets/
v1.rs

1use std::path::Path;
2
3use reqwest::{
4    header::{self, HeaderValue},
5    multipart::Form,
6};
7use serde::{Deserialize, Serialize};
8
9use crate::{DateTime, Error, client::Client};
10
11const URL: &str = "https://apis.roblox.com/assets/user-auth/v1";
12
13#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
14pub enum AssetType {
15    Audio,
16    Decal,
17    Model,
18    Video,
19}
20
21#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
22pub enum Creator {
23    #[serde(rename = "userId")]
24    // TODO: cast to u64
25    UserId(String), // can be sent as a u64, but it's returned as a string in some cases
26    #[serde(rename = "groupId")]
27    GroupId(String),
28}
29
30#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
31pub struct CreationContext {
32    pub creator: Creator,
33    #[serde(rename = "expectedPrice")]
34    pub expected_price: Option<u64>,
35}
36
37#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
38pub struct ModerationResult {
39    #[serde(rename = "moderationState")]
40    pub state: String,
41}
42
43#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
44pub struct AssetInfo {
45    #[serde(rename = "assetId")]
46    pub id: String,
47    pub icon: String,
48    #[serde(rename = "displayName")]
49    pub title: String,
50    pub description: String,
51
52    pub path: String,
53    pub state: String,
54    #[serde(rename = "assetType")]
55    pub asset_type: AssetType,
56
57    #[serde(rename = "revisionId")]
58    pub revision_id: String,
59    #[serde(rename = "revisionCreateTime")]
60    pub revision_creation_time: DateTime,
61
62    #[serde(rename = "creationContext")]
63    pub creation_context: CreationContext,
64    #[serde(rename = "moderationResult")]
65    pub moderation_result: ModerationResult,
66}
67
68#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
69pub struct AssetUploadResponse {
70    pub path: String,
71    // TODO: cast to u64 please
72    #[serde(rename = "assetId")]
73    pub id: String,
74    #[serde(rename = "displayName")]
75    pub title: String,
76
77    pub state: String,
78    #[serde(rename = "assetType")]
79    pub asset_type: AssetType,
80
81    #[serde(rename = "revisionId")]
82    pub revision_id: String,
83    #[serde(rename = "revisionCreateTime")]
84    pub revision_creation_time: DateTime,
85    #[serde(rename = "creationContext")]
86    pub creation_context: CreationContext,
87    #[serde(rename = "moderationResult")]
88    pub moderation_result: ModerationResult,
89}
90
91#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
92pub struct AssetUploadStatus {
93    pub path: String,
94    #[serde(rename = "operationId")]
95    pub operation_id: String,
96    #[serde(rename = "done")]
97    pub complete: bool,
98    pub response: Option<AssetUploadResponse>,
99}
100
101pub async fn asset(client: &mut Client, id: u64) -> Result<AssetInfo, Error> {
102    let result = client
103        .requestor
104        .client
105        .get(format!("{URL}/{id}"))
106        .headers(client.requestor.default_headers.clone())
107        .send()
108        .await;
109
110    let response = client.validate_response(result).await?;
111    client.requestor.parse_json::<AssetInfo>(response).await
112}
113
114// this api also takes in a patch request to update an exists asset "{URL}/assets/{id}"
115pub async fn upload(
116    client: &mut Client,
117    path: impl AsRef<Path>,
118    title: &str,
119    description: &str,
120    asset_type: AssetType,
121    creation_context: CreationContext,
122) -> Result<AssetUploadStatus, Error> {
123    let mut headers = client.requestor.default_headers.clone();
124    headers.insert(header::ACCEPT, HeaderValue::from_str("*/*").unwrap());
125
126    #[derive(Clone, Debug, Deserialize, Serialize)]
127    struct Request<'a> {
128        #[serde(rename = "displayName")]
129        title: &'a str,
130        description: &'a str,
131        #[serde(rename = "assetType")]
132        asset_type: AssetType,
133        #[serde(rename = "creationContext")]
134        creation_context: CreationContext,
135    }
136
137    let request = serde_json::to_string(&Request {
138        title,
139        description,
140        asset_type,
141        creation_context,
142    })
143    .unwrap();
144
145    let result = client
146        .requestor
147        .client
148        .post(format!("{URL}/assets"))
149        .headers(headers)
150        .multipart(
151            Form::new()
152                .text("request", request)
153                .file("fileContent", &path)
154                .await
155                .unwrap(),
156        )
157        .send()
158        .await;
159
160    let response = client.validate_response(result).await?;
161    client
162        .requestor
163        .parse_json::<AssetUploadStatus>(response)
164        .await
165}
166
167pub async fn status(client: &mut Client, operation_id: &str) -> Result<AssetUploadStatus, Error> {
168    let result = client
169        .requestor
170        .client
171        .get(format!("{URL}/operations/{operation_id}"))
172        .headers(client.requestor.default_headers.clone())
173        .send()
174        .await;
175
176    let response = client.validate_response(result).await?;
177    client
178        .requestor
179        .parse_json::<AssetUploadStatus>(response)
180        .await
181}