1use crate::prelude::*;
2
3pub struct CharacterGroup<'a> {
5 pub(crate) esi: &'a Esi,
6}
7
8#[derive(Debug, Deserialize)]
9#[allow(missing_docs)]
10pub struct CharacterPublicInfo {
11 pub achievement_score: Option<i64>,
12 pub alliance_id: Option<i64>,
13 pub birthday: String,
14 pub bloodline_id: i64,
15 pub character_title_id: Option<String>,
16 pub corporation_id: i64,
17 pub corporation_title: Option<String>,
18 pub description: Option<String>,
19 pub faction_id: Option<i64>,
20 pub gender: String,
21 pub name: String,
22 pub race_id: i64,
23 pub security_status: Option<f64>,
24}
25
26#[derive(Debug, Deserialize)]
27#[allow(missing_docs)]
28pub struct CharacterCorporationHistoryItem {
29 pub corporation_id: i64,
30 pub is_deleted: Option<bool>,
31 pub record_id: i64,
32 pub start_date: String,
33}
34
35#[derive(Debug, Deserialize)]
36#[allow(missing_docs)]
37pub struct CharacterPortraitInfo {
38 pub px128x128: Option<String>,
39 pub px256x256: Option<String>,
40 pub px512x512: Option<String>,
41 pub px64x64: Option<String>,
42}
43
44#[derive(Debug, Deserialize)]
45#[allow(missing_docs)]
46pub struct CharacterAffiliation {
47 pub alliance_id: Option<i64>,
48 pub character_id: i64,
49 pub corporation_id: i64,
50 pub faction_id: Option<i64>,
51}
52
53#[derive(Debug, Deserialize)]
54#[allow(missing_docs)]
55pub struct Notification {
56 #[serde(default)]
57 pub is_read: bool,
58 pub notification_id: i64,
59 pub sender_id: i64,
60 pub sender_type: String,
61 pub text: Option<String>,
62 pub timestamp: String,
63 #[serde(rename = "type")]
64 pub notification_type: String,
65}
66
67#[derive(Debug, Deserialize)]
68#[allow(missing_docs)]
69pub struct WalletTransaction {
70 pub client_id: i64,
71 pub date: String,
72 pub is_buy: bool,
73 pub is_personal: bool,
74 pub journal_ref_id: i64,
75 pub location_id: i64,
76 pub quantity: i64,
77 pub transaction_id: i64,
78 pub type_id: i64,
79 pub unit_price: f64,
80}
81
82impl CharacterGroup<'_> {
83 api_get!(
84 get_public_info,
86 "GetCharactersDetail",
87 RequestType::Public,
88 CharacterPublicInfo,
89 (character_id: i64) => "{character_id}"
90 );
91
92 api_get!(
93 get_history,
95 "GetCharactersCharacterIdCorporationhistory",
96 RequestType::Public,
97 Vec<CharacterCorporationHistoryItem>,
98 (character_id: i64) => "{character_id}"
99 );
100
101 api_get!(
102 get_portrait,
104 "GetCharactersCharacterIdPortrait",
105 RequestType::Public,
106 CharacterPortraitInfo,
107 (character_id: i64) => "{character_id}"
108 );
109
110 api_post!(
111 get_affiliation,
113 "PostCharactersAffiliation",
114 RequestType::Public,
115 Vec<CharacterAffiliation>,
116 ; Chunked(character_ids: &[i64], 1000)
117 );
118
119 api_get!(
120 get_blueprints,
122 "GetCharactersCharacterIdBlueprints",
123 RequestType::Authenticated,
124 Vec<Blueprint>,
125 (character_id: i64) => "{character_id}"
126 );
127
128 api_get!(
129 get_notifications,
131 "GetCharactersCharacterIdNotifications",
132 RequestType::Authenticated,
133 Vec<Notification>,
134 (character_id: i64) => "{character_id}"
135 );
136
137 api_get!(
138 get_wallet_transactions,
140 "GetCharactersCharacterIdWalletTransactions",
141 RequestType::Authenticated,
142 Vec<WalletTransaction>,
143 (character_id: i64) => "{character_id}"
144 );
145}
146
147#[derive(Debug, Clone, PartialEq, Deserialize)]
149#[allow(missing_docs)]
150pub struct ResearchAgent {
151 pub agent_id: i64,
152 pub points_per_day: f64,
153 pub remainder_points: f64,
154 pub skill_type_id: i64,
155 pub started_at: String,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
160#[allow(missing_docs)]
161pub struct Fatigue {
162 pub jump_fatigue_expire_date: Option<String>,
163 pub last_jump_date: Option<String>,
164 pub last_update_date: Option<String>,
165}
166
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
169#[serde(rename_all = "snake_case")]
170pub enum MedalStatus {
171 Public,
173 Private,
175 #[serde(other)]
177 Unrecognized,
178}
179
180#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
182#[allow(missing_docs)]
183pub struct MedalGraphic {
184 pub color: Option<i64>,
185 pub graphic: String,
186 pub layer: i64,
187 pub part: i64,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
192#[allow(missing_docs)]
193pub struct Medal {
194 pub corporation_id: i64,
195 pub date: String,
196 pub description: String,
197 pub graphics: Vec<MedalGraphic>,
198 pub issuer_id: i64,
200 pub medal_id: i64,
201 pub reason: String,
202 pub status: MedalStatus,
203 pub title: String,
204}
205
206#[derive(Debug, Clone, PartialEq, Deserialize)]
208#[allow(missing_docs)]
209pub struct ContactNotification {
210 pub message: String,
211 pub notification_id: i64,
212 pub send_date: String,
213 pub sender_character_id: i64,
215 pub standing_level: f64,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
220#[allow(missing_docs)]
221pub enum CorporationRole {
222 #[serde(rename = "Account_Take_1")]
223 AccountTake1,
224 #[serde(rename = "Account_Take_2")]
225 AccountTake2,
226 #[serde(rename = "Account_Take_3")]
227 AccountTake3,
228 #[serde(rename = "Account_Take_4")]
229 AccountTake4,
230 #[serde(rename = "Account_Take_5")]
231 AccountTake5,
232 #[serde(rename = "Account_Take_6")]
233 AccountTake6,
234 #[serde(rename = "Account_Take_7")]
235 AccountTake7,
236 #[serde(rename = "Accountant")]
237 Accountant,
238 #[serde(rename = "Auditor")]
239 Auditor,
240 #[serde(rename = "Brand_Manager")]
241 BrandManager,
242 #[serde(rename = "Communications_Officer")]
243 CommunicationsOfficer,
244 #[serde(rename = "Config_Equipment")]
245 ConfigEquipment,
246 #[serde(rename = "Config_Starbase_Equipment")]
247 ConfigStarbaseEquipment,
248 #[serde(rename = "Container_Take_1")]
249 ContainerTake1,
250 #[serde(rename = "Container_Take_2")]
251 ContainerTake2,
252 #[serde(rename = "Container_Take_3")]
253 ContainerTake3,
254 #[serde(rename = "Container_Take_4")]
255 ContainerTake4,
256 #[serde(rename = "Container_Take_5")]
257 ContainerTake5,
258 #[serde(rename = "Container_Take_6")]
259 ContainerTake6,
260 #[serde(rename = "Container_Take_7")]
261 ContainerTake7,
262 #[serde(rename = "Contract_Manager")]
263 ContractManager,
264 #[serde(rename = "Deliveries_Container_Take")]
265 DeliveriesContainerTake,
266 #[serde(rename = "Deliveries_Query")]
267 DeliveriesQuery,
268 #[serde(rename = "Deliveries_Take")]
269 DeliveriesTake,
270 #[serde(rename = "Diplomat")]
271 Diplomat,
272 #[serde(rename = "Director")]
273 Director,
274 #[serde(rename = "Factory_Manager")]
275 FactoryManager,
276 #[serde(rename = "Fitting_Manager")]
277 FittingManager,
278 #[serde(rename = "Hangar_Query_1")]
279 HangarQuery1,
280 #[serde(rename = "Hangar_Query_2")]
281 HangarQuery2,
282 #[serde(rename = "Hangar_Query_3")]
283 HangarQuery3,
284 #[serde(rename = "Hangar_Query_4")]
285 HangarQuery4,
286 #[serde(rename = "Hangar_Query_5")]
287 HangarQuery5,
288 #[serde(rename = "Hangar_Query_6")]
289 HangarQuery6,
290 #[serde(rename = "Hangar_Query_7")]
291 HangarQuery7,
292 #[serde(rename = "Hangar_Take_1")]
293 HangarTake1,
294 #[serde(rename = "Hangar_Take_2")]
295 HangarTake2,
296 #[serde(rename = "Hangar_Take_3")]
297 HangarTake3,
298 #[serde(rename = "Hangar_Take_4")]
299 HangarTake4,
300 #[serde(rename = "Hangar_Take_5")]
301 HangarTake5,
302 #[serde(rename = "Hangar_Take_6")]
303 HangarTake6,
304 #[serde(rename = "Hangar_Take_7")]
305 HangarTake7,
306 #[serde(rename = "Junior_Accountant")]
307 JuniorAccountant,
308 #[serde(rename = "Personnel_Manager")]
309 PersonnelManager,
310 #[serde(rename = "Project_Manager")]
311 ProjectManager,
312 #[serde(rename = "Rent_Factory_Facility")]
313 RentFactoryFacility,
314 #[serde(rename = "Rent_Office")]
315 RentOffice,
316 #[serde(rename = "Rent_Research_Facility")]
317 RentResearchFacility,
318 #[serde(rename = "Security_Officer")]
319 SecurityOfficer,
320 #[serde(rename = "Skill_Plan_Manager")]
321 SkillPlanManager,
322 #[serde(rename = "Starbase_Defense_Operator")]
323 StarbaseDefenseOperator,
324 #[serde(rename = "Starbase_Fuel_Technician")]
325 StarbaseFuelTechnician,
326 #[serde(rename = "Station_Manager")]
327 StationManager,
328 #[serde(rename = "Trader")]
329 Trader,
330 #[serde(other)]
332 Unrecognized,
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
337#[allow(missing_docs)]
338pub struct CharacterRoles {
339 pub roles: Option<Vec<CorporationRole>>,
340 pub roles_at_base: Option<Vec<CorporationRole>>,
341 pub roles_at_hq: Option<Vec<CorporationRole>>,
342 pub roles_at_other: Option<Vec<CorporationRole>>,
343}
344
345#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
347#[serde(rename_all = "snake_case")]
348pub enum StandingSource {
349 Agent,
351 NpcCorp,
353 Faction,
355 #[serde(other)]
357 Unrecognized,
358}
359
360#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
362#[allow(missing_docs)]
363pub struct CharacterTitle {
364 pub name: Option<String>,
365 pub title_id: Option<i64>,
366}
367
368impl CharacterGroup<'_> {
369 api_get!(
370 get_agents_research,
372 "GetCharactersCharacterIdAgentsResearch",
373 RequestType::Authenticated,
374 Vec<ResearchAgent>,
375 (character_id: i64) => "{character_id}"
376 );
377
378 api_get!(
379 get_fatigue,
381 "GetCharactersCharacterIdFatigue",
382 RequestType::Authenticated,
383 Fatigue,
384 (character_id: i64) => "{character_id}"
385 );
386
387 api_get!(
388 get_medals,
390 "GetCharactersCharacterIdMedals",
391 RequestType::Authenticated,
392 Vec<Medal>,
393 (character_id: i64) => "{character_id}"
394 );
395
396 api_get!(
397 get_contact_notifications,
399 "GetCharactersCharacterIdNotificationsContacts",
400 RequestType::Authenticated,
401 Vec<ContactNotification>,
402 (character_id: i64) => "{character_id}"
403 );
404
405 api_get!(
406 get_roles,
408 "GetCharactersCharacterIdRoles",
409 RequestType::Authenticated,
410 CharacterRoles,
411 (character_id: i64) => "{character_id}"
412 );
413
414 api_get!(
415 get_standings,
417 "GetCharactersCharacterIdStandings",
418 RequestType::Authenticated,
419 Vec<Standing>,
420 (character_id: i64) => "{character_id}"
421 );
422
423 api_get!(
424 get_titles,
426 "GetCharactersCharacterIdTitles",
427 RequestType::Authenticated,
428 Vec<CharacterTitle>,
429 (character_id: i64) => "{character_id}"
430 );
431
432 api_post!(
433 calculate_cspa_charge,
436 "PostCharactersCharacterIdCspa",
437 RequestType::Authenticated,
438 f64,
439 (character_id: i64) => "{character_id}",
440 characters: &[i64],
441 );
442}
443
444#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
446pub struct Blueprint {
447 pub item_id: i64,
449 pub location_flag: String,
451 pub location_id: i64,
453 pub material_efficiency: i64,
455 pub quantity: i64,
457 pub runs: i64,
459 pub time_efficiency: i64,
461 pub type_id: i64,
463}
464
465#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
467pub struct Standing {
468 pub from_id: i64,
470 pub from_type: StandingSource,
472 pub standing: f64,
474}
475
476#[cfg(test)]
477mod character_basic_tests {
478 use super::{CharacterRoles, CorporationRole, Medal, MedalStatus, Standing, StandingSource};
479
480 #[test]
481 fn test_parse_roles_with_unknown_role() {
482 let json =
483 r#"{"roles": ["Director", "Account_Take_1", "Brand_New_Role"], "roles_at_hq": []}"#;
484 let roles: CharacterRoles = serde_json::from_str(json).unwrap();
485 let list = roles.roles.unwrap();
486 assert_eq!(list[0], CorporationRole::Director);
487 assert_eq!(list[1], CorporationRole::AccountTake1);
488 assert_eq!(list[2], CorporationRole::Unrecognized);
489 assert!(roles.roles_at_base.is_none());
490 }
491
492 #[test]
493 fn test_parse_standing() {
494 let standing: Standing = serde_json::from_str(
495 r#"{"from_id": 500001, "from_type": "npc_corp", "standing": 1.5}"#,
496 )
497 .unwrap();
498 assert_eq!(standing.from_type, StandingSource::NpcCorp);
499 }
500
501 #[test]
502 fn test_parse_medal() {
503 let json = r#"{"corporation_id": 1, "date": "2026-01-01T00:00:00Z", "description": "d",
504 "graphics": [{"graphic": "g", "layer": 0, "part": 1}], "issuer_id": 2112625428,
505 "medal_id": 7, "reason": "r", "status": "private", "title": "t"}"#;
506 let medal: Medal = serde_json::from_str(json).unwrap();
507 assert_eq!(medal.status, MedalStatus::Private);
508 assert!(medal.graphics[0].color.is_none());
509 }
510}