1use crate::groups::Page;
2use crate::prelude::*;
3use uuid::Uuid;
4
5pub struct FreelanceJobsGroup<'a> {
7 pub(crate) esi: &'a Esi,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
12pub enum JobState {
13 Unspecified,
15 Active,
17 Closed,
19 Completed,
21 Expired,
23 Deleted,
25 #[serde(other)]
27 Unrecognized,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
32pub enum JobCareer {
33 Unspecified,
35 Explorer,
37 Industrialist,
39 Enforcer,
41 #[serde(rename = "Soldier of Fortune")]
43 SoldierOfFortune,
44 #[serde(other)]
46 Unrecognized,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
51#[allow(missing_docs)]
52pub struct JobProgress {
53 pub current: i64,
54 pub desired: i64,
55}
56
57#[derive(Debug, Clone, PartialEq, Deserialize)]
59#[allow(missing_docs)]
60pub struct JobReward {
61 pub initial: f64,
62 pub remaining: f64,
63}
64
65#[derive(Debug, Clone, PartialEq, Deserialize)]
67#[allow(missing_docs)]
68pub struct FreelanceJobSummary {
69 pub id: Uuid,
70 pub last_modified: String,
71 pub name: String,
72 pub progress: JobProgress,
73 pub reward: Option<JobReward>,
74 pub state: JobState,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
79#[allow(missing_docs)]
80pub struct BroadcastLocation {
81 pub id: i64,
83 pub name: String,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
88#[allow(missing_docs)]
89pub struct JobRestrictions {
90 pub maximum_age: Option<i64>,
91 pub minimum_age: Option<i64>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
96#[allow(missing_docs)]
97pub struct AccessAndVisibility {
98 pub acl_protected: bool,
99 pub broadcast_locations: Option<Vec<BroadcastLocation>>,
100 pub restrictions: Option<JobRestrictions>,
101}
102
103#[derive(Debug, Clone, PartialEq, Deserialize)]
105#[allow(missing_docs)]
106pub struct JobConfiguration {
107 pub method: String,
108 pub parameters: serde_json::Value,
109 pub version: i64,
110}
111
112#[derive(Debug, Clone, PartialEq, Deserialize)]
114#[allow(missing_docs)]
115pub struct JobContribution {
116 pub contribution_per_participant_limit: Option<i64>,
117 pub max_committed_participants: i64,
118 pub reward_per_contribution: Option<f64>,
119 pub submission_limit: Option<i64>,
120 pub submission_multiplier: Option<f64>,
121}
122
123#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
125#[allow(missing_docs)]
126pub struct JobCreatorCharacter {
127 pub id: i64,
128 pub name: String,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
133#[allow(missing_docs)]
134pub struct JobCreatorCorporation {
135 pub id: i64,
136 pub name: String,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
141#[allow(missing_docs)]
142pub struct JobCreator {
143 pub character: JobCreatorCharacter,
144 pub corporation: JobCreatorCorporation,
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
149#[allow(missing_docs)]
150pub struct JobDetails {
151 pub career: JobCareer,
152 pub created: String,
153 pub creator: JobCreator,
154 pub description: String,
155 pub expires: Option<String>,
156 pub finished: Option<String>,
157}
158
159#[derive(Debug, Clone, PartialEq, Deserialize)]
161#[allow(missing_docs)]
162pub struct FreelanceJob {
163 pub access_and_visibility: AccessAndVisibility,
164 pub configuration: JobConfiguration,
165 pub contribution: Option<JobContribution>,
166 pub details: JobDetails,
167 pub id: Uuid,
168 pub last_modified: String,
169 pub name: String,
170 pub progress: JobProgress,
171 pub reward: Option<JobReward>,
172 pub state: JobState,
173}
174
175impl FreelanceJobsGroup<'_> {
176 api_get!(
177 list,
180 "GetFreelanceJobsListing",
181 RequestType::Public,
182 Page<FreelanceJobSummary>,
183 ;
184 Optional(after: String) => "after",
185 Optional(before: String) => "before",
186 Optional(limit: i64) => "limit",
187 Optional(corporation_id: i64) => "corporation_id"
188 );
189
190 api_get!(
191 get_job,
193 "GetFreelanceJobsDetail",
194 RequestType::Public,
195 FreelanceJob,
196 (job_id: Uuid) => "{job_id}"
197 );
198}
199
200#[cfg(test)]
201mod tests {
202 use super::JobState;
203 use crate::groups::{FreelanceJobSummary, Page};
204
205 #[test]
206 fn test_parse_page_with_unknown_state() {
207 let json = r#"{
208 "cursor": {"after": "abc"},
209 "freelance_jobs": [{
210 "id": "3868eaed-8278-4cb7-9709-7d7de9c20dc7",
211 "last_modified": "2026-10-01T00:00:00Z",
212 "name": "Haul",
213 "progress": {"current": 1, "desired": 10},
214 "state": "Archived"
215 }]
216 }"#;
217 let page: Page<FreelanceJobSummary> = serde_json::from_str(json).unwrap();
218 assert_eq!(page.items[0].state, JobState::Unrecognized);
219 assert!(page.items[0].reward.is_none());
220 assert_eq!(page.cursor.unwrap().after.as_deref(), Some("abc"));
221 }
222}
223
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
226pub enum ParticipationState {
227 Unspecified,
229 Committed,
231 Kicked,
233 Resigned,
235 #[serde(other)]
237 Unrecognized,
238}
239
240#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
242#[allow(missing_docs)]
243pub struct JobParticipation {
244 pub contributed: i64,
245 pub last_modified: String,
246 pub state: ParticipationState,
247}
248
249#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
251#[allow(missing_docs)]
252pub struct JobParticipant {
253 pub contributed: i64,
254 pub id: i64,
256 pub name: String,
257 pub state: ParticipationState,
258}
259
260#[derive(Debug, Deserialize)]
261struct CharacterFreelanceJobs {
262 freelance_jobs: Vec<FreelanceJobSummary>,
263}
264
265impl FreelanceJobsGroup<'_> {
266 pub async fn get_character_jobs(
268 &self,
269 character_id: i64,
270 ) -> EsiResult<Vec<FreelanceJobSummary>> {
271 let path = self
272 .esi
273 .get_endpoint_for_op_id("GetCharactersFreelanceJobsListing")?
274 .replace("{character_id}", &character_id.to_string());
275 let wrapper: CharacterFreelanceJobs = self
276 .esi
277 .query("GET", RequestType::Authenticated, &path, None, None)
278 .await?;
279 Ok(wrapper.freelance_jobs)
280 }
281
282 api_get!(
283 get_character_participation,
285 "GetCharactersFreelanceJobsParticipation",
286 RequestType::Authenticated,
287 JobParticipation,
288 (character_id: i64) => "{character_id}",
289 (job_id: Uuid) => "{job_id}"
290 );
291
292 api_get!(
293 list_corporation_jobs,
295 "GetCorporationsFreelanceJobsListing",
296 RequestType::Authenticated,
297 Page<FreelanceJobSummary>,
298 (corporation_id: i64) => "{corporation_id}";
299 Optional(after: String) => "after",
300 Optional(before: String) => "before",
301 Optional(limit: i64) => "limit"
302 );
303
304 api_get!(
305 list_corporation_job_participants,
307 "GetCorporationsFreelanceJobsParticipants",
308 RequestType::Authenticated,
309 Page<JobParticipant>,
310 (corporation_id: i64) => "{corporation_id}",
311 (job_id: Uuid) => "{job_id}";
312 Optional(after: String) => "after",
313 Optional(before: String) => "before",
314 Optional(limit: i64) => "limit"
315 );
316}