roblox_api/api/assets/
v1.rs

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