1use crate::{PackageIdent, VersionIdent};
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::{collections::HashSet, hash::Hash};
6use url::Url;
7use uuid::Uuid;
8
9#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
10#[non_exhaustive]
11pub struct PackageV1 {
12 #[serde(rename = "uuid4")]
13 pub uuid: Uuid,
14 #[serde(rename = "owner")]
15 pub namespace: String,
16 pub name: String,
17 #[serde(rename = "full_name")]
18 pub ident: PackageIdent,
19 pub categories: HashSet<String>,
20 pub date_created: DateTime<Utc>,
21 pub date_updated: DateTime<Utc>,
22 pub donation_link: Option<Url>,
23 pub has_nsfw_content: bool,
24 pub is_deprecated: bool,
25 pub is_pinned: bool,
26 pub package_url: Url,
27 pub rating_score: u32,
28 pub versions: Vec<PackageVersionV1>,
29}
30
31impl PackageV1 {
32 pub fn latest(&self) -> &PackageVersionV1 {
33 &self.versions[0]
34 }
35
36 pub fn is_modpack(&self) -> bool {
37 self.categories.contains("Modpacks")
38 }
39
40 pub fn version_by_id(&self, uuid: &Uuid) -> Option<&PackageVersionV1> {
41 self.versions.iter().find(|v| v.uuid == *uuid)
42 }
43
44 pub fn version_by_name(&self, version: &semver::Version) -> Option<&PackageVersionV1> {
45 self.versions.iter().find(|v| v.number == *version)
46 }
47
48 pub fn total_downloads(&self) -> u32 {
49 self.versions.iter().map(|v| v.downloads).sum()
50 }
51}
52
53impl Hash for PackageV1 {
54 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55 self.uuid.hash(state);
56 }
57}
58
59impl PartialEq for PackageV1 {
60 fn eq(&self, other: &Self) -> bool {
61 self.uuid == other.uuid
62 }
63}
64
65#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
66#[non_exhaustive]
67pub struct PackageVersionV1 {
68 #[serde(rename = "uuid4")]
69 pub uuid: Uuid,
70 pub name: String,
71 #[serde(rename = "version_number")]
72 pub number: semver::Version,
73 #[serde(rename = "full_name")]
74 pub ident: VersionIdent,
75 pub date_created: DateTime<Utc>,
76 pub dependencies: Vec<VersionIdent>,
77 pub description: String,
78 pub download_url: Url,
79 pub downloads: u32,
80 pub file_size: u64,
81 pub icon: Url,
82 pub is_active: bool,
83 pub website_url: String,
84}
85
86impl PartialEq for PackageVersionV1 {
87 fn eq(&self, other: &Self) -> bool {
88 self.uuid == other.uuid
89 }
90}
91
92impl Hash for PackageVersionV1 {
93 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
94 self.uuid.hash(state);
95 }
96}
97
98#[derive(Serialize, Deserialize, Debug, Clone)]
99#[non_exhaustive]
100pub struct LegacyProfileCreateResponse {
101 pub key: Uuid,
102}
103
104#[derive(Serialize, Deserialize, Debug, Clone)]
105#[non_exhaustive]
106pub struct UserMediaInitiateUploadParams {
107 #[serde(rename = "filename")]
108 pub name: String,
109 #[serde(rename = "file_size_bytes")]
110 pub size: u64,
111}
112
113#[derive(Debug, Serialize, Deserialize, Clone)]
114#[non_exhaustive]
115pub struct UserMediaInitiateUploadResponse {
116 pub user_media: UserMedia,
117 pub upload_urls: Vec<UploadPartUrl>,
118}
119
120#[derive(Debug, Serialize, Deserialize, Clone)]
121#[non_exhaustive]
122pub struct UserMedia {
123 pub uuid: Uuid,
124 #[serde(rename = "filename")]
125 pub name: String,
126 pub size: u64,
127 #[serde(rename = "datetime_created")]
128 pub date_created: DateTime<Utc>,
129 pub expiry: DateTime<Utc>,
130 pub status: UserMediaStatus,
131}
132
133#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
134#[serde(rename_all = "snake_case")]
135#[non_exhaustive]
136pub enum UserMediaStatus {
137 Initial,
138 UploadInitiated,
139 UploadCreated,
140 UploadError,
141 UploadComplete,
142 UploadAborted,
143}
144
145#[derive(Debug, Serialize, Deserialize, Clone)]
146#[non_exhaustive]
147pub struct UploadPartUrl {
148 #[serde(rename = "part_number")]
149 pub number: u32,
150 pub url: String,
151 pub offset: u64,
152 pub length: u64,
153}
154
155#[derive(Debug, Serialize, Deserialize, Clone)]
156#[non_exhaustive]
157pub struct UserMediaFinishUploadParams {
158 pub parts: Vec<CompletedPart>,
159}
160
161#[derive(Debug, Serialize, Deserialize, Clone)]
162pub struct CompletedPart {
163 #[serde(rename = "ETag")]
164 pub tag: String,
165 #[serde(rename = "PartNumber")]
166 pub number: u32,
167}
168
169#[derive(Debug, Serialize, Deserialize, Clone)]
170#[non_exhaustive]
171pub struct PackageSubmissionResult {
172 pub package_version: PackageVersion,
173 pub available_communities: Vec<AvailableCommunity>,
174}
175
176#[derive(Debug, Serialize, Deserialize, Clone)]
177#[non_exhaustive]
178pub struct AvailableCommunity {
179 pub community: Community,
180 pub categories: CommunityCategory,
181 pub url: Url,
182}
183
184#[derive(Debug, Serialize, Deserialize, Clone)]
185#[non_exhaustive]
186pub struct CommunityCategory {
187 pub name: String,
188 pub slug: String,
189}
190
191#[derive(Debug, Serialize, Deserialize, Clone)]
192#[non_exhaustive]
193pub struct PackageVersionMetrics {
194 pub downloads: u64,
195}
196
197#[derive(Debug, Serialize, Deserialize, Clone)]
198#[non_exhaustive]
199pub struct PackageMetrics {
200 pub downloads: u64,
201}
202
203#[derive(Debug, Serialize, Deserialize, Clone)]
204#[non_exhaustive]
205pub struct RenderMarkdownParams {
206 pub markdown: String,
207}
208
209#[derive(Debug, Serialize, Deserialize, Clone)]
210#[non_exhaustive]
211pub struct RenderMarkdownResponse {
212 pub html: String,
213}
214
215#[derive(Debug, Serialize, Deserialize, Clone)]
216#[non_exhaustive]
217pub struct MarkdownResponse {
218 pub markdown: String,
219}
220
221#[derive(Debug, Serialize, Deserialize, Clone)]
222#[non_exhaustive]
223pub struct PackageIndexEntry {
224 pub namespace: String,
225 pub name: String,
226 pub version_number: semver::Version,
227 pub file_format: Option<String>,
228 pub file_size: u64,
229 pub dependencies: Vec<VersionIdent>,
230}
231
232#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
233#[non_exhaustive]
234pub struct PackageVersion {
235 #[serde(rename = "full_name")]
236 pub ident: VersionIdent,
237 pub description: String,
238 pub icon: Url,
239 pub dependencies: Vec<VersionIdent>,
240 pub download_url: Url,
241 pub downloads: u32,
242 pub date_created: DateTime<Utc>,
243 pub website_url: String,
244 pub is_active: bool,
245}
246
247impl PartialEq for PackageVersion {
248 fn eq(&self, other: &Self) -> bool {
249 self.ident == other.ident
250 }
251}
252
253impl Hash for PackageVersion {
254 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
255 self.ident.hash(state);
256 }
257}
258
259#[derive(Serialize, Deserialize, Debug, Clone, Eq)]
260#[non_exhaustive]
261pub struct Package {
262 #[serde(rename = "full_name")]
263 pub ident: PackageIdent,
264 pub package_url: Url,
265 pub date_created: DateTime<Utc>,
266 pub date_updated: DateTime<Utc>,
267 pub rating_score: i32,
268 pub is_pinned: bool,
269 pub is_deprecated: bool,
270 pub total_downloads: i32,
271 pub latest: PackageVersion,
272 pub community_listings: Vec<PackageListingExperimental>,
273}
274
275impl PartialEq for Package {
276 fn eq(&self, other: &Self) -> bool {
277 self.ident == other.ident
278 }
279}
280
281impl Hash for Package {
282 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
283 self.ident.hash(state);
284 }
285}
286
287#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
288#[non_exhaustive]
289pub struct PackageListingExperimental {
290 pub has_nsfw_content: bool,
291 pub categories: HashSet<String>,
292 pub community: String,
293 pub review_status: ReviewStatus,
294}
295
296#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
297#[serde(rename_all = "snake_case")]
298#[non_exhaustive]
299pub enum ReviewStatus {
300 Unreviewed,
301 Approved,
302 Rejected,
303}
304
305#[derive(Serialize, Deserialize, Debug, Clone)]
306#[non_exhaustive]
307pub struct PaginatedResponse<T> {
308 pub pagination: Pagination,
309 pub results: Vec<T>,
310}
311
312#[derive(Serialize, Deserialize, Debug, Clone)]
313#[non_exhaustive]
314pub struct Pagination {
315 pub next_link: Option<Url>,
316 pub previous_link: Option<Url>,
317}
318
319#[derive(Serialize, Deserialize, Debug, Clone)]
320#[non_exhaustive]
321pub struct Community {
322 #[serde(rename = "identifier")]
323 pub ident: String,
324 pub name: String,
325 pub discord_url: Option<Url>,
326 pub wiki_url: Option<Url>,
327 pub require_package_listing_approval: bool,
328}
329
330#[derive(Serialize, Deserialize, Debug, Clone)]
331#[non_exhaustive]
332pub struct IconValidatorParams {
333 pub icon_data: String,
334}
335
336#[derive(Serialize, Deserialize, Debug, Clone)]
337#[non_exhaustive]
338pub struct ManifestV1ValidatorParams {
339 pub namespace: String,
340 pub manifest_data: String,
341}
342
343#[derive(Serialize, Deserialize, Debug, Clone)]
344#[non_exhaustive]
345pub struct ReadmeValidatorParams {
346 pub readme_data: String,
347}
348
349#[derive(Serialize, Deserialize, Debug, Clone)]
350#[non_exhaustive]
351pub struct ValidatorResponse {
352 pub success: bool,
353}
354
355#[derive(Serialize, Deserialize, Debug, Clone)]
356#[non_exhaustive]
357pub struct WikisResponse {
358 pub results: Vec<ListedWiki>,
359 pub cursor: DateTime<Utc>,
360 pub has_more: bool,
361}
362
363#[derive(Serialize, Deserialize, Debug, Clone)]
364#[non_exhaustive]
365pub struct ListedWiki {
366 pub namespace: String,
367 pub name: String,
368 pub wiki: Wiki,
369}
370
371#[derive(Serialize, Deserialize, Debug, Clone)]
372#[non_exhaustive]
373pub struct Wiki {
374 pub id: String,
375 pub title: String,
376 pub slug: String,
377 #[serde(rename = "datetime_created")]
378 pub created_at: DateTime<Utc>,
379 #[serde(rename = "datetime_updated")]
380 pub updated_at: DateTime<Utc>,
381 pub pages: Vec<WikiPage>,
382}
383
384#[derive(Serialize, Deserialize, Debug, Clone)]
385#[non_exhaustive]
386pub struct WikiPage {
387 pub id: String,
388 pub title: String,
389 pub slug: String,
390 #[serde(rename = "datetime_created")]
391 pub created_at: DateTime<Utc>,
392 #[serde(rename = "datetime_updated")]
393 pub updated_at: DateTime<Utc>,
394 #[serde(default, rename = "markdown_content")]
395 pub content: Option<String>,
396}
397
398#[derive(Serialize, Deserialize, Debug, Clone)]
399#[non_exhaustive]
400pub struct WikiPageUpsert {
401 pub id: Option<String>,
402 pub title: String,
403 #[serde(rename = "markdown_content")]
404 pub content: String,
405}
406
407#[derive(Serialize, Deserialize, Debug, Clone)]
408#[non_exhaustive]
409pub struct WikiPageDelete {
410 pub id: String,
411}