linkedin_api/
types.rs

1use std::str::FromStr;
2
3use email_address::EmailAddress;
4use isolang;
5use my_country::Country;
6use phonenumber::PhoneNumber;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_json::Value;
9use time::Month;
10use url::Url;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct Locale {
14    pub country: Country,
15    pub language: isolang::Language,
16}
17
18pub struct Identity {
19    pub authentication_token: String,
20    pub session_cookie: String,
21}
22
23/// The complete LinkedIn profile view structure
24#[derive(Debug, Clone, Serialize, Deserialize)]
25#[serde(rename_all = "camelCase")]
26pub struct ProfileView {
27    pub certification_view: CertificationView,
28    pub course_view: CourseView,
29    pub education_view: EducationView,
30    pub entity_urn: Option<String>,
31    pub honor_view: HonorView,
32    pub language_view: LanguageView,
33    pub organization_view: OrganizationView,
34    pub patent_view: PatentView,
35    pub position_group_view: PositionGroupView,
36    pub position_view: PositionView,
37    pub primary_locale: Locale,
38    pub profile: Profile,
39    pub project_view: ProjectView,
40    pub publication_view: PublicationView,
41    pub skill_view: SkillView,
42    pub summary_treasury_media_count: u32,
43    pub summary_treasury_medias: Vec<Value>,
44    pub test_score_view: TestScoreView,
45    pub volunteer_cause_view: VolunteerCauseView,
46    pub volunteer_experience_view: VolunteerExperienceView,
47    #[serde(skip)]
48    pub skills: Vec<Skill>,
49}
50
51/// Strongly-typed name structure
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub struct PersonName {
54    pub first: String,
55    pub last: String,
56}
57
58impl PersonName {
59    pub fn full_name(&self) -> String {
60        format!("{} {}", self.first, self.last)
61    }
62}
63
64#[derive(Debug, Clone, PartialEq, Serialize)]
65pub struct Address {
66    pub raw: String,
67    pub street: Option<String>,
68    pub city: Option<String>,
69    pub state: Option<String>,
70    pub country: Option<Country>,
71    pub postal_code: Option<String>,
72}
73
74impl Address {
75    pub fn parse(raw_address: &str) -> Self {
76        let parts: Vec<&str> = raw_address.split(',').map(|s| s.trim()).collect();
77        Self {
78            raw: raw_address.to_string(),
79            street: parts.get(0).map(|s| s.to_string()),
80            city: parts.get(1).map(|s| s.to_string()),
81            state: parts.get(2).map(|s| s.to_string()),
82            country: None,     // Cannot be derived from a simple string parse
83            postal_code: None, // Cannot be derived from a simple string parse
84        }
85    }
86}
87
88// Custom deserializer for Address
89impl<'de> Deserialize<'de> for Address {
90    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91    where
92        D: Deserializer<'de>,
93    {
94        let raw = String::deserialize(deserializer)?;
95        Ok(Address::parse(&raw))
96    }
97}
98
99/// Enhanced Profile with all fields from JSON
100#[derive(Debug, Clone, Serialize, Deserialize)]
101#[serde(rename_all = "camelCase")]
102pub struct Profile {
103    pub entity_urn: Option<String>,
104
105    pub first_name: Option<String>,
106    pub last_name: Option<String>,
107    pub headline: Option<String>,
108    pub summary: Option<String>,
109
110    pub industry_name: Option<String>,
111    pub industry_urn: Option<String>,
112
113    pub geo_country_name: Option<String>,
114    pub geo_country_urn: Option<String>,
115    pub geo_location_name: Option<String>,
116    pub geo_location_backfilled: Option<bool>,
117    pub geo_location: Option<GeoLocation>,
118
119    pub address: Option<Address>,
120    pub birth_date: Option<BirthDate>,
121
122    pub default_locale: Option<Locale>,
123    pub supported_locales: Option<Vec<Locale>>,
124
125    pub location: Option<Location>,
126    pub location_name: Option<String>,
127
128    pub mini_profile: Option<MiniProfile>,
129    pub profile_picture: Option<ProfilePicture>,
130    pub profile_picture_original_image: Option<VectorImageContainer>,
131
132    pub show_education_on_profile_top_card: Option<bool>,
133    pub student: Option<bool>,
134    pub elt: Option<bool>,
135
136    pub version_tag: Option<String>,
137
138    #[serde(skip)]
139    pub profile_id: String,
140
141    #[serde(skip)]
142    pub contact: ContactInfo,
143}
144
145impl Profile {
146    /// Helper method to get full name
147    pub fn get_full_name(&self) -> Option<String> {
148        match (&self.first_name, &self.last_name) {
149            (Some(first), Some(last)) => Some(format!("{} {}", first, last)),
150            (Some(first), None) => Some(first.clone()),
151            (None, Some(last)) => Some(last.clone()),
152            (None, None) => None,
153        }
154    }
155
156    /// Helper method to get profile image URL
157    pub fn get_profile_image_url(&self) -> Option<Url> {
158        self.profile_picture_original_image
159            .as_ref()
160            .and_then(|container| container.vector_image.as_ref())
161            .and_then(|vector_image| {
162                if let (Some(root_url), Some(artifact)) =
163                    (&vector_image.root_url, vector_image.artifacts.first())
164                {
165                    let full_url = format!(
166                        "{}{}",
167                        root_url,
168                        artifact
169                            .file_identifying_url_path_segment
170                            .as_deref()
171                            .unwrap_or("")
172                    );
173                    Url::parse(&full_url).ok()
174                } else {
175                    None
176                }
177            })
178    }
179
180    /// Get profile ID from entity URN
181    pub fn get_profile_id(&self) -> Option<String> {
182        self.entity_urn
183            .as_ref()
184            .and_then(|urn| urn.split(':').last().map(|id| id.to_string()))
185    }
186}
187
188#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
189pub struct GeoLocation {
190    pub geo_urn: Option<String>,
191    pub postal_code: Option<String>,
192}
193
194#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
195pub struct BirthDate {
196    pub day: Option<u8>,
197    pub month: Option<Month>,
198    pub year: Option<u16>,
199}
200
201impl FromStr for BirthDate {
202    type Err = String;
203
204    fn from_str(s: &str) -> Result<Self, Self::Err> {
205        let parts: Vec<&str> = s.split('-').collect();
206
207        match parts.len() {
208            3 => {
209                let year = parts[0].parse::<u16>().ok();
210                let month = parts[1]
211                    .parse::<u8>()
212                    .ok()
213                    .and_then(|m| Month::try_from(m).ok()); // assuming Month has try_from
214                let day = parts[2].parse::<u8>().ok();
215
216                Ok(BirthDate { day, month, year })
217            }
218            _ => Err(format!("Invalid date format: {}", s)),
219        }
220    }
221}
222
223impl BirthDate {
224    /// Get as a proper date if all fields are present
225    pub fn as_date(&self) -> Option<time::Date> {
226        if let (Some(year), Some(month), Some(day)) = (self.year, self.month, self.day) {
227            let month = Month::try_from(month).ok()?;
228            time::Date::from_calendar_date(year as i32, month, day).ok()
229        } else {
230            None
231        }
232    }
233}
234
235/// Generic paging structure used throughout LinkedIn API
236#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
237pub struct Paging {
238    pub count: u32,
239    pub links: Vec<Value>,
240    pub start: u32,
241    pub total: u32,
242}
243
244/// Certification view
245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
246#[serde(rename_all = "camelCase")]
247pub struct CertificationView {
248    pub elements: Vec<Certification>,
249    pub entity_urn: Option<String>,
250    pub paging: Paging,
251    pub profile_id: String,
252}
253
254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256pub struct Certification {
257    pub entity_urn: Option<String>,
258    pub name: String,
259    pub company: Option<MiniCompany>,
260    pub authority: Option<String>,
261    pub license_number: Option<String>,
262    pub time_period: Option<TimePeriod>,
263    pub url: Option<Url>,
264}
265
266/// Course view
267#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
268#[serde(rename_all = "camelCase")]
269pub struct CourseView {
270    pub elements: Vec<Course>,
271    pub entity_urn: Option<String>,
272    pub paging: Paging,
273    pub profile_id: String,
274}
275
276#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
277pub struct Course {
278    pub entity_urn: Option<String>,
279    pub name: String,
280    pub number: Option<String>,
281}
282
283/// Honor/Awards view
284#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
285#[serde(rename_all = "camelCase")]
286pub struct HonorView {
287    pub elements: Vec<Honor>,
288    pub entity_urn: Option<String>,
289    pub paging: Paging,
290    pub profile_id: String,
291}
292
293#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
294#[serde(rename_all = "camelCase")]
295pub struct Honor {
296    pub entity_urn: Option<String>,
297    pub title: String,
298    pub issuer: Option<String>,
299    pub issue_date: Option<YearMonth>,
300    pub description: Option<String>,
301    pub occupation: Option<String>,
302}
303
304/// Language view
305#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
306#[serde(rename_all = "camelCase")]
307pub struct LanguageView {
308    pub elements: Vec<Language>,
309    pub entity_urn: Option<String>,
310    pub paging: Paging,
311    pub profile_id: String,
312}
313
314#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
315pub struct Language {
316    pub entity_urn: Option<String>,
317    pub name: String,
318    pub proficiency: Option<LanguageProficiency>,
319}
320
321#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
322pub enum LanguageProficiency {
323    #[serde(rename = "NATIVE_OR_BILINGUAL")]
324    NativeOrBilingual,
325    #[serde(rename = "FULL_PROFESSIONAL")]
326    FullProfessional,
327    #[serde(rename = "PROFESSIONAL_WORKING")]
328    ProfessionalWorking,
329    #[serde(rename = "LIMITED_WORKING")]
330    LimitedWorking,
331    #[serde(rename = "ELEMENTARY")]
332    Elementary,
333}
334
335/// Enhanced Experience with all fields
336#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
337#[serde(rename_all = "camelCase")]
338pub struct Experience {
339    pub entity_urn: Option<String>,
340    pub title: Option<String>,
341    pub company_name: Option<String>,
342    pub company_urn: Option<String>,
343    pub company: Option<CompanyInfo>,
344    pub description: Option<String>,
345    pub time_period: Option<TimePeriod>,
346    pub geo_location_name: Option<String>,
347    pub geo_urn: Option<String>,
348    pub location_name: Option<String>,
349    pub region: Option<String>,
350}
351
352impl Experience {
353    /// Get company logo URL
354    pub fn get_company_logo_url(&self) -> Option<Url> {
355        self.company
356            .as_ref()
357            .and_then(|company| company.mini_company.as_ref())
358            .and_then(|mini| mini.logo.as_ref())
359            .and_then(|container| container.vector_image.as_ref())
360            .and_then(|vector_image| {
361                if let (Some(root_url), Some(artifact)) =
362                    (&vector_image.root_url, vector_image.artifacts.first())
363                {
364                    let full_url = format!(
365                        "{}{}",
366                        root_url,
367                        artifact
368                            .file_identifying_url_path_segment
369                            .as_deref()
370                            .unwrap_or("")
371                    );
372                    Url::parse(&full_url).ok()
373                } else {
374                    None
375                }
376            })
377    }
378
379    /// Check if this is current position (no end date)
380    pub fn is_current(&self) -> bool {
381        self.time_period
382            .as_ref()
383            .map(|tp| tp.end_date.is_none())
384            .unwrap_or(false)
385    }
386}
387
388#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
389#[serde(rename_all = "camelCase")]
390pub struct CompanyInfo {
391    pub employee_count_range: Option<EmployeeCountRange>,
392    pub industries: Vec<String>,
393    pub mini_company: Option<MiniCompany>,
394}
395
396#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
397pub struct EmployeeCountRange {
398    pub start: u32,
399    pub end: u32,
400}
401
402#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
403#[serde(rename_all = "camelCase")]
404pub struct MiniCompany {
405    pub active: bool,
406    pub dash_company_urn: Option<String>,
407    pub entity_urn: Option<String>,
408    pub logo: Option<VectorImageContainer>,
409    pub name: String,
410    pub object_urn: String,
411    pub showcase: bool,
412    pub tracking_id: String,
413    pub universal_name: Option<String>,
414}
415
416/// Enhanced Education with all fields
417#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
418#[serde(rename_all = "camelCase")]
419pub struct Education {
420    pub entity_urn: Option<String>,
421    pub school_name: Option<String>,
422    pub school_urn: Option<String>,
423    pub school: Option<SchoolInfo>,
424    pub degree_name: Option<String>,
425    pub degree_urn: Option<String>,
426    pub field_of_study: Option<String>,
427    pub field_of_study_urn: Option<String>,
428    pub activities: Option<String>,
429    pub description: Option<String>,
430    pub grade: Option<String>,
431    pub time_period: Option<TimePeriod>,
432    pub honors: Option<Vec<String>>,
433    pub test_scores: Option<Vec<String>>,
434}
435
436impl Education {
437    /// Get school logo URL
438    pub fn get_school_logo_url(&self) -> Option<Url> {
439        self.school
440            .as_ref()
441            .and_then(|school| school.logo.as_ref())
442            .and_then(|container| container.vector_image.as_ref())
443            .and_then(|vector_image| {
444                if let (Some(root_url), Some(artifact)) =
445                    (&vector_image.root_url, vector_image.artifacts.first())
446                {
447                    let full_url = format!(
448                        "{}{}",
449                        root_url,
450                        artifact
451                            .file_identifying_url_path_segment
452                            .as_deref()
453                            .unwrap_or("")
454                    );
455                    Url::parse(&full_url).ok()
456                } else {
457                    None
458                }
459            })
460    }
461
462    /// Parse activities into a list
463    pub fn get_activities_list(&self) -> Vec<String> {
464        self.activities
465            .as_ref()
466            .map(|activities| {
467                activities
468                    .split('\n')
469                    .filter_map(|activity| {
470                        let trimmed = activity.trim().trim_start_matches("- ");
471                        if trimmed.is_empty() {
472                            None
473                        } else {
474                            Some(trimmed.to_string())
475                        }
476                    })
477                    .collect()
478            })
479            .unwrap_or_default()
480    }
481}
482
483#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
484#[serde(rename_all = "camelCase")]
485pub struct SchoolInfo {
486    pub active: bool,
487    pub entity_urn: Option<String>,
488    pub logo: Option<VectorImageContainer>,
489    pub object_urn: String,
490    pub school_name: String,
491    pub tracking_id: String,
492}
493
494/// Test Score view
495#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
496#[serde(rename_all = "camelCase")]
497pub struct TestScoreView {
498    pub elements: Vec<TestScore>,
499    pub entity_urn: Option<String>,
500    pub paging: Paging,
501    pub profile_id: String,
502}
503
504#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
505#[serde(rename_all = "camelCase")]
506pub struct TestScore {
507    pub entity_urn: Option<String>,
508    pub name: String,
509    pub score: String,
510    pub date: Option<YearMonth>,
511    pub description: Option<String>,
512    pub occupation: Option<String>,
513}
514
515/// Enhanced Contact Info with strong typing
516#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
517pub struct ContactInfo {
518    pub email_address: Option<EmailAddress>,
519    pub websites: Vec<Website>,
520    pub twitter: Vec<String>,
521    pub phone_numbers: Vec<PhoneNumber>,
522    pub birthdate: Option<BirthDate>,
523    pub ims: Option<Vec<Value>>,
524}
525
526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
527pub struct Website {
528    pub url: Option<Url>,
529    pub label: Option<String>,
530}
531
532/// Position Group View
533#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
534#[serde(rename_all = "camelCase")]
535pub struct PositionGroupView {
536    pub elements: Vec<PositionGroup>,
537    pub entity_urn: Option<String>,
538    pub paging: Paging,
539    pub profile_id: String,
540}
541
542#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
543#[serde(rename_all = "camelCase")]
544pub struct PositionGroup {
545    pub entity_urn: Option<String>,
546    pub name: String,
547    pub mini_company: Option<MiniCompany>,
548    pub paging: Paging,
549    pub positions: Vec<Experience>,
550    pub time_period: Option<TimePeriod>,
551    pub region: Option<String>,
552}
553
554/// Position View (individual positions)
555#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
556#[serde(rename_all = "camelCase")]
557pub struct PositionView {
558    pub elements: Vec<Experience>,
559    pub entity_urn: Option<String>,
560    pub paging: Paging,
561    pub profile_id: String,
562}
563
564/// Enhanced Education View
565#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
566#[serde(rename_all = "camelCase")]
567pub struct EducationView {
568    pub elements: Vec<Education>,
569    pub entity_urn: Option<String>,
570    pub paging: Paging,
571    pub profile_id: String,
572}
573
574/// Skill View
575#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
576#[serde(rename_all = "camelCase")]
577pub struct SkillView {
578    pub elements: Vec<Skill>,
579    pub entity_urn: Option<String>,
580    pub paging: Paging,
581    pub profile_id: String,
582}
583
584#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
585pub struct Skill {
586    pub entity_urn: Option<String>,
587    pub name: String,
588}
589
590/// Volunteer Experience View
591#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
592#[serde(rename_all = "camelCase")]
593pub struct VolunteerExperienceView {
594    pub elements: Vec<VolunteerExperience>,
595    pub entity_urn: Option<String>,
596    pub paging: Paging,
597    pub profile_id: String,
598}
599
600#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
601#[serde(rename_all = "camelCase")]
602pub struct VolunteerExperience {
603    pub entity_urn: Option<String>,
604    pub role: String,
605    pub company_name: Option<String>,
606    pub company_urn: Option<String>,
607    pub company: Option<CompanyInfo>,
608    pub cause: Option<String>,
609    pub description: Option<String>,
610    pub time_period: Option<TimePeriod>,
611    pub region: Option<String>,
612}
613
614/// Volunteer Cause View
615#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
616#[serde(rename_all = "camelCase")]
617pub struct VolunteerCauseView {
618    pub elements: Vec<VolunteerCause>,
619    pub entity_urn: Option<String>,
620    pub paging: Paging,
621    pub profile_id: String,
622}
623
624#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
625#[serde(rename_all = "camelCase")]
626pub struct VolunteerCause {
627    pub cause_name: String,
628    pub cause_type: String,
629}
630
631/// Generic view for empty sections
632#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
633#[serde(rename_all = "camelCase")]
634pub struct OrganizationView {
635    pub elements: Vec<Value>,
636    pub entity_urn: Option<String>,
637    pub paging: Paging,
638    pub profile_id: String,
639}
640
641#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
642#[serde(rename_all = "camelCase")]
643pub struct PatentView {
644    pub elements: Vec<Value>,
645    pub entity_urn: Option<String>,
646    pub paging: Paging,
647    pub profile_id: String,
648}
649
650/// Project View (projects user has worked on)
651#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
652#[serde(rename_all = "camelCase")]
653pub struct ProjectView {
654    pub elements: Vec<Project>,
655    pub entity_urn: Option<String>,
656    pub paging: Paging,
657    pub profile_id: String,
658}
659
660#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
661#[serde(rename_all = "camelCase")]
662pub struct Project {
663    pub entity_urn: Option<String>,
664    pub title: Option<String>,
665    pub description: Option<String>,
666    pub members: Vec<ProjectMember>,
667    pub time_period: Option<TimePeriod>,
668}
669
670#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
671#[serde(rename_all = "camelCase")]
672pub struct ProjectMember {
673    pub entity_urn: Option<String>,
674    pub profile_urn: Option<String>,
675    pub member: Option<MiniProfile>,
676}
677
678#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
679#[serde(rename_all = "camelCase")]
680pub struct PublicationView {
681    pub elements: Vec<Value>,
682    pub entity_urn: Option<String>,
683    pub paging: Paging,
684    pub profile_id: String,
685}
686
687#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
688#[serde(rename_all = "camelCase")]
689pub struct Location {
690    pub basic_location: Option<BasicLocation>,
691}
692
693#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
694#[serde(rename_all = "camelCase")]
695pub struct BasicLocation {
696    pub country_code: Option<String>,
697    pub postal_code: Option<String>,
698}
699
700#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
701#[serde(rename_all = "camelCase")]
702pub struct MiniProfile {
703    pub dash_entity_urn: Option<String>,
704    pub entity_urn: Option<String>,
705    pub object_urn: Option<String>,
706    pub public_identifier: Option<String>,
707    pub first_name: Option<String>,
708    pub last_name: Option<String>,
709    pub occupation: Option<String>,
710    pub tracking_id: Option<String>,
711    pub picture: Option<VectorImageContainer>,
712}
713
714#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
715#[serde(rename_all = "camelCase")]
716pub struct ProfilePicture {
717    pub display_image: Option<String>,
718    pub original_image: Option<String>,
719    pub photo_filter_edit_info: Option<PhotoFilterEditInfo>,
720}
721
722#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
723#[serde(rename_all = "camelCase")]
724pub struct PhotoFilterEditInfo {
725    pub top_left: Option<Point>,
726    pub top_right: Option<Point>,
727    pub bottom_left: Option<Point>,
728    pub bottom_right: Option<Point>,
729    pub brightness: Option<f32>,
730    pub contrast: Option<f32>,
731    pub saturation: Option<f32>,
732    pub vignette: Option<f32>,
733    pub photo_filter_type: Option<String>,
734}
735
736#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
737#[serde(rename_all = "camelCase")]
738pub struct Point {
739    pub x: f32,
740    pub y: f32,
741}
742
743#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
744#[serde(rename_all = "camelCase")]
745pub struct VectorImageContainer {
746    pub vector_image: Option<VectorImage>,
747}
748
749#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
750#[serde(rename_all = "camelCase")]
751pub struct VectorImage {
752    pub root_url: Option<String>,
753    pub artifacts: Vec<ImageArtifact>,
754}
755
756#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
757#[serde(rename_all = "camelCase")]
758pub struct ImageArtifact {
759    pub height: u32,
760    pub width: u32,
761    pub expires_at: Option<u64>,
762    pub file_identifying_url_path_segment: Option<String>,
763}
764
765#[derive(Debug, PartialEq, Serialize, Clone, Deserialize)]
766pub struct TimePeriod {
767    pub start_date: Option<YearMonth>,
768    pub end_date: Option<YearMonth>,
769}
770
771#[derive(Debug, PartialEq, Clone)]
772pub struct YearMonth {
773    pub year: i32,
774    pub month: Month,
775}
776
777impl Serialize for YearMonth {
778    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
779    where
780        S: Serializer,
781    {
782        use serde::ser::SerializeStruct;
783
784        let mut s = serializer.serialize_struct("YearMonth", 2)?;
785        s.serialize_field("year", &self.year)?;
786        s.serialize_field("month", &(self.month as u8))?;
787        s.end()
788    }
789}
790
791impl<'de> Deserialize<'de> for YearMonth {
792    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
793    where
794        D: Deserializer<'de>,
795    {
796        #[derive(Deserialize)]
797        struct Raw {
798            year: i32,
799            month: u8,
800        }
801
802        let raw = Raw::deserialize(deserializer)?;
803        let month = Month::try_from(raw.month)
804            .map_err(|_| serde::de::Error::custom("invalid month value"))?;
805
806        Ok(YearMonth {
807            year: raw.year,
808            month,
809        })
810    }
811}
812
813#[derive(Debug, Clone, Serialize, Deserialize)]
814pub struct Connection {
815    pub urn_id: String,
816    pub public_id: String,
817    pub distance: String,
818}
819#[derive(Debug, Clone, Serialize, Deserialize)]
820pub struct MemberBadges {
821    pub premium: bool,
822    pub open_link: bool,
823    pub influencer: bool,
824    pub job_seeker: bool,
825}
826#[derive(Debug, Clone, Serialize, Deserialize)]
827pub struct PersonSearchResult {
828    pub urn_id: String,
829    pub public_id: String,
830    pub distance: String,
831}
832
833#[derive(Debug, Clone, Serialize, Deserialize)]
834pub struct Invitation {
835    pub entity_urn: Option<String>,
836    pub shared_secret: String,
837}
838
839pub struct UniformResourceName {
840    pub namespace: String, // the context of the id
841    pub id: String,
842}
843
844#[derive(Debug, Clone, Serialize, Deserialize)]
845pub struct NetworkInfo {
846    pub followers_count: u64,
847}
848
849#[derive(Debug, Clone, Serialize, Deserialize)]
850pub struct School {
851    pub name: String,
852}
853
854#[derive(Debug, Clone, Serialize, Deserialize)]
855pub struct Company {
856    pub name: String,
857}
858
859#[derive(Debug, Clone, Serialize, Deserialize)]
860pub struct Conversation {
861    pub id: String,
862}
863
864#[derive(Debug, Clone, Serialize, Deserialize)]
865pub struct ConversationDetails {
866    pub id: String,
867}
868
869/// Parameters for people search.
870#[derive(Debug, Clone, Default)]
871pub struct SearchPeopleParams {
872    pub keywords: Option<String>,
873    pub connection_of: Option<String>,
874    pub network_depth: Option<String>,
875    pub current_company: Option<Vec<String>>,
876    pub past_companies: Option<Vec<String>>,
877    pub nonprofit_interests: Option<Vec<String>>,
878    pub profile_languages: Option<Vec<String>>,
879    pub regions: Option<Vec<String>>,
880    pub industries: Option<Vec<String>>,
881    pub schools: Option<Vec<String>>,
882    pub include_private_profiles: bool,
883    pub limit: Option<usize>,
884}