1#![allow(unused)]
2
3use crate::prelude::*;
4
5pub struct MailGroup<'a> {
7 pub(crate) esi: &'a Esi,
8}
9
10#[derive(Debug, Deserialize, Serialize, Clone)]
11pub struct MailLabels {
13 #[serde(default)]
15 pub labels: Vec<MailLabel>,
16 pub total_unread_count: Option<i64>,
18}
19
20#[derive(Debug, Deserialize, Serialize, Clone)]
21pub struct MailLabel {
23 pub color: String,
25 pub label_id: i64,
27 pub name: String,
29 #[serde(default)]
31 pub unread_count: Option<i64>,
32}
33
34#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
35pub enum RecipientType {
37 #[serde(rename = "alliance")]
39 Alliance,
40 #[serde(rename = "character")]
42 Character,
43 #[serde(rename = "corporation")]
45 Corporation,
46 #[serde(rename = "mailing_list")]
48 MailingList,
49 #[serde(other)]
51 Unrecognized,
52}
53
54#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
55pub struct MailRecipient {
57 pub recipient_id: i64,
59 pub recipient_type: RecipientType,
61}
62
63#[derive(Debug, Deserialize, Serialize, Clone)]
64pub struct MailHeader {
66 pub from: Option<i64>,
68 pub is_read: Option<bool>,
70 #[serde(default)]
72 pub labels: Vec<i64>,
73 pub mail_id: Option<i64>,
75 #[serde(default)]
77 pub recipients: Vec<MailRecipient>,
78 pub subject: Option<String>,
80 pub timestamp: Option<String>,
82}
83
84#[derive(Debug, Deserialize, Serialize, Clone)]
85pub struct Mail {
87 pub body: Option<String>,
89 pub from: Option<i64>,
91 #[serde(default)]
93 pub labels: Vec<i64>,
94 pub read: Option<bool>,
96 #[serde(default)]
98 pub recipients: Vec<MailRecipient>,
99 pub subject: Option<String>,
101 pub timestamp: Option<String>,
103}
104
105#[derive(Debug, Serialize, Clone)]
106pub struct NewMail {
108 pub body: String,
110 pub recipients: Vec<MailRecipient>,
112 pub subject: String,
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub approved_cost: Option<i64>,
117}
118
119#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
120pub enum MailLabelColor {
122 #[serde(rename = "#0000fe")]
124 Blue,
125 #[serde(rename = "#006634")]
127 DarkGreen,
128 #[serde(rename = "#0099ff")]
130 LightBlue,
131 #[serde(rename = "#00ff33")]
133 BrightGreen,
134 #[serde(rename = "#01ffff")]
136 Cyan,
137 #[serde(rename = "#349800")]
139 Green,
140 #[serde(rename = "#660066")]
142 Purple,
143 #[serde(rename = "#666666")]
145 DarkGrey,
146 #[serde(rename = "#999999")]
148 Grey,
149 #[serde(rename = "#99ffff")]
151 PaleCyan,
152 #[serde(rename = "#9a0000")]
154 DarkRed,
155 #[serde(rename = "#ccff9a")]
157 PaleGreen,
158 #[serde(rename = "#e6e6e6")]
160 LightGrey,
161 #[serde(rename = "#fe0000")]
163 Red,
164 #[serde(rename = "#ff6600")]
166 Orange,
167 #[serde(rename = "#ffff01")]
169 Yellow,
170 #[serde(rename = "#ffffcd")]
172 PaleYellow,
173 #[serde(rename = "#ffffff")]
175 White,
176 #[serde(other)]
178 Unrecognized,
179}
180
181#[derive(Debug, Serialize, Clone)]
182pub struct NewMailLabel {
184 pub name: String,
186 #[serde(skip_serializing_if = "Option::is_none")]
188 pub color: Option<MailLabelColor>,
189}
190
191#[derive(Debug, Serialize, Clone, Default)]
192pub struct MailUpdate {
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub labels: Option<Vec<i64>>,
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub read: Option<bool>,
200}
201
202#[derive(Debug, Deserialize, Serialize, Clone)]
203pub struct MailingList {
205 pub mailing_list_id: i64,
207 pub name: String,
209}
210
211impl MailGroup<'_> {
212 api_get!(
213 get_character_mail,
218 "GetCharactersCharacterIdMail",
219 RequestType::Authenticated,
220 Vec<MailHeader>,
221 (character_id: i64) => "{character_id}";
222 OptionalMany(labels: &[i64]) => "labels",
223 Optional(last_mail_id: i64) => "last_mail_id"
224 );
225
226 api_post!(
227 send_character_mail,
229 "PostCharactersCharacterIdMail",
230 RequestType::Authenticated,
231 i64,
232 (character_id: i64) => "{character_id}",
233 mail: &NewMail,
234 );
235
236 api_get!(
237 get_character_mail_labels,
240 "GetCharactersCharacterIdMailLabels",
241 RequestType::Authenticated,
242 MailLabels,
243 (character_id: i64) => "{character_id}"
244 );
245
246 api_post!(
247 create_character_mail_label,
249 "PostCharactersCharacterIdMailLabels",
250 RequestType::Authenticated,
251 i64,
252 (character_id: i64) => "{character_id}",
253 label: &NewMailLabel,
254 );
255
256 api_delete!(
257 delete_character_mail_label,
259 "DeleteCharactersCharacterIdMailLabelsLabelId",
260 RequestType::Authenticated,
261 (),
262 (character_id: i64) => "{character_id}",
263 (label_id: i64) => "{label_id}"
264 );
265
266 api_get!(
267 get_character_mailing_lists,
269 "GetCharactersCharacterIdMailLists",
270 RequestType::Authenticated,
271 Vec<MailingList>,
272 (character_id: i64) => "{character_id}"
273 );
274
275 api_delete!(
276 delete_character_mail,
278 "DeleteCharactersCharacterIdMailMailId",
279 RequestType::Authenticated,
280 (),
281 (character_id: i64) => "{character_id}",
282 (mail_id: i64) => "{mail_id}"
283 );
284
285 api_get!(
286 get_character_mail_by_id,
288 "GetCharactersCharacterIdMailMailId",
289 RequestType::Authenticated,
290 Mail,
291 (character_id: i64) => "{character_id}",
292 (mail_id: i64) => "{mail_id}"
293 );
294
295 api_put!(
296 update_character_mail,
298 "PutCharactersCharacterIdMailMailId",
299 RequestType::Authenticated,
300 (),
301 (character_id: i64) => "{character_id}",
302 (mail_id: i64) => "{mail_id}",
303 update: &MailUpdate,
304 );
305}
306
307#[cfg(test)]
308mod mail_tests {
309 use super::*;
310
311 #[test]
312 fn test_parse_mail_header_and_unknown_recipient() {
313 let json = r#"[{"from": 2112625428, "is_read": true, "labels": [3, 9000000000],
314 "mail_id": 7000000000, "subject": "Hi", "timestamp": "2026-10-01T00:00:00Z",
315 "recipients": [{"recipient_id": 1, "recipient_type": "mailing_list"},
316 {"recipient_id": 2, "recipient_type": "something_new"}]}]"#;
317 let headers: Vec<MailHeader> = serde_json::from_str(json).unwrap();
318 assert_eq!(headers[0].mail_id, Some(7_000_000_000));
319 assert_eq!(
320 headers[0].recipients[0].recipient_type,
321 RecipientType::MailingList
322 );
323 assert_eq!(
324 headers[0].recipients[1].recipient_type,
325 RecipientType::Unrecognized
326 );
327 }
328
329 #[test]
330 fn test_serialize_new_mail_and_label() {
331 let mail = NewMail {
332 body: "b".into(),
333 recipients: vec![MailRecipient {
334 recipient_id: 1,
335 recipient_type: RecipientType::Character,
336 }],
337 subject: "s".into(),
338 approved_cost: None,
339 };
340 let v = serde_json::to_value(&mail).unwrap();
341 assert_eq!(v["recipients"][0]["recipient_type"], "character");
342 assert!(v.get("approved_cost").is_none());
343 let label = NewMailLabel {
344 name: "x".into(),
345 color: Some(MailLabelColor::Red),
346 };
347 assert_eq!(serde_json::to_value(&label).unwrap()["color"], "#fe0000");
348 let upd = MailUpdate {
349 labels: None,
350 read: Some(true),
351 };
352 assert_eq!(serde_json::to_string(&upd).unwrap(), r#"{"read":true}"#);
353 }
354
355 #[test]
356 fn test_parse_mail_and_lists() {
357 let m: Mail = serde_json::from_str(r#"{"body": "x", "from": 1, "read": false}"#).unwrap();
358 assert_eq!(m.read, Some(false));
359 let l: Vec<MailingList> =
360 serde_json::from_str(r#"[{"mailing_list_id": 5000000000, "name": "n"}]"#).unwrap();
361 assert_eq!(l[0].mailing_list_id, 5_000_000_000);
362 }
363}