Skip to main content

esi_openapi/groups/
character.rs

1use crate::prelude::*;
2
3/// Endpoints for Character
4pub 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 a character's public information.
85        get_public_info,
86        "GetCharactersDetail",
87        RequestType::Public,
88        CharacterPublicInfo,
89        (character_id: i64) => "{character_id}"
90    );
91
92    api_get!(
93        /// Get a character's corporation history.
94        get_history,
95        "GetCharactersCharacterIdCorporationhistory",
96        RequestType::Public,
97        Vec<CharacterCorporationHistoryItem>,
98        (character_id: i64) => "{character_id}"
99    );
100
101    api_get!(
102        /// Get a character's portrait URLs on the image server.
103        get_portrait,
104        "GetCharactersCharacterIdPortrait",
105        RequestType::Public,
106        CharacterPortraitInfo,
107        (character_id: i64) => "{character_id}"
108    );
109
110    api_post!(
111        /// Get character affiliations.
112        get_affiliation,
113        "PostCharactersAffiliation",
114        RequestType::Public,
115        Vec<CharacterAffiliation>,
116        ; Chunked(character_ids: &[i64], 1000)
117    );
118
119    api_get!(
120        /// Get character blueprints.
121        get_blueprints,
122        "GetCharactersCharacterIdBlueprints",
123        RequestType::Authenticated,
124        Vec<Blueprint>,
125        (character_id: i64) => "{character_id}"
126    );
127
128    api_get!(
129        /// Get character notifications.
130        get_notifications,
131        "GetCharactersCharacterIdNotifications",
132        RequestType::Authenticated,
133        Vec<Notification>,
134        (character_id: i64) => "{character_id}"
135    );
136
137    api_get!(
138        /// Get character wallet transactions.
139        get_wallet_transactions,
140        "GetCharactersCharacterIdWalletTransactions",
141        RequestType::Authenticated,
142        Vec<WalletTransaction>,
143        (character_id: i64) => "{character_id}"
144    );
145}
146
147/// A research agent a character works with.
148#[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/// Jump fatigue of a character.
159#[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/// Whether a medal is visible to everyone.
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
169#[serde(rename_all = "snake_case")]
170pub enum MedalStatus {
171    /// Visible to everyone.
172    Public,
173    /// Visible only to the owner.
174    Private,
175    /// A status this version of the crate does not know about.
176    #[serde(other)]
177    Unrecognized,
178}
179
180/// A layer of a medal's artwork.
181#[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/// A medal awarded to a character.
191#[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    /// Character ID of the issuer.
199    pub issuer_id: i64,
200    pub medal_id: i64,
201    pub reason: String,
202    pub status: MedalStatus,
203    pub title: String,
204}
205
206/// A notification about a change in contact standings.
207#[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    /// Character ID of the sender.
214    pub sender_character_id: i64,
215    pub standing_level: f64,
216}
217
218/// A corporation role.
219#[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    /// A role this version of the crate does not know about.
331    #[serde(other)]
332    Unrecognized,
333}
334
335/// The corporation roles of a character.
336#[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/// Where a standing comes from.
346#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
347#[serde(rename_all = "snake_case")]
348pub enum StandingSource {
349    /// An agent.
350    Agent,
351    /// An NPC corporation.
352    NpcCorp,
353    /// A faction.
354    Faction,
355    /// A source this version of the crate does not know about.
356    #[serde(other)]
357    Unrecognized,
358}
359
360/// A corporation title held by a character.
361#[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        /// List the research agents of a character.
371        get_agents_research,
372        "GetCharactersCharacterIdAgentsResearch",
373        RequestType::Authenticated,
374        Vec<ResearchAgent>,
375        (character_id: i64) => "{character_id}"
376    );
377
378    api_get!(
379        /// Get a character's jump fatigue.
380        get_fatigue,
381        "GetCharactersCharacterIdFatigue",
382        RequestType::Authenticated,
383        Fatigue,
384        (character_id: i64) => "{character_id}"
385    );
386
387    api_get!(
388        /// List the medals of a character.
389        get_medals,
390        "GetCharactersCharacterIdMedals",
391        RequestType::Authenticated,
392        Vec<Medal>,
393        (character_id: i64) => "{character_id}"
394    );
395
396    api_get!(
397        /// List the contact standing change notifications of a character.
398        get_contact_notifications,
399        "GetCharactersCharacterIdNotificationsContacts",
400        RequestType::Authenticated,
401        Vec<ContactNotification>,
402        (character_id: i64) => "{character_id}"
403    );
404
405    api_get!(
406        /// Get the corporation roles of a character.
407        get_roles,
408        "GetCharactersCharacterIdRoles",
409        RequestType::Authenticated,
410        CharacterRoles,
411        (character_id: i64) => "{character_id}"
412    );
413
414    api_get!(
415        /// List the standings of a character with agents, NPC corporations and factions.
416        get_standings,
417        "GetCharactersCharacterIdStandings",
418        RequestType::Authenticated,
419        Vec<Standing>,
420        (character_id: i64) => "{character_id}"
421    );
422
423    api_get!(
424        /// List the corporation titles of a character.
425        get_titles,
426        "GetCharactersCharacterIdTitles",
427        RequestType::Authenticated,
428        Vec<CharacterTitle>,
429        (character_id: i64) => "{character_id}"
430    );
431
432    api_post!(
433        /// Calculate the CONCORD spam (CSPA) charge for contacting the given characters.
434        /// Returns the charge in ISK.
435        calculate_cspa_charge,
436        "PostCharactersCharacterIdCspa",
437        RequestType::Authenticated,
438        f64,
439        (character_id: i64) => "{character_id}",
440        characters: &[i64],
441    );
442}
443
444/// A blueprint owned by a character or a corporation.
445#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
446pub struct Blueprint {
447    /// ID of the item.
448    pub item_id: i64,
449    /// Where the blueprint is (see the ESI location flags).
450    pub location_flag: String,
451    /// ID of the location.
452    pub location_id: i64,
453    /// Material efficiency level.
454    pub material_efficiency: i64,
455    /// Quantity; `-1` for originals, `-2` for copies.
456    pub quantity: i64,
457    /// Remaining runs; `-1` for originals.
458    pub runs: i64,
459    /// Time efficiency level.
460    pub time_efficiency: i64,
461    /// Type ID of the blueprint.
462    pub type_id: i64,
463}
464
465/// A standing a character or a corporation has with an agent, NPC corporation or faction.
466#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
467pub struct Standing {
468    /// ID of the entity the standing comes from.
469    pub from_id: i64,
470    /// Kind of that entity.
471    pub from_type: StandingSource,
472    /// Standing, from -10.0 to 10.0.
473    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}