Skip to content

Commit

Permalink
Add multipart content type (#30)
Browse files Browse the repository at this point in the history
* Add multipart content type

* Regenerate with vrchatapi/specification#408

Signed-off-by: C0D3 M4513R <[email protected]>

* Use async file io and don't `unwrap`

* Don't use file-io for multipart uploads/image endpoints

---------

Signed-off-by: C0D3 M4513R <[email protected]>
Co-authored-by: C0D3 M4513R <[email protected]>
  • Loading branch information
jellejurre and C0D3-M4513R authored Nov 12, 2024
1 parent af466f2 commit 402dddb
Show file tree
Hide file tree
Showing 13 changed files with 340 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .openapi-generator/FILES
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ docs/ApiConfigReportReasons.md
docs/ApiHealth.md
docs/AuthenticationApi.md
docs/Avatar.md
docs/AvatarStyles.md
docs/AvatarUnityPackageUrlObject.md
docs/AvatarsApi.md
docs/Badge.md
Expand Down Expand Up @@ -220,6 +221,7 @@ src/models/api_config_report_categories.rs
src/models/api_config_report_reasons.rs
src/models/api_health.rs
src/models/avatar.rs
src/models/avatar_styles.rs
src/models/avatar_unity_package_url_object.rs
src/models/badge.rs
src/models/ban_group_member_request.rs
Expand Down
1 change: 1 addition & 0 deletions docs/Avatar.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Name | Type | Description | Notes
**image_url** | **String** | |
**name** | **String** | |
**release_status** | [**models::ReleaseStatus**](ReleaseStatus.md) | |
**styles** | [**models::AvatarStyles**](Avatar_styles.md) | |
**tags** | **Vec<String>** | |
**thumbnail_image_url** | **String** | |
**unity_package_url** | **String** | |
Expand Down
13 changes: 13 additions & 0 deletions docs/AvatarStyles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# AvatarStyles

## Properties

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**primary** | Option<**String**> | | [optional]
**secondary** | Option<**String**> | | [optional]
**supplementary** | Option<**Vec<String>**> | | [optional]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


2 changes: 2 additions & 0 deletions docs/File.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**animation_style** | Option<**String**> | | [optional]
**mask_tag** | Option<**String**> | | [optional]
**extension** | **String** | |
**id** | **String** | |
**mime_type** | [**models::MimeType**](MIMEType.md) | |
Expand Down
96 changes: 96 additions & 0 deletions docs/FilesApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Method | HTTP request | Description
[**get_file_data_upload_status**](FilesApi.md#get_file_data_upload_status) | **GET** /file/{fileId}/{versionId}/{fileType}/status | Check FileData Upload Status
[**get_files**](FilesApi.md#get_files) | **GET** /files | List Files
[**start_file_data_upload**](FilesApi.md#start_file_data_upload) | **PUT** /file/{fileId}/{versionId}/{fileType}/start | Start FileData Upload
[**upload_gallery_image**](FilesApi.md#upload_gallery_image) | **POST** /gallery | Upload gallery image
[**upload_icon**](FilesApi.md#upload_icon) | **POST** /icon | Upload icon
[**upload_image**](FilesApi.md#upload_image) | **POST** /file/image | Upload gallery image, icon, emoji or sticker



Expand Down Expand Up @@ -330,3 +333,96 @@ Name | Type | Description | Required | Notes

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)


## upload_gallery_image

> models::File upload_gallery_image(file)
Upload gallery image

Upload a gallery image

### Parameters


Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**file** | **std::path::PathBuf** | The binary blob of the png file. | [required] |

### Return type

[**models::File**](File.md)

### Authorization

[authCookie](../README.md#authCookie)

### HTTP request headers

- **Content-Type**: multipart/form-data
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)


## upload_icon

> models::File upload_icon(file)
Upload icon

Upload an icon

### Parameters


Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**file** | **std::path::PathBuf** | The binary blob of the png file. | [required] |

### Return type

[**models::File**](File.md)

### Authorization

[authCookie](../README.md#authCookie)

### HTTP request headers

- **Content-Type**: multipart/form-data
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)


## upload_image

> models::File upload_image(file, tag, animation_style, mask_tag)
Upload gallery image, icon, emoji or sticker

Upload an image, which can be an icon, gallery image, sticker or emoji

### Parameters


Name | Type | Description | Required | Notes
------------- | ------------- | ------------- | ------------- | -------------
**file** | **std::path::PathBuf** | The binary blob of the png file. | [required] |
**tag** | **String** | Needs to be either icon, gallery, sticker or emoji | [required] |
**animation_style** | Option<**String**> | Animation style for sticker, required for sticker. | |
**mask_tag** | Option<**String**> | Mask of the sticker, optional for sticker. | |

### Return type

[**models::File**](File.md)

### Authorization

[authCookie](../README.md#authCookie)

### HTTP request headers

- **Content-Type**: multipart/form-data
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

2 changes: 1 addition & 1 deletion docs/GroupsApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Name | Type | Description | Required | Notes
> models::GroupAnnouncement create_group_announcement(group_id, create_group_announcement_request)
Create Group Announcement

Creates an Announcement for a Group.
Creates an Announcement for a Group. Warning: This will also remove all announcements. To make proper announcements, use the posts endpoint instead

### Parameters

Expand Down
3 changes: 3 additions & 0 deletions generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ sed -i 's/Result<models::CurrentUser, Error<GetCurrentUserError>>/Result<models:
# https://github.com/vrchatapi/vrchatapi-rust/pull/29
sed -i "s/local_var_req_builder = local_var_req_builder.json(&\(.*\));/if let Some(\1) = \1 { \0 }/g" src/apis/files_api.rs

#https://github.com/vrchatapi/vrchatapi-rust/pull/30
perl -0pi -e 's|(fn\s+[^(]*\([^)]*)file:\s+:?:?std::path::PathBuf,?([^)]*)((?:(?!\/\/ TODO: support file upload for '\''file'\'' parameter)[\s\S])*)\/\/ TODO: support file upload for '\''file'\'' parameter|\1file: impl Into<::std::borrow::Cow<'\''static, [u8]>>,\n\tfilename: impl Into<::std::borrow::Cow<'\''static, str>>,\n\tmime_type: &str,\2\3let part = reqwest::multipart::Part::bytes(file).file_name(filename).mime_str(mime_type)?;\n\tlocal_var_form = local_var_form.part("file", part);|g' src/apis/files_api.rs

cargo fmt
cargo build
cargo test
169 changes: 169 additions & 0 deletions src/apis/files_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,27 @@ pub enum StartFileDataUploadError {
UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`upload_gallery_image`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UploadGalleryImageError {
UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`upload_icon`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UploadIconError {
UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`upload_image`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UploadImageError {
UnknownValue(serde_json::Value),
}

/// Creates a new File object
pub async fn create_file(
configuration: &configuration::Configuration,
Expand Down Expand Up @@ -545,3 +566,151 @@ pub async fn start_file_data_upload(
Err(Error::ResponseError(local_var_error))
}
}

/// Upload a gallery image
pub async fn upload_gallery_image(
configuration: &configuration::Configuration,
file: impl Into<::std::borrow::Cow<'static, [u8]>>,
filename: impl Into<::std::borrow::Cow<'static, str>>,
mime_type: &str,
) -> Result<models::File, Error<UploadGalleryImageError>> {
let local_var_configuration = configuration;

let local_var_client = &local_var_configuration.client;

let local_var_uri_str = format!("{}/gallery", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder =
local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
let mut local_var_form = reqwest::multipart::Form::new();
let part = reqwest::multipart::Part::bytes(file)
.file_name(filename)
.mime_str(mime_type)?;
local_var_form = local_var_form.part("file", part);
local_var_req_builder = local_var_req_builder.multipart(local_var_form);

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;

let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
serde_json::from_str(&local_var_content).map_err(Error::from)
} else {
let local_var_entity: Option<UploadGalleryImageError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}

/// Upload an icon
pub async fn upload_icon(
configuration: &configuration::Configuration,
file: impl Into<::std::borrow::Cow<'static, [u8]>>,
filename: impl Into<::std::borrow::Cow<'static, str>>,
mime_type: &str,
) -> Result<models::File, Error<UploadIconError>> {
let local_var_configuration = configuration;

let local_var_client = &local_var_configuration.client;

let local_var_uri_str = format!("{}/icon", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder =
local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
let mut local_var_form = reqwest::multipart::Form::new();
let part = reqwest::multipart::Part::bytes(file)
.file_name(filename)
.mime_str(mime_type)?;
local_var_form = local_var_form.part("file", part);
local_var_req_builder = local_var_req_builder.multipart(local_var_form);

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;

let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
serde_json::from_str(&local_var_content).map_err(Error::from)
} else {
let local_var_entity: Option<UploadIconError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}

/// Upload an image, which can be an icon, gallery image, sticker or emoji
pub async fn upload_image(
configuration: &configuration::Configuration,
file: impl Into<::std::borrow::Cow<'static, [u8]>>,
filename: impl Into<::std::borrow::Cow<'static, str>>,
mime_type: &str,
tag: &str,
animation_style: Option<&str>,
mask_tag: Option<&str>,
) -> Result<models::File, Error<UploadImageError>> {
let local_var_configuration = configuration;

let local_var_client = &local_var_configuration.client;

let local_var_uri_str = format!("{}/file/image", local_var_configuration.base_path);
let mut local_var_req_builder =
local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder =
local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
}
let mut local_var_form = reqwest::multipart::Form::new();
let part = reqwest::multipart::Part::bytes(file)
.file_name(filename)
.mime_str(mime_type)?;
local_var_form = local_var_form.part("file", part);
local_var_form = local_var_form.text("tag", tag.to_string());
if let Some(local_var_param_value) = animation_style {
local_var_form = local_var_form.text("animationStyle", local_var_param_value.to_string());
}
if let Some(local_var_param_value) = mask_tag {
local_var_form = local_var_form.text("maskTag", local_var_param_value.to_string());
}
local_var_req_builder = local_var_req_builder.multipart(local_var_form);

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;

let local_var_status = local_var_resp.status();
let local_var_content = local_var_resp.text().await?;

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
serde_json::from_str(&local_var_content).map_err(Error::from)
} else {
let local_var_entity: Option<UploadImageError> =
serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent {
status: local_var_status,
content: local_var_content,
entity: local_var_entity,
};
Err(Error::ResponseError(local_var_error))
}
}
2 changes: 1 addition & 1 deletion src/apis/groups_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ pub async fn create_group(
}
}

/// Creates an Announcement for a Group.
/// Creates an Announcement for a Group. Warning: This will also remove all announcements. To make proper announcements, use the posts endpoint instead
pub async fn create_group_announcement(
configuration: &configuration::Configuration,
group_id: &str,
Expand Down
4 changes: 4 additions & 0 deletions src/models/avatar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub struct Avatar {
pub name: String,
#[serde(rename = "releaseStatus")]
pub release_status: models::ReleaseStatus,
#[serde(rename = "styles")]
pub styles: models::AvatarStyles,
#[serde(rename = "tags")]
pub tags: Vec<String>,
#[serde(rename = "thumbnailImageUrl")]
Expand Down Expand Up @@ -64,6 +66,7 @@ impl Avatar {
image_url: String,
name: String,
release_status: models::ReleaseStatus,
styles: models::AvatarStyles,
tags: Vec<String>,
thumbnail_image_url: String,
unity_package_url: String,
Expand All @@ -84,6 +87,7 @@ impl Avatar {
image_url,
name,
release_status,
styles,
tags,
thumbnail_image_url,
unity_package_url,
Expand Down
Loading

0 comments on commit 402dddb

Please sign in to comment.