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