use std::fmt::Display;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
#[derive(Debug, Serialize)]
pub struct Pagination {
pub limit: i64,
pub offset: i64,
}
impl Default for Pagination {
fn default() -> Self {
Self {
limit: 25,
offset: 0,
}
}
}
impl From<(i64, i64)> for Pagination {
fn from(value: (i64, i64)) -> Self {
Self {
limit: value.0,
offset: value.1,
}
}
}
#[derive(Debug, Clone, Copy, Serialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[serde(rename_all = "snake_case")]
pub enum ProjectsSort {
#[serde(rename = "-views")]
Views,
#[serde(rename = "-downloads")]
Downloads,
#[serde(rename = "-newest")]
Newest,
#[serde(rename = "-stars")]
Stars,
#[serde(rename = "-updated")]
Updated,
#[serde(rename = "-recent-downloads")]
RecentDownloads,
#[serde(rename = "-recent-views")]
RecentViews,
Slug, }
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[serde(rename_all = "snake_case")]
pub enum Category {
AdminTools,
Chat,
DevTools,
Economy,
Gameplay,
Games,
Protection,
RolePlaying,
WorldManagement,
Misc,
Undefined,
}
impl Display for Category {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::AdminTools => "Admin Tools",
Self::Chat => "Chat",
Self::DevTools => "Dev Tools",
Self::Economy => "Economy",
Self::Gameplay => "Gameplay",
Self::Games => "Games",
Self::Protection => "Protection",
Self::RolePlaying => "Role Playing",
Self::WorldManagement => "World Management",
Self::Misc => "Misc",
Self::Undefined => "Undefined",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Platform {
Paper,
Waterfall,
Velocity,
}
impl Display for Platform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::Paper => "Paper",
Self::Waterfall => "Waterfall",
Self::Velocity => "Velocity",
};
write!(f, "{s}")
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Project {
#[serde(deserialize_with = "time::serde::rfc3339::deserialize")]
pub created_at: OffsetDateTime,
pub name: String,
pub namespace: Namespace,
pub stats: ProjectStats,
pub category: Category,
#[serde(deserialize_with = "time::serde::rfc3339::deserialize")]
pub last_updated: OffsetDateTime,
pub visibility: Visibility,
pub avatar_url: String,
pub description: String,
pub user_actions: UserActions,
pub settings: ProjectSettings,
}
#[derive(Debug, Deserialize)]
pub struct Namespace {
pub owner: String,
pub slug: String,
}
impl Namespace {
pub fn url(&self) -> String {
format!("https://hangar.papermc.io/{}/{}", self.owner, self.slug)
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ProjectStats {
pub views: i64,
pub downloads: i64,
pub recent_views: i64,
pub recent_downloads: i64,
pub stars: i64,
pub watchers: i64,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Visibility {
Public,
New,
NeedsChanges,
NeedsApproval,
SoftDelete,
}
#[derive(Debug, Deserialize)]
pub struct UserActions {
pub starred: bool,
pub watching: bool,
pub flagged: bool,
}
#[derive(Debug, Deserialize)]
pub struct ProjectSettings {
pub links: Vec<Link>,
pub tags: Vec<ProjectTags>,
pub license: License,
pub keywords: Vec<String>,
pub sponsors: String,
pub donation: Donation,
}
#[derive(Debug, Deserialize)]
pub struct Link {
pub id: i64,
#[serde(rename = "type")]
pub link_type: String,
pub title: Option<String>,
pub links: Vec<ActualLink>,
}
#[derive(Debug, Deserialize)]
pub struct ActualLink {
pub id: i64,
pub name: String,
pub url: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ProjectTags {
Addon,
Library,
SupportsFolia,
}
#[derive(Debug, Deserialize)]
pub struct License {
pub name: Option<String>,
pub url: Option<String>,
#[serde(rename = "type")]
pub license_type: String,
}
#[derive(Debug, Deserialize)]
pub struct Donation {
pub enable: bool,
pub subject: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Version {
#[serde(deserialize_with = "time::serde::rfc3339::deserialize")]
pub created_at: OffsetDateTime,
pub name: String,
pub visibility: Visibility,
pub description: String,
pub stats: VersionStats,
pub author: String,
pub review_state: ReviewState,
pub channel: Channel,
pub pinned_status: PinnedStatus,
pub downloads: ByPlatform<VersionDownloads>,
pub plugin_dependencies: ByPlatform<Vec<VersionPluginDependencies>>,
pub platform_dependencies: ByPlatform<Vec<String>>,
pub platform_dependencies_formatted: ByPlatform<Vec<String>>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VersionStats {
pub total_downloads: i64,
pub platform_downloads: ByPlatform<i64>,
}
#[derive(Debug, Deserialize)]
pub struct ByPlatform<T> {
#[serde(rename = "PAPER")]
pub paper: Option<T>,
#[serde(rename = "WATERFALL")]
pub waterfall: Option<T>,
#[serde(rename = "VELOCITY")]
pub velocity: Option<T>,
}
impl<T> ByPlatform<T> {
pub fn get(&self, platform: Platform) -> Option<&T> {
match platform {
Platform::Paper => self.paper.as_ref(),
Platform::Waterfall => self.waterfall.as_ref(),
Platform::Velocity => self.velocity.as_ref(),
}
}
pub fn iter(&self) -> impl Iterator<Item = (Platform, &T)> {
self.paper
.iter()
.map(|v| (Platform::Paper, v))
.chain(self.waterfall.iter().map(|v| (Platform::Waterfall, v)))
.chain(self.velocity.iter().map(|v| (Platform::Velocity, v)))
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ReviewState {
Unreviewed,
Reviewed,
UnderReview,
PartiallyReviewed,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Channel {
#[serde(deserialize_with = "time::serde::rfc3339::deserialize")]
pub created_at: OffsetDateTime,
pub name: String,
pub description: Option<String>,
pub color: String,
pub flags: Vec<ChannelFlags>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ChannelFlags {
Frozen,
Unstable,
Pinned,
SendsNotifications,
HideByDefault,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum PinnedStatus {
None,
Version,
Channel,
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum VersionDownloads {
#[serde(rename_all = "camelCase")]
Internal {
file_info: VersionDownloadsFileInfo,
download_url: String,
},
#[serde(rename_all = "camelCase")]
External {
external_url: String,
},
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VersionDownloadsFileInfo {
pub name: String,
pub size_bytes: i64,
pub sha256_hash: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VersionPluginDependencies {
pub name: String,
pub required: bool,
pub external_url: Option<String>,
pub platform: Platform,
}