1use crate::groups::Page;
2use crate::prelude::*;
3use uuid::Uuid;
4
5pub struct MilitaryCampaignsGroup<'a> {
7 pub(crate) esi: &'a Esi,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
12pub enum CampaignState {
13 Unspecified,
15 Active,
17 Completed,
19 Expired,
21 #[serde(other)]
23 Unrecognized,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
28#[allow(missing_docs)]
29pub struct Campaign {
30 pub finished: Option<String>,
31 pub id: Uuid,
32 pub progress: i64,
33 pub started: Option<String>,
34 pub state: CampaignState,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
39#[allow(missing_docs)]
40pub struct ObjectiveParticipants {
41 pub committed: i64,
42 pub contributors: i64,
43 pub total: i64,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
48#[allow(missing_docs)]
49pub struct Objective {
50 pub finished: Option<String>,
51 pub id: Uuid,
52 pub last_modified: String,
53 pub participants: ObjectiveParticipants,
54 pub progress: i64,
55 pub started: Option<String>,
56 pub state: CampaignState,
57}
58
59#[derive(Debug, Deserialize)]
60struct CampaignList {
61 campaigns: Vec<Campaign>,
62}
63
64impl MilitaryCampaignsGroup<'_> {
65 pub async fn list(&self) -> EsiResult<Vec<Campaign>> {
67 let path = self
68 .esi
69 .get_endpoint_for_op_id("GetMilitaryCampaignsListing")?;
70 let wrapper: CampaignList = self
71 .esi
72 .query("GET", RequestType::Public, &path, None, None)
73 .await?;
74 Ok(wrapper.campaigns)
75 }
76
77 api_get!(
78 get_campaign,
80 "GetMilitaryCampaignsDetail",
81 RequestType::Public,
82 Campaign,
83 (campaign_id: Uuid) => "{campaign_id}"
84 );
85
86 api_get!(
87 list_objectives,
90 "GetMilitaryCampaignsObjectivesListing",
91 RequestType::Public,
92 Page<Objective>,
93 (campaign_id: Uuid) => "{campaign_id}";
94 Optional(after: String) => "after",
95 Optional(before: String) => "before",
96 Optional(limit: i64) => "limit"
97 );
98
99 api_get!(
100 get_objective,
102 "GetMilitaryCampaignsObjectivesDetail",
103 RequestType::Public,
104 Objective,
105 (campaign_id: Uuid) => "{campaign_id}",
106 (objective_id: Uuid) => "{objective_id}"
107 );
108}
109
110#[cfg(test)]
111mod tests {
112 use super::{Campaign, CampaignState};
113 use crate::groups::{Objective, Page};
114
115 #[test]
116 fn test_parse_campaign() {
117 let json =
118 r#"{"id": "3868eaed-8278-4cb7-9709-7d7de9c20dc7", "progress": 40, "state": "Active"}"#;
119 let campaign: Campaign = serde_json::from_str(json).unwrap();
120 assert_eq!(campaign.state, CampaignState::Active);
121 assert!(campaign.started.is_none());
122 }
123
124 #[test]
125 fn test_parse_objectives_page_without_cursor() {
126 let json = r#"{"objectives": [{
127 "id": "3868eaed-8278-4cb7-9709-7d7de9c20dc7",
128 "last_modified": "2026-10-01T00:00:00Z",
129 "participants": {"committed": 1, "contributors": 2, "total": 3},
130 "progress": 5, "state": "Completed"
131 }]}"#;
132 let page: Page<Objective> = serde_json::from_str(json).unwrap();
133 assert!(page.cursor.is_none());
134 assert_eq!(page.items[0].participants.total, 3);
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
140#[allow(missing_docs)]
141pub struct CharacterObjective {
142 pub campaign_id: Uuid,
143 pub contributed: i64,
144 pub id: Uuid,
145 pub is_committed: bool,
146 pub last_modified: String,
147}
148
149impl MilitaryCampaignsGroup<'_> {
150 api_get!(
151 list_character_objectives,
153 "GetCharactersMilitaryCampaignsObjectivesListing",
154 RequestType::Authenticated,
155 Page<CharacterObjective>,
156 (character_id: i64) => "{character_id}";
157 Optional(after: String) => "after",
158 Optional(before: String) => "before",
159 Optional(limit: i64) => "limit"
160 );
161
162 api_get!(
163 get_character_objective,
165 "GetCharactersMilitaryCampaignsObjectivesParticipation",
166 RequestType::Authenticated,
167 CharacterObjective,
168 (character_id: i64) => "{character_id}",
169 (objective_id: Uuid) => "{objective_id}"
170 );
171}