use crate::groups::Page;
use crate::prelude::*;
use uuid::Uuid;
pub struct ParagonHubGroup<'a> {
pub(crate) esi: &'a Esi,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ListingState {
Listed,
SoldOut,
Expired,
Removed,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
#[serde(untagged)]
#[allow(missing_docs)]
pub enum ListingPrice {
Isk { isk: f64 },
Plex { plex: i64 },
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct SkinrListing {
pub created: String,
pub expires: String,
pub id: Uuid,
pub last_modified: String,
pub price: ListingPrice,
pub quantity: i64,
pub seller_id: i64,
pub skinr_id: String,
pub state: ListingState,
}
impl ParagonHubGroup<'_> {
api_get!(
get_skinr_listings,
"GetParagonHubSkinr",
RequestType::Public,
Page<SkinrListing>,
;
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
}
#[cfg(test)]
mod tests {
use super::{ListingPrice, ListingState};
use crate::groups::{Page, SkinrListing};
#[test]
fn test_parse_listings_with_both_price_kinds() {
let json = r#"{"listings": [
{"created": "2026-10-01T00:00:00Z", "expires": "2026-11-01T00:00:00Z",
"id": "3868eaed-8278-4cb7-9709-7d7de9c20dc7", "last_modified": "2026-10-02T00:00:00Z",
"price": {"isk": 1500000.5}, "quantity": 1, "seller_id": 2112000000,
"skinr_id": "abc", "state": "sold_out"},
{"created": "2026-10-01T00:00:00Z", "expires": "2026-11-01T00:00:00Z",
"id": "3868eaed-8278-4cb7-9709-7d7de9c20dc8", "last_modified": "2026-10-02T00:00:00Z",
"price": {"plex": 250}, "quantity": 3, "seller_id": 2112000001,
"skinr_id": "def", "state": "listed"}
]}"#;
let page: Page<SkinrListing> = serde_json::from_str(json).unwrap();
assert!(page.cursor.is_none());
assert_eq!(page.items[0].state, ListingState::SoldOut);
assert!(matches!(page.items[0].price, ListingPrice::Isk { .. }));
assert!(matches!(
page.items[1].price,
ListingPrice::Plex { plex: 250 }
));
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct ListingTarget {
pub character_id: Option<i64>,
pub corporation_id: Option<i64>,
pub alliance_id: Option<i64>,
pub public: Option<bool>,
}
#[derive(Debug, Clone, PartialEq, Deserialize)]
#[allow(missing_docs)]
pub struct CharacterSkinrListing {
pub created: String,
pub expires: String,
pub id: Uuid,
pub last_modified: String,
pub price: ListingPrice,
pub quantity: i64,
pub seller_id: i64,
pub skinr_id: String,
pub state: ListingState,
pub target: ListingTarget,
}
impl ParagonHubGroup<'_> {
api_get!(
get_character_skinr_listings,
"GetCharactersParagonHubSkinr",
RequestType::Authenticated,
Page<CharacterSkinrListing>,
(character_id: i64) => "{character_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
api_get!(
get_alliance_skinr_listings,
"GetParagonHubSkinrAlliances",
RequestType::Authenticated,
Page<SkinrListing>,
(alliance_id: i64) => "{alliance_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
api_get!(
get_skinr_listings_for_character,
"GetParagonHubSkinrCharacters",
RequestType::Authenticated,
Page<SkinrListing>,
(character_id: i64) => "{character_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
api_get!(
get_corporation_skinr_listings,
"GetParagonHubSkinrCorporations",
RequestType::Authenticated,
Page<SkinrListing>,
(corporation_id: i64) => "{corporation_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
}
#[cfg(test)]
mod target_tests {
use super::*;
#[test]
fn test_parse_character_listing_target() {
let page: Page<CharacterSkinrListing> = serde_json::from_str(
r#"{"listings":[{"created":"a","expires":"b","id":"67e6b7a0-6f58-4b5b-a2c4-4f3a1f0f2b11",
"last_modified":"c","price":{"plex":5},"quantity":1,"seller_id":2,"skinr_id":"s",
"state":"listed","target":{"corporation_id":9}}]}"#,
)
.unwrap();
assert_eq!(page.items[0].target.corporation_id, Some(9));
assert!(page.cursor.is_none());
}
}