use crate::groups::Page;
use crate::prelude::*;
use uuid::Uuid;
pub struct CorporationProjectsGroup<'a> {
pub(crate) esi: &'a Esi,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectStateFilter {
All,
Active,
}
impl std::fmt::Display for ProjectStateFilter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
ProjectStateFilter::All => "All",
ProjectStateFilter::Active => "Active",
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum ProjectState {
Unspecified,
Active,
Closed,
Completed,
Expired,
Deleted,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectProgress {
pub current: i64,
pub desired: i64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ProjectReward {
pub initial: f64,
pub remaining: f64,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ProjectSummary {
pub id: Uuid,
pub last_modified: String,
pub name: String,
pub progress: ProjectProgress,
pub reward: Option<ProjectReward>,
pub state: ProjectState,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectLocation {
pub solar_system_id: Option<i64>,
pub constellation_id: Option<i64>,
pub region_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectIdentity {
pub character_id: Option<i64>,
pub corporation_id: Option<i64>,
pub alliance_id: Option<i64>,
pub faction_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct TypeOrGroup {
pub type_id: Option<i64>,
pub group_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct DockingLocation {
pub structure_id: Option<i64>,
pub station_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectArchetype {
pub archetype_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectFaction {
pub faction_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectSignature {
pub signature_type_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectCorporation {
pub corporation_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct FwComplexConfig {
#[serde(default)]
pub archetypes: Vec<ProjectArchetype>,
#[serde(default)]
pub factions: Vec<ProjectFaction>,
#[serde(default)]
pub locations: Vec<ProjectLocation>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ShipActivityConfig {
#[serde(default)]
pub identities: Vec<ProjectIdentity>,
#[serde(default)]
pub locations: Vec<ProjectLocation>,
#[serde(default)]
pub ships: Vec<TypeOrGroup>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct LocationsConfig {
#[serde(default)]
pub locations: Vec<ProjectLocation>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct DeliverItemConfig {
#[serde(default)]
pub docking_locations: Vec<DockingLocation>,
#[serde(default)]
pub items: Vec<TypeOrGroup>,
pub office_id: Option<i64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct EarnLoyaltyPointConfig {
#[serde(default)]
pub corporations: Vec<ProjectCorporation>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum ManufactureOwner {
Any,
Corporation,
Character,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ManufactureItemConfig {
#[serde(default)]
pub docking_locations: Vec<DockingLocation>,
#[serde(default)]
pub items: Vec<TypeOrGroup>,
pub owner: ManufactureOwner,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct MineMaterialConfig {
#[serde(default)]
pub locations: Vec<ProjectLocation>,
#[serde(default)]
pub materials: Vec<TypeOrGroup>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ScanSignatureConfig {
#[serde(default)]
pub locations: Vec<ProjectLocation>,
#[serde(default)]
pub signatures: Vec<ProjectSignature>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum ConflictType {
Any,
Pvp,
Pve,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ShipInsuranceConfig {
pub conflict_type: ConflictType,
#[serde(default)]
pub identities: Vec<ProjectIdentity>,
#[serde(default)]
pub locations: Vec<ProjectLocation>,
pub reimburse_implants: bool,
#[serde(default)]
pub ships: Vec<TypeOrGroup>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct UnknownProjectConfig {
pub data: Option<serde_json::Value>,
#[serde(rename = "type")]
pub config_type: String,
}
#[derive(Debug, Clone, PartialEq, Default, Deserialize, Serialize)]
pub struct ProjectConfiguration {
pub capture_fw_complex: Option<FwComplexConfig>,
pub damage_ship: Option<ShipActivityConfig>,
pub defend_fw_complex: Option<FwComplexConfig>,
pub deliver_item: Option<DeliverItemConfig>,
pub destroy_npc: Option<LocationsConfig>,
pub destroy_ship: Option<ShipActivityConfig>,
pub earn_loyalty_point: Option<EarnLoyaltyPointConfig>,
pub lost_ship: Option<ShipActivityConfig>,
pub manual: Option<serde_json::Value>,
pub manufacture_item: Option<ManufactureItemConfig>,
pub mine_material: Option<MineMaterialConfig>,
pub remote_boost_shield: Option<ShipActivityConfig>,
pub remote_repair_armor: Option<ShipActivityConfig>,
pub salvage_wreck: Option<LocationsConfig>,
pub scan_signature: Option<ScanSignatureConfig>,
pub ship_insurance: Option<ShipInsuranceConfig>,
pub unknown: Option<UnknownProjectConfig>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ContributionRules {
pub participation_limit: Option<i64>,
pub reward_per_contribution: Option<f64>,
pub submission_limit: Option<i64>,
pub submission_multiplier: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectCreator {
pub id: i64,
pub name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum ProjectCareer {
Unspecified,
Explorer,
Industrialist,
Enforcer,
#[serde(rename = "Soldier of Fortune")]
SoldierOfFortune,
#[serde(other)]
Unrecognized,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectDetails {
pub career: ProjectCareer,
pub created: String,
pub description: String,
pub expires: Option<String>,
pub finished: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Project {
pub configuration: ProjectConfiguration,
pub contribution: Option<ContributionRules>,
pub creator: ProjectCreator,
pub details: ProjectDetails,
pub id: Uuid,
pub last_modified: String,
pub name: String,
pub progress: ProjectProgress,
pub reward: Option<ProjectReward>,
pub state: ProjectState,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectContribution {
pub contributed: i64,
pub last_modified: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ProjectContributor {
pub contributed: i64,
pub id: i64,
pub name: String,
}
impl CorporationProjectsGroup<'_> {
api_get!(
list,
"GetCorporationsProjectsListing",
RequestType::Authenticated,
Page<ProjectSummary>,
(corporation_id: i64) => "{corporation_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit",
Optional(state: ProjectStateFilter) => "state"
);
api_get!(
get_project,
"GetCorporationsProjectsDetail",
RequestType::Authenticated,
Project,
(corporation_id: i64) => "{corporation_id}",
(project_id: Uuid) => "{project_id}"
);
api_get!(
get_contribution,
"GetCorporationsProjectsContribution",
RequestType::Authenticated,
ProjectContribution,
(corporation_id: i64) => "{corporation_id}",
(project_id: Uuid) => "{project_id}",
(character_id: i64) => "{character_id}"
);
api_get!(
list_contributors,
"GetCorporationsProjectsContributors",
RequestType::Authenticated,
Page<ProjectContributor>,
(corporation_id: i64) => "{corporation_id}",
(project_id: Uuid) => "{project_id}";
Optional(after: String) => "after",
Optional(before: String) => "before",
Optional(limit: i64) => "limit"
);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_project_listing() {
let json = r#"{"cursor": {"after": "abc"}, "projects": [
{"id": "6f1d8a5e-0b7c-4d3e-9a2f-1c5b7e9d0a11", "last_modified": "t", "name": "n",
"progress": {"current": 5000000000, "desired": 9000000000},
"reward": {"initial": 1000.5, "remaining": 10.0}, "state": "Active"},
{"id": "6f1d8a5e-0b7c-4d3e-9a2f-1c5b7e9d0a12", "last_modified": "t", "name": "m",
"progress": {"current": 0, "desired": 1}, "state": "Archived"}]}"#;
let page: Page<ProjectSummary> = serde_json::from_str(json).unwrap();
assert_eq!(page.items[0].progress.current, 5_000_000_000);
assert_eq!(page.items[0].state, ProjectState::Active);
assert_eq!(page.items[1].state, ProjectState::Unrecognized);
assert_eq!(page.cursor.unwrap().after.as_deref(), Some("abc"));
}
#[test]
fn test_parse_project_with_each_configuration_shape() {
let base = |config: &str| {
format!(
r#"{{"configuration": {config},
"creator": {{"id": 2124758468, "name": "c"}},
"details": {{"career": "Soldier of Fortune", "created": "t", "description": "d"}},
"id": "6f1d8a5e-0b7c-4d3e-9a2f-1c5b7e9d0a11", "last_modified": "t", "name": "n",
"progress": {{"current": 1, "desired": 2}}, "state": "Closed"}}"#
)
};
let mining: Project = serde_json::from_str(&base(
r#"{"mine_material": {"locations": [{"region_id": 10000002}],
"materials": [{"group_id": 450}]}}"#,
))
.unwrap();
assert_eq!(mining.details.career, ProjectCareer::SoldierOfFortune);
let cfg = mining.configuration.mine_material.unwrap();
assert_eq!(cfg.locations[0].region_id, Some(10000002));
assert_eq!(cfg.materials[0].group_id, Some(450));
let insurance: Project = serde_json::from_str(&base(
r#"{"ship_insurance": {"conflict_type": "Pvp", "reimburse_implants": true}}"#,
))
.unwrap();
assert_eq!(
insurance
.configuration
.ship_insurance
.unwrap()
.conflict_type,
ConflictType::Pvp
);
let manual: Project = serde_json::from_str(&base(r#"{"manual": {}}"#)).unwrap();
assert!(manual.configuration.manual.is_some());
assert!(manual.configuration.mine_material.is_none());
let future: Project = serde_json::from_str(&base(r#"{"teleport_cat": {"x": 1}}"#)).unwrap();
assert_eq!(future.configuration, ProjectConfiguration::default());
}
#[test]
fn test_parse_contribution_and_contributors() {
let c: ProjectContribution = serde_json::from_str(r#"{"contributed": 7}"#).unwrap();
assert_eq!(c.last_modified, None);
let page: Page<ProjectContributor> = serde_json::from_str(
r#"{"contributors": [{"contributed": 3000000000, "id": 1, "name": "x"}]}"#,
)
.unwrap();
assert_eq!(page.items[0].contributed, 3_000_000_000);
assert!(page.cursor.is_none());
}
#[test]
fn test_state_filter_display() {
assert_eq!(ProjectStateFilter::Active.to_string(), "Active");
assert_eq!(ProjectStateFilter::All.to_string(), "All");
}
}