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 UserId(String), #[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 #[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
114pub 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}