1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use serde_json::Value;
3use time::Month;
4use url::Url;
5
6pub struct Identity {
7 pub authentication_token: String,
8 pub session_cookie: String,
9}
10
11#[derive(Debug, Clone, Default)]
13pub struct SearchPeopleParams {
14 pub keywords: Option<String>,
15 pub connection_of: Option<String>,
16 pub network_depth: Option<String>,
17 pub current_company: Option<Vec<String>>,
18 pub past_companies: Option<Vec<String>>,
19 pub nonprofit_interests: Option<Vec<String>>,
20 pub profile_languages: Option<Vec<String>>,
21 pub regions: Option<Vec<String>>,
22 pub industries: Option<Vec<String>>,
23 pub schools: Option<Vec<String>>,
24 pub include_private_profiles: bool,
25 pub limit: Option<usize>,
26}
27
28#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub struct Profile {
32 #[serde(rename = "entityUrn")]
33 pub entity_urn: Option<String>,
34
35 pub first_name: Option<String>,
36 pub last_name: Option<String>,
37 pub headline: Option<String>,
38 pub summary: Option<String>,
39 pub industry_name: Option<String>,
40 #[serde(rename = "industryUrn")]
41 pub industry_urn: Option<String>,
42
43 pub geo_country_name: Option<String>,
44 #[serde(rename = "geoCountryUrn")]
45 pub geo_country_urn: Option<String>,
46 #[serde(rename = "geoLocationName")]
47 pub geo_location_name: Option<String>,
48 #[serde(rename = "geoLocationBackfilled")]
49 pub geo_location_backfilled: Option<bool>,
50
51 pub address: Option<String>,
52 pub birth_date: Option<BirthDate>,
53
54 pub default_locale: Option<Locale>,
55 pub supported_locales: Option<Vec<Locale>>,
56
57 pub location: Option<Location>,
58 #[serde(rename = "locationName")]
59 pub location_name: Option<String>,
60
61 #[serde(rename = "miniProfile")]
62 pub mini_profile: Option<MiniProfile>,
63
64 pub profile_picture: Option<ProfilePicture>,
65 #[serde(rename = "profilePictureOriginalImage")]
66 pub profile_picture_original_image: Option<VectorImageContainer>,
67
68 #[serde(rename = "showEducationOnProfileTopCard")]
69 pub show_education_on_profile_top_card: Option<bool>,
70 pub student: Option<bool>,
71
72 #[serde(rename = "versionTag")]
73 pub version_tag: Option<String>,
74
75 #[serde(skip)]
76 pub profile_id: String, #[serde(skip)]
79 pub experience: Vec<Experience>,
80
81 #[serde(skip)]
82 pub education: Vec<Education>,
83
84 #[serde(skip)]
85 pub skills: Vec<Skill>,
86
87 #[serde(skip)]
88 pub contact: ContactInfo,
89}
90
91#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct BirthDate {
94 pub day: Option<u32>,
95 pub month: Option<u32>,
96 pub year: Option<u32>,
97}
98
99#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub struct Locale {
102 pub country: Option<String>,
103 pub language: Option<String>,
104}
105
106#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct Location {
109 pub basic_location: Option<BasicLocation>,
110}
111
112#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct BasicLocation {
115 pub country_code: Option<String>,
116 pub postal_code: Option<String>,
117}
118
119#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
120#[serde(rename_all = "camelCase")]
121pub struct MiniProfile {
122 #[serde(rename = "dashEntityUrn")]
123 pub dash_entity_urn: Option<String>,
124 #[serde(rename = "entityUrn")]
125 pub entity_urn: Option<String>,
126 #[serde(rename = "objectUrn")]
127 pub object_urn: Option<String>,
128 pub public_identifier: Option<String>,
129 pub first_name: Option<String>,
130 pub last_name: Option<String>,
131 pub occupation: Option<String>,
132 pub tracking_id: Option<String>,
133 pub picture: Option<VectorImageContainer>,
134}
135
136#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct ProfilePicture {
139 pub display_image: Option<String>,
140 pub original_image: Option<String>,
141 pub photo_filter_edit_info: Option<PhotoFilterEditInfo>,
142}
143
144#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct PhotoFilterEditInfo {
147 pub top_left: Option<Point>,
148 pub top_right: Option<Point>,
149 pub bottom_left: Option<Point>,
150 pub bottom_right: Option<Point>,
151 pub brightness: Option<f32>,
152 pub contrast: Option<f32>,
153 pub saturation: Option<f32>,
154 pub vignette: Option<f32>,
155 pub photo_filter_type: Option<String>,
156}
157
158#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
159#[serde(rename_all = "camelCase")]
160pub struct Point {
161 pub x: f32,
162 pub y: f32,
163}
164
165#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
166#[serde(rename_all = "camelCase")]
167pub struct VectorImageContainer {
168 #[serde(rename = "com.linkedin.common.VectorImage")]
169 pub vector_image: Option<VectorImage>,
170}
171
172#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct VectorImage {
175 pub root_url: Option<String>,
176 pub artifacts: Vec<ImageArtifact>,
177}
178
179#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
180#[serde(rename_all = "camelCase")]
181pub struct ImageArtifact {
182 pub height: u32,
183 pub width: u32,
184 pub expires_at: Option<u64>,
185 pub file_identifying_url_path_segment: Option<String>,
186}
187
188#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct Experience {
192 pub title: Option<String>,
193 #[serde(rename = "companyName")]
194 pub company_name: Option<String>,
195 #[serde(rename = "companyLogoUrl")]
196 pub company_logo_url: Option<String>,
197 pub role: Option<String>,
198 #[serde(rename = "timePeriod")]
199 pub time_period: Option<TimePeriod>,
200 pub description: Option<String>,
201}
202
203#[derive(Debug, PartialEq, Serialize, Clone, Deserialize)]
204pub struct TimePeriod {
205 #[serde(rename = "startDate")]
206 pub start_date: YearMonth,
207 #[serde(rename = "endDate")]
208 pub end_date: YearMonth,
209}
210
211#[derive(Debug, PartialEq, Clone)]
212pub struct YearMonth {
213 pub year: i32,
214 pub month: Month,
215}
216
217impl Serialize for YearMonth {
218 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219 where
220 S: Serializer,
221 {
222 use serde::ser::SerializeStruct;
223
224 let mut s = serializer.serialize_struct("YearMonth", 2)?;
225 s.serialize_field("year", &self.year)?;
226 s.serialize_field("month", &(self.month as u8))?;
227 s.end()
228 }
229}
230
231impl<'de> Deserialize<'de> for YearMonth {
232 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
233 where
234 D: Deserializer<'de>,
235 {
236 #[derive(Deserialize)]
237 struct Raw {
238 year: i32,
239 month: u8,
240 }
241
242 let raw = Raw::deserialize(deserializer)?;
243 let month = Month::try_from(raw.month)
244 .map_err(|_| serde::de::Error::custom("invalid month value"))?;
245
246 Ok(YearMonth {
247 year: raw.year,
248 month,
249 })
250 }
251}
252
253#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256pub struct Education {
257 pub school_name: Option<String>,
258 pub degree: Option<String>,
259 pub field_of_study: Option<String>,
260}
261
262#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
264#[serde(rename_all = "camelCase")]
265pub struct Skill {
266 pub name: String,
267}
268
269#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
270pub struct ContactInfo {
271 #[serde(rename = "emailAddress")]
272 pub email_address: Option<String>,
273 pub websites: Vec<Website>,
274 pub twitter: Vec<String>,
275 #[serde(rename = "phoneNumbers")]
276 pub phone_numbers: Vec<String>,
277 pub birthdate: Option<String>,
278 pub ims: Option<Vec<Value>>,
279}
280
281#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
282pub struct Website {
283 pub url: String,
284 pub label: Option<String>,
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct Connection {
289 pub urn_id: String,
290 pub public_id: String,
291 pub distance: String,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct Conversation {
296 pub id: String,
297}
298
299#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct ConversationDetails {
301 pub id: String,
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize)]
305pub struct MemberBadges {
306 pub premium: bool,
307 pub open_link: bool,
308 pub influencer: bool,
309 pub job_seeker: bool,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct NetworkInfo {
314 pub followers_count: u64,
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct School {
319 pub name: String,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
323pub struct Company {
324 pub name: String,
325}
326
327#[derive(Debug, Clone, Serialize, Deserialize)]
328pub struct PersonSearchResult {
329 pub urn_id: String,
330 pub public_id: String,
331 pub distance: String,
332}
333
334#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct Invitation {
336 #[serde(rename = "entityUrn")]
337 pub entity_urn: String,
338 #[serde(rename = "sharedSecret")]
339 pub shared_secret: String,
340}
341
342pub struct UniformResourceName {
343 pub namespace: String, pub id: String,
345}
346impl Profile {
347 pub fn get_full_name(&self) -> Option<String> {
349 match (&self.first_name, &self.last_name) {
350 (Some(first), Some(last)) => Some(format!("{} {}", first, last)),
351 (Some(first), None) => Some(first.clone()),
352 (None, Some(last)) => Some(last.clone()),
353 (None, None) => None,
354 }
355 }
356
357 pub fn get_profile_image(&self) -> Option<Url> {
359 self.profile_picture_original_image
360 .as_ref()
361 .and_then(|container| container.vector_image.as_ref())
362 .and_then(|vector_image| {
363 if let (Some(root_url), Some(artifact)) =
364 (&vector_image.root_url, vector_image.artifacts.first())
365 {
366 let full_url = format!(
367 "{}{}",
368 root_url,
369 artifact
370 .file_identifying_url_path_segment
371 .as_deref()
372 .unwrap_or("")
373 );
374 Url::parse(&full_url).ok()
375 } else {
376 None
377 }
378 })
379 }
380}