modrinth_api/models/
project.rs

1/*
2 * Labrinth
3 *
4 * This documentation doesn't provide a way to test our API. In order to facilitate testing, we recommend the following tools:  - [cURL](https://curl.se/) (recommended, command-line) - [ReqBIN](https://reqbin.com/) (recommended, online) - [Postman](https://www.postman.com/downloads/) - [Insomnia](https://insomnia.rest/) - Your web browser, if you don't need to send headers or a request body  Once you have a working client, you can test that it works by making a `GET` request to `https://staging-api.modrinth.com/`:  ```json {   \"about\": \"Welcome traveler!\",   \"documentation\": \"https://docs.modrinth.com\",   \"name\": \"modrinth-labrinth\",   \"version\": \"2.7.0\" } ```  If you got a response similar to the one above, you can use the Modrinth API! When you want to go live using the production API, use `api.modrinth.com` instead of `staging-api.modrinth.com`.  ## Authentication This API has two options for authentication: personal access tokens and [OAuth2](https://en.wikipedia.org/wiki/OAuth). All tokens are tied to a Modrinth user and use the `Authorization` header of the request.  Example: ``` Authorization: mrp_RNtLRSPmGj2pd1v1ubi52nX7TJJM9sznrmwhAuj511oe4t1jAqAQ3D6Wc8Ic ```  You do not need a token for most requests. Generally speaking, only the following types of requests require a token: - those which create data (such as version creation) - those which modify data (such as editing a project) - those which access private data (such as draft projects, notifications, emails, and payout data)  Each request requiring authentication has a certain scope. For example, to view the email of the user being requested, the token must have the `USER_READ_EMAIL` scope. You can find the list of available scopes [on GitHub](https://github.com/modrinth/labrinth/blob/master/src/models/pats.rs#L15). Making a request with an invalid scope will return a 401 error.  Please note that certain scopes and requests cannot be completed with a personal access token or using OAuth. For example, deleting a user account can only be done through Modrinth's frontend.  ### OAuth2 Applications interacting with the authenticated API should create an OAuth2 application. You can do this in [the developer settings](https://modrinth.com/settings/applications).  Once you have created a client, use the following URL to have a user authorize your client: ``` https://modrinth.com/auth/authorize?client_id=<CLIENT_ID>&redirect_uri=<CALLBACK_URL>&scope=<SCOPE_ONE>+<SCOPE_TWO>+<SCOPE_THREE> ```  Then, use the following URL to get the token: ``` https://api.modrinth.com/_internal/oauth/token ```  This route will be changed in the future to move the `_internal` part to `v3`.  ### Personal access tokens Personal access tokens (PATs) can be generated in from [the user settings](https://modrinth.com/settings/account).  ### GitHub tokens For backwards compatibility purposes, some types of GitHub tokens also work for authenticating a user with Modrinth's API, granting all scopes. **We urge any application still using GitHub tokens to start using personal access tokens for security and reliability purposes.** GitHub tokens will cease to function to authenticate with Modrinth's API as soon as version 3 of the API is made generally available.  ## Cross-Origin Resource Sharing This API features Cross-Origin Resource Sharing (CORS) implemented in compliance with the [W3C spec](https://www.w3.org/TR/cors/). This allows for cross-domain communication from the browser. All responses have a wildcard same-origin which makes them completely public and accessible to everyone, including any code on any site.  ## Identifiers The majority of items you can interact with in the API have a unique eight-digit base62 ID. Projects, versions, users, threads, teams, and reports all use this same way of identifying themselves. Version files use the sha1 or sha512 file hashes as identifiers.  Each project and user has a friendlier way of identifying them; slugs and usernames, respectively. While unique IDs are constant, slugs and usernames can change at any moment. If you want to store something in the long term, it is recommended to use the unique ID.  ## Ratelimits The API has a ratelimit defined per IP. Limits and remaining amounts are given in the response headers. - `X-Ratelimit-Limit`: the maximum number of requests that can be made in a minute - `X-Ratelimit-Remaining`: the number of requests remaining in the current ratelimit window - `X-Ratelimit-Reset`: the time in seconds until the ratelimit window resets  Ratelimits are the same no matter whether you use a token or not. The ratelimit is currently 300 requests per minute. If you have a use case requiring a higher limit, please [contact us](mailto:admin@modrinth.com).  ## User Agents To access the Modrinth API, you **must** use provide a uniquely-identifying `User-Agent` header. Providing a user agent that only identifies your HTTP client library (such as \"okhttp/4.9.3\") increases the likelihood that we will block your traffic. It is recommended, but not required, to include contact information in your user agent. This allows us to contact you if we would like a change in your application's behavior without having to block your traffic. - Bad: `User-Agent: okhttp/4.9.3` - Good: `User-Agent: project_name` - Better: `User-Agent: github_username/project_name/1.56.0` - Best: `User-Agent: github_username/project_name/1.56.0 (launcher.com)` or `User-Agent: github_username/project_name/1.56.0 (contact@launcher.com)`  ## Versioning Modrinth follows a simple pattern for its API versioning. In the event of a breaking API change, the API version in the URL path is bumped, and migration steps will be published below.  When an API is no longer the current one, it will immediately be considered deprecated. No more support will be provided for API versions older than the current one. It will be kept for some time, but this amount of time is not certain.  We will exercise various tactics to get people to update their implementation of our API. One example is by adding something like `STOP USING THIS API` to various data returned by the API.  Once an API version is completely deprecated, it will permanently return a 410 error. Please ensure your application handles these 410 errors.  ### Migrations Inside the following spoiler, you will be able to find all changes between versions of the Modrinth API, accompanied by tips and a guide to migrate applications to newer versions.  Here, you can also find changes for [Minotaur](https://github.com/modrinth/minotaur), Modrinth's official Gradle plugin. Major versions of Minotaur directly correspond to major versions of the Modrinth API.  <details><summary>API v1 to API v2</summary>  These bullet points cover most changes in the v2 API, but please note that fields containing `mod` in most contexts have been shifted to `project`.  For example, in the search route, the field `mod_id` was renamed to `project_id`.  - The search route has been moved from `/api/v1/mod` to `/v2/search` - New project fields: `project_type` (may be `mod` or `modpack`), `moderation_message` (which has a `message` and `body`), `gallery` - New search facet: `project_type` - Alphabetical sort removed (it didn't work and is not possible due to limits in MeiliSearch) - New search fields: `project_type`, `gallery`   - The gallery field is an array of URLs to images that are part of the project's gallery - The gallery is a new feature which allows the user to upload images showcasing their mod to the CDN which will be displayed on their mod page - Internal change: Any project file uploaded to Modrinth is now validated to make sure it's a valid Minecraft mod, Modpack, etc.   - For example, a Forge 1.17 mod with a JAR not containing a mods.toml will not be allowed to be uploaded to Modrinth - In project creation, projects may not upload a mod with no versions to review, however they can be saved as a draft   - Similarly, for version creation, a version may not be uploaded without any files - Donation URLs have been enabled - New project status: `archived`. Projects with this status do not appear in search - Tags (such as categories, loaders) now have icons (SVGs) and specific project types attached - Dependencies have been wiped and replaced with a new system - Notifications now have a `type` field, such as `project_update`  Along with this, project subroutes (such as `/v2/project/{id}/version`) now allow the slug to be used as the ID. This is also the case with user routes.  </details><details><summary>Minotaur v1 to Minotaur v2</summary>  Minotaur 2.x introduced a few breaking changes to how your buildscript is formatted.  First, instead of registering your own `publishModrinth` task, Minotaur now automatically creates a `modrinth` task. As such, you can replace the `task publishModrinth(type: TaskModrinthUpload) {` line with just `modrinth {`.  To declare supported Minecraft versions and mod loaders, the `gameVersions` and `loaders` arrays must now be used. The syntax for these are pretty self-explanatory.  Instead of using `releaseType`, you must now use `versionType`. This was actually changed in v1.2.0, but very few buildscripts have moved on from v1.1.0.  Dependencies have been changed to a special DSL. Create a `dependencies` block within the `modrinth` block, and then use `scope.type(\"project/version\")`. For example, `required.project(\"fabric-api\")` adds a required project dependency on Fabric API.  You may now use the slug anywhere that a project ID was previously required.  </details> 
5 *
6 * The version of the OpenAPI document: v2.7.0/15cf3fc
7 * Contact: support@modrinth.com
8 * Generated by: https://openapi-generator.tech
9 */
10
11use crate::models;
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
15pub struct Project {
16    /// The slug of a project, used for vanity URLs. Regex: ```^[\\w!@$()`.+,\"\\-']{3,64}$```
17    #[serde(rename = "slug")]
18    pub slug: String,
19    /// The title or name of the project
20    #[serde(rename = "title")]
21    pub title: String,
22    /// A short description of the project
23    #[serde(rename = "description")]
24    pub description: String,
25    /// A list of the categories that the project has
26    #[serde(rename = "categories")]
27    pub categories: Vec<String>,
28    /// The client side support of the project
29    #[serde(rename = "client_side")]
30    pub client_side: ClientSide,
31    /// The server side support of the project
32    #[serde(rename = "server_side")]
33    pub server_side: ServerSide,
34    /// A long form description of the project
35    #[serde(rename = "body")]
36    pub body: String,
37    /// The status of the project
38    #[serde(rename = "status")]
39    pub status: Status,
40    /// The requested status when submitting for review or scheduling the project for release
41    #[serde(rename = "requested_status", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
42    pub requested_status: Option<Option<RequestedStatus>>,
43    /// A list of categories which are searchable but non-primary
44    #[serde(rename = "additional_categories", skip_serializing_if = "Option::is_none")]
45    pub additional_categories: Option<Vec<String>>,
46    /// An optional link to where to submit bugs or issues with the project
47    #[serde(rename = "issues_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
48    pub issues_url: Option<Option<String>>,
49    /// An optional link to the source code of the project
50    #[serde(rename = "source_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
51    pub source_url: Option<Option<String>>,
52    /// An optional link to the project's wiki page or other relevant information
53    #[serde(rename = "wiki_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
54    pub wiki_url: Option<Option<String>>,
55    /// An optional invite link to the project's discord
56    #[serde(rename = "discord_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
57    pub discord_url: Option<Option<String>>,
58    /// A list of donation links for the project
59    #[serde(rename = "donation_urls", skip_serializing_if = "Option::is_none")]
60    pub donation_urls: Option<Vec<models::ProjectDonationUrl>>,
61    /// The project type of the project
62    #[serde(rename = "project_type")]
63    pub project_type: ProjectType,
64    /// The total number of downloads of the project
65    #[serde(rename = "downloads")]
66    pub downloads: i32,
67    /// The URL of the project's icon
68    #[serde(rename = "icon_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
69    pub icon_url: Option<Option<String>>,
70    /// The RGB color of the project, automatically generated from the project icon
71    #[serde(rename = "color", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
72    pub color: Option<Option<i32>>,
73    /// The ID of the moderation thread associated with this project
74    #[serde(rename = "thread_id", skip_serializing_if = "Option::is_none")]
75    pub thread_id: Option<String>,
76    #[serde(rename = "monetization_status", skip_serializing_if = "Option::is_none")]
77    pub monetization_status: Option<MonetizationStatus>,
78    /// The ID of the project, encoded as a base62 string
79    #[serde(rename = "id")]
80    pub id: String,
81    /// The ID of the team that has ownership of this project
82    #[serde(rename = "team")]
83    pub team: String,
84    /// The link to the long description of the project. Always null, only kept for legacy compatibility.
85    #[serde(rename = "body_url", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
86    pub body_url: Option<Option<String>>,
87    #[serde(rename = "moderator_message", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
88    pub moderator_message: Option<Option<models::ModeratorMessage>>,
89    /// The date the project was published
90    #[serde(rename = "published")]
91    pub published: String,
92    /// The date the project was last updated
93    #[serde(rename = "updated")]
94    pub updated: String,
95    /// The date the project's status was set to an approved status
96    #[serde(rename = "approved", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
97    pub approved: Option<Option<String>>,
98    /// The date the project's status was submitted to moderators for review
99    #[serde(rename = "queued", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")]
100    pub queued: Option<Option<String>>,
101    /// The total number of users following the project
102    #[serde(rename = "followers")]
103    pub followers: i32,
104    #[serde(rename = "license", skip_serializing_if = "Option::is_none")]
105    pub license: Option<models::ProjectLicense>,
106    /// A list of the version IDs of the project (will never be empty unless `draft` status)
107    #[serde(rename = "versions", skip_serializing_if = "Option::is_none")]
108    pub versions: Option<Vec<String>>,
109    /// A list of all of the game versions supported by the project
110    #[serde(rename = "game_versions", skip_serializing_if = "Option::is_none")]
111    pub game_versions: Option<Vec<String>>,
112    /// A list of all of the loaders supported by the project
113    #[serde(rename = "loaders", skip_serializing_if = "Option::is_none")]
114    pub loaders: Option<Vec<String>>,
115    /// A list of images that have been uploaded to the project's gallery
116    #[serde(rename = "gallery", skip_serializing_if = "Option::is_none")]
117    pub gallery: Option<Vec<models::GalleryImage>>,
118}
119
120impl Project {
121    pub fn new(slug: String, title: String, description: String, categories: Vec<String>, client_side: ClientSide, server_side: ServerSide, body: String, status: Status, project_type: ProjectType, downloads: i32, id: String, team: String, published: String, updated: String, followers: i32) -> Project {
122        Project {
123            slug,
124            title,
125            description,
126            categories,
127            client_side,
128            server_side,
129            body,
130            status,
131            requested_status: None,
132            additional_categories: None,
133            issues_url: None,
134            source_url: None,
135            wiki_url: None,
136            discord_url: None,
137            donation_urls: None,
138            project_type,
139            downloads,
140            icon_url: None,
141            color: None,
142            thread_id: None,
143            monetization_status: None,
144            id,
145            team,
146            body_url: None,
147            moderator_message: None,
148            published,
149            updated,
150            approved: None,
151            queued: None,
152            followers,
153            license: None,
154            versions: None,
155            game_versions: None,
156            loaders: None,
157            gallery: None,
158        }
159    }
160}
161/// The client side support of the project
162#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
163pub enum ClientSide {
164    #[serde(rename = "required")]
165    Required,
166    #[serde(rename = "optional")]
167    Optional,
168    #[serde(rename = "unsupported")]
169    Unsupported,
170}
171
172impl Default for ClientSide {
173    fn default() -> ClientSide {
174        Self::Required
175    }
176}
177/// The server side support of the project
178#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
179pub enum ServerSide {
180    #[serde(rename = "required")]
181    Required,
182    #[serde(rename = "optional")]
183    Optional,
184    #[serde(rename = "unsupported")]
185    Unsupported,
186}
187
188impl Default for ServerSide {
189    fn default() -> ServerSide {
190        Self::Required
191    }
192}
193/// The status of the project
194#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
195pub enum Status {
196    #[serde(rename = "approved")]
197    Approved,
198    #[serde(rename = "archived")]
199    Archived,
200    #[serde(rename = "rejected")]
201    Rejected,
202    #[serde(rename = "draft")]
203    Draft,
204    #[serde(rename = "unlisted")]
205    Unlisted,
206    #[serde(rename = "processing")]
207    Processing,
208    #[serde(rename = "withheld")]
209    Withheld,
210    #[serde(rename = "scheduled")]
211    Scheduled,
212    #[serde(rename = "private")]
213    Private,
214    #[serde(rename = "unknown")]
215    Unknown,
216}
217
218impl Default for Status {
219    fn default() -> Status {
220        Self::Approved
221    }
222}
223/// The requested status when submitting for review or scheduling the project for release
224#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
225pub enum RequestedStatus {
226    #[serde(rename = "approved")]
227    Approved,
228    #[serde(rename = "archived")]
229    Archived,
230    #[serde(rename = "unlisted")]
231    Unlisted,
232    #[serde(rename = "private")]
233    Private,
234    #[serde(rename = "draft")]
235    Draft,
236}
237
238impl Default for RequestedStatus {
239    fn default() -> RequestedStatus {
240        Self::Approved
241    }
242}
243/// The project type of the project
244#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
245pub enum ProjectType {
246    #[serde(rename = "mod")]
247    Mod,
248    #[serde(rename = "modpack")]
249    Modpack,
250    #[serde(rename = "resourcepack")]
251    Resourcepack,
252    #[serde(rename = "shader")]
253    Shader,
254}
255
256impl Default for ProjectType {
257    fn default() -> ProjectType {
258        Self::Mod
259    }
260}
261/// 
262#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
263pub enum MonetizationStatus {
264    #[serde(rename = "monetized")]
265    Monetized,
266    #[serde(rename = "demonetized")]
267    Demonetized,
268    #[serde(rename = "force-demonetized")]
269    ForceDemonetized,
270}
271
272impl Default for MonetizationStatus {
273    fn default() -> MonetizationStatus {
274        Self::Monetized
275    }
276}
277